从2.2.7开始,使用JAXB-RI实现的解组失败

时间:2019-03-16 11:57:13

标签: jaxb

我们正在升级到JAXB-RI实现的新版本。但是,从com.sun.xml.bind:jaxb-impl:2.2.7开始,我们的解组代码失败。如果我们切换回2.2.6版,它将正确解组。

我尝试了对象类上注释的各种组合。问题似乎出在XmlBars.getBars方法周围,该方法不再返回子Bar元素。

我已经使用org.glassfish.jaxb:jaxb-runtime和最新的Moxy进行了尝试,它们表现出相同的行为。

此JUnit5测试中显示了失败的示例:

package com.company;

import org.junit.jupiter.api.Test;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import java.io.StringReader;
import java.util.List;

import static org.junit.jupiter.api.Assertions.assertEquals;

class XmlBarsTest {

    private static final String XML = "<Bars><Bar><Name>name1</Name></Bar><Bar><Name>name2</Name></Bar></Bars>";

    @Test
    public void deserializeXmlBars() throws JAXBException {
        StringReader reader = new StringReader(XML);
        JAXBContext context = JAXBContext.newInstance(XmlBars.class);
        Unmarshaller unmarshaller = context.createUnmarshaller();
        XmlBars deserializeBars = (XmlBars) unmarshaller.unmarshal(reader);
        List<XmlBar> bars = deserializeBars.getBars();

        assertEquals(2, bars.size(), "Missing bars");
    }
}

支持类是XmlBars:

package com.company;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;

import java.util.ArrayList;
import java.util.List;

import static java.util.stream.Collectors.toList;


@XmlRootElement(name = "Bars")
public class XmlBars {

    @XmlTransient
    private List<Bar> bars;

    public XmlBars() {
        bars = new ArrayList<>();
    }

    public XmlBars(List<Bar> bars) {
        this.bars = bars;
    }

    @XmlElement(name = "Bar")
    public List<XmlBar> getBars() {
        return bars == null ?
                null :
                bars.stream()
                        .map(XmlBar::new)
                        .collect(toList());
    }

    public void setBars(List<XmlBar> list) {
        this.bars = list.stream()
                .map(XmlBar::getBar)
                .collect(toList());
    }
}

XmlBar:

package com.company;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlTransient;

public class XmlBar {
    @XmlTransient
    private Bar bar;

    public XmlBar() {
        bar = new Bar();
    }

    public XmlBar(Bar bar) {
        this.bar = bar;
    }

    Bar getBar() {
        return bar;
    }

    @XmlElement(name = "Name")
    public String getName() {
        return bar.getName();
    }

    public void setName(String name) {
        bar.setName(name);
    }
}

和酒吧:

package com.company;

public class Bar {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

以及支持的pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.company</groupId>
    <artifactId>test</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.3.1</version>
        </dependency>
        <dependency>
            <groupId>com.sun.xml.bind</groupId>
            <artifactId>jaxb-impl</artifactId>
            <!-- Works with 2.2.6. Fails with 2.2.7 -->
            <version>2.2.7</version>
        </dependency>

        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>5.4.0</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>5.4.0</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.0</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <showDeprecation>true</showDeprecation>
                    <showWarnings>true</showWarnings>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>3.0.0-M3</version>
            </plugin>
        </plugins>
    </build>
</project>

更新

如果我将XmlBars修改为以下内容,它将起作用:

package com.company;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;

import java.util.ArrayList;
import java.util.List;

import static java.util.stream.Collectors.toList;


@XmlRootElement(name = "Bars")
public class XmlBars {

    @XmlTransient
    private List<Bar> bars;

    /* Adding this enables the annotations to work as before */
    private List<XmlBar> xmlBars;

    public XmlBars() {
        bars = new ArrayList<>();
        xmlBars = new ArrayList<>();
    }

    public XmlBars(List<Bar> bars) {
        this.bars = bars;
        this.xmlBars = bars.stream()
                .map(XmlBar::new)
                .collect(toList());
    }

    @XmlElement(name = "Bar")
    public List<XmlBar> getBars() {
        return xmlBars;
    }

    public void setBars(List<XmlBar> list) {
        this.bars = list.stream()
                .map(XmlBar::getBar)
                .collect(toList());
        this.xmlBars = list;
    }
}

所以,问题是,如何注释原始版本以防止需要维护本地属性?

1 个答案:

答案 0 :(得分:0)

我们找不到解决方案。因此,我们重新设计了类,使其具有带有常规getter和setter的属性。