未调用 JAXB ValidationEventHandler 的 handleEvent 方法

JAXB ValidationEventHandler's handleEvent method not being called

我正在尝试使用 XML 规则中不允许的字符来捕获 ValidationEvent。 (例如,“&”) 此外,我设置 ValidationEventHandler 来检查解组错误。 我尝试使用 InputStream 解组,但事件处理程序没有捕获错误。 handleEvent 方法根本没有执行。另一方面,使用 StringReader 将正常工作。

我已经阅读了描述 unmarshal 方法的 Javadoc。但是,我没有看到它无法捕获ValidationEvent。

Unmarshal XML data from the specified InputStream and return the resulting content tree. Validation event location information may be incomplete when using this form of the unmarshal API.

在最后一次尝试中,我确实尝试过在线搜索,但我找不到任何东西。
任何帮助将不胜感激:D

附加问题:

很抱歉添加一个问题。 (POJO class 有点变了...) 我定义了 POJO class 字段 @XmlPath Annotation 与 XML 元素名称 不同,但它似乎不起作用。我应该将它用作 XmlElement 吗?


POJO class:

import org.eclipse.persistence.oxm.annotations.XmlPath;

import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import java.util.List;

@XmlRootElement
class Article {
    private String title;
    private String category;
    private List<ArticleImage> imageList;

    public String getTitle() {
        return title;
    }

    @XmlElement
    public void setTitle(String title) {
        this.title = title;
    }

    public String getCategory() {
        return category;
    }

    @XmlElement
    public void setCategory(String category) {
        this.category = category;
    }

    public List<ArticleImage> getImageList() {
        return imageList;
    }

    // for Extra Question... :D
    @XmlPath("image")
    public void setImageList(List<ArticleImage> imageList) {
        this.imageList = imageList;
    }
}

class ArticleImage {
    private String url;
    private String ext;

    public String getUrl() {
        return url;
    }

    @XmlAttribute
    public void setUrl(String url) {
        this.url = url;
    }

    public String getExt() {
        return ext;
    }

    @XmlAttribute
    public void setExt(String ext) {
        this.ext = ext;
    }
}


验证事件处理程序:

import javax.xml.bind.ValidationEvent;
import javax.xml.bind.ValidationEventHandler;
import javax.xml.bind.ValidationEventLocator;

class CustomValidationHandler implements ValidationEventHandler {

    // This method is not reached when debugging.
    @Override
    public boolean handleEvent(ValidationEvent event) {
        if (event.getSeverity() == ValidationEvent.FATAL_ERROR ||
                event.getSeverity() == ValidationEvent.ERROR) {
            ValidationEventLocator locator = event.getLocator();
            throw new RuntimeException("Error in EventHandler. line number: " + locator.getLineNumber());
        }
        return true;
    }
}


解组代码:

import org.eclipse.persistence.jaxb.JAXBContextFactory;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import java.io.ByteArrayInputStream;
import java.io.InputStream;

public class SomeTest {

    public void someMethod() {
        String xmlString = "<article type=\"item\">\n"
                + "    <title>M&A</title>\n"
                + "    <category>1234-1234</category>\n"
                + "    <image url=\"hello\" ext=\"jpg\"/>\n"
                + "</article>";

        try (InputStream fileInputStream = new ByteArrayInputStream(xmlString.getBytes())) {
            JAXBContext context = JAXBContextFactory.createContext(new Class[]{Article.class}, null);
            Unmarshaller unmarshaller = context.createUnmarshaller();
            unmarshaller.setEventHandler(new CustomValidationHandler());
            Article article = (Article) unmarshaller.unmarshal(fileInputStream);

            System.out.println(article.getTitle());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        new SomeTest().someMethod();
    }
}

它适用于两种情况:InputStreamStringReader

刚刚更改:

JAXBContext context = JAXBContext.newInstance(Article.class);

正如@mart 和@Sergey 所说

更新 JAXBContext context = JAXBContextFactory.createContext(new Class[]{Article.class}, null);

   JAXBContext context = JAXBContext.newInstance(Article.class);

还要添加 @XmlAccessorType(XmlAccessType.FIELD) 在你的文章 pojo class.

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Article {
    @XmlElement
    private String title;
    @XmlElement
    private String category;

//setter getters

}

我查过了,如果有异常,正在调用CustomValidationHandler

最初建议替换

JAXBContext context = JAXBContextFactory.createContext(new Class[]{Article.class}, null);

JAXBContext context = JAXBContext.newInstance(Article.class);

在 JAXBContextFactory.createContext 的实现中,您可以看到 classesToBeBound(在您的情况下您通过了 Article)执行一些检查,这些检查导致 "Unable to find a JAXB implementation to delegate" 异常。这是我在 运行 你的代码时遇到的问题,我认为你也有。然后你的事件处理程序被调用(至少在我的设置中)。

后来你遇到了问题“... Class 有两个同名的属性 "value" ...”,我建议检查这个 link 来解释原因它发生了。

link 是:

编辑以回复新问题:

如果你不介意我问你想用 @XmlPath("image") 做什么?

您的 POJO 结构与 xml 不匹配。去掉注解,修改image的setter方法,如下:

@XmlRootElement
class Article {
    private String title;
    private String category;
    private List<ArticleImage> imageList;

    public String getTitle() {
        return title;
    }

    @XmlElement
    public void setTitle(String title) {
        this.title = title;
    }

    public String getCategory() {
        return category;
    }

    @XmlElement
    public void setCategory(String category) {
        this.category = category;
    }

    public List<ArticleImage> getImage() {
        return imageList;
    }

    // for Extra Question... :D
    // method name changed!
    public void setImage(List<ArticleImage> imageList) {
        this.imageList = imageList;
    }
}

class ArticleImage {
    private String url;
    private String ext;

    public String getUrl() {
        return url;
    }

    @XmlAttribute
    public void setUrl(String url) {
        this.url = url;
    }

    public String getExt() {
        return ext;
    }

    @XmlAttribute
    public void setExt(String ext) {
        this.ext = ext;
    }
}