使用@XmlAnyElement批注解组XML时出现空指针异常

时间:2016-07-21 16:25:54

标签: java xml jaxb

我目前正在尝试使用JAXB将一些XML解组为java对象,并且我得到一个奇怪的Null指针异常。解组时这只是一个问题。我可以和这些课程一起训练。以下是相关的代码片段(不相关的部分用“......”表示):

  1. JAXB Root元素:

    ...
    @XmlRootElement(name="assets")
    public class Assets {
        String product;
        Images images = new Images();
    
        ...
    
        Public Assets() {}
    
        ...
    
        public String getProduct() { return this.product; }
    
        @XmlAttribute(name="product")
        public void setProduct(String newProduct) { this.product = newProduct; }
    
        public Images getImages() { return this.images; }
    
        @XmlElement(name="images")
        public void setImages(Images newImages) { this.images = newImages; }
    
        ...
    }
    
  2. 根元素的Images子元素:

    ...
    @XmlRootElement(name="images")
    @XmlSeeAlso(Image.class)
    @XmlType(propOrder = {"mainAsset", "image"})
    public class Images {
        List<Image> images;
        Image mainAsset;
    
        private static char counter = 'a';
        private static final String prefix = "product-image-";
    
        // Here's the part that causes the NPE
        @XmlAnyElement(lax=true)
        public List<JAXBElement<Image>> getImage() {
            final List<JAXBElement<Image>> imageList = new ArrayList<JAXBElement<Image>>();
            for (final Image g : this.images) {
                imageList.add(new JAXBElement(new QName(prefix + counter++), Image.class, g));
            }
            counter = 'a';
            return imageList;
        }
    
        @XmlElement(name="renditions")
        public void setImage(List<Image> newImages) { this.images = newImages; }
    
        public Image getMainAsset() { return this.mainAsset; }
    
        @XmlElement(name="main-asset-name")
        public void setMainAsset(Image newMainAsset) { this.mainAsset = newMainAsset; }
    }
    
  3. 解组XML的逻辑:

    ...
    public void modifyXML() {
    try {
        JAXBContext context = JAXBContext.newInstance(Assets.class, Images.class, Image.class);
        Unmarshaller um = context.createUnmarshaller();
        File f = new File("/path/to/my.xml");
        Assets assets = (Assets) um.unmarshal(f);
        ...
    } catch (JAXBException e) {
        e.printStackTrace();
    }
    }
    ...
    
  4. 最后,我试图解组的XML(可能有助于知道这个xml文件实际上是使用JAXB marshaller生成的,它运行没有任何问题):

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <assets product="TEST PRODUCT">
        <images>
            <main-asset-name>
                <path>stuff.jpg</path>
                <title>theTitle</path>
                <alt>theAlt</path>
                <description>theDescription</description>
            </main-asset-name>
            <product-image-a>
                <path>48x48.jpg</path>
                <title>theTitle</path>
                <alt>theAlt</path>
                <description>theDescription</description>
            </product-image-a>
            <product-image-b>
                <path>140x140.jpg</path>
                <title>theTitle</path>
                <alt>theAlt</path>
                <description>theDescription</description>
            </product-image-b>
            <product-image-c>
                <path>1280x1280.jpg</path>
                <title>theTitle</path>
                <alt>theAlt</path>
                <description>theDescription</description>
            </product-image-c>
            <product-image-d>
                <path>319x319.jpg</path>
                <title>theTitle</path>
                <alt>theAlt</path>
                <description>theDescription</description>
            </product-image-d>
        </images>
    </assets>
    
  5. 好的,这就是所有相关代码(我认为)。当我运行我的程序时,我在调用unmarshaller之后立即收到以下错误:

    java.lang.NullPointerException
        at com.my.companys.name.Images.getImage(Images.java:25)
    

    引用的行号是for循环在我的Images.java类文件中开始的行。

    有没有人知道为什么this.images可能在这里为空?任何帮助是极大的赞赏。提前谢谢。

1 个答案:

答案 0 :(得分:0)

这是我一直在使用的解决方案。这是一个黑客攻击,但地狱......它完成了这项工作。

首先,我将原始xml作为字符串而不是将其作为文件读取:

public void modifyXML() {
    try {
        JAXBContext context = JAXBContext.newInstance(Assets.class, Image.class);
        Unmarshaller um = context.createUnmarshaller();
        // This xml should be formatted in a way that JAXB can work with
        String rawXML = getRawXML("/path/to/my.xml");
        // Hand the modified xml to the unmarshaller
        Assets umAssets = (Assets) um.unmarshal(new StreamSource(new StringReader(rawXML)));
        // Do stuff with umAssets
        ...
    } catch (Exception e) {
        e.printStackTrace();
    }
}

private String getRawXML(String path) throws IOException {
    String xml = readFile(path, StandardCharsets.UTF_8);
    // This should make it so JAXB can handle the xml properly
    xml = xml.replaceAll("<main-asset-name>", "<image>");
    xml = xml.replaceAll("</main-asset-name>", "</image>");
    xml = xml.replaceAll("<product-image.*>", "<image>");
    return xml.replaceAll("</product-image.*>", "</image>");
}

private String readFile(String path, Charset encoding) throws IOException {
    // A simple file reader
    byte[] encoded = Files.readAllBytes(Paths.get(path));
    return new String(encoded, encoding);
}

这似乎可以解决问题,所以我现在要使用它。当然,如果有人有解决方案,我仍然愿意接受更好的解决方案。