覆盖元素对象

时间:2016-02-25 09:57:39

标签: java xml jaxb

我正在尝试创建一个对象模型,以便能够使用JAXB输出以下XML:

<root version="1">
    <first version="1"/>
</root>

或者这个:

<root version="1">
    <second version="1"/>
</root>

显然是这个例子的过度简化版本。只能存在firstsecond类型的子元素,而不能同时存在。

我的根元素如下所示:

@XmlRootElement(name = "root")
public class ExampleRootElement {
    private int version;
    private ExampleBaseSubElement subElement;

    @XmlAttribute(name = "version")
    public int getVersion() {
        return version;
    }

    public void setVersion(int version) {
        this.version = version;
    }

    public ExampleBaseSubElement getSubElement() {
        return subElement;
    }

    public void setSubElement(ExampleBaseSubElement subElement) {
        this.subElement = subElement;
    }
}

由于子元素必须是firstsecond,我创建了一个空的抽象虚拟类ExampleBaseSubElement,以便从first和{{的特定类中扩展1}}。我会在这里使用一个接口,但显然JAXB无法处理这些。 (我通常在C#中使用这种东西,所以请原谅,如果这是使用JAXB在Java中执行它的一种非常糟糕的方法)

虚拟课程:

second

public abstract class ExampleBaseSubElement { } 的代码:

first

@XmlRootElement(name="first") public class ExampleFirstSubElement extends ExampleBaseSubElement { private int version; @XmlAttribute(name="version") public int getVersion() { return version; } public void setVersion(int version) { this.version = version; } } 的代码:(仅为了这个示例与second几乎相同)

first

我可能错误的是期望使用@XmlRootElement(name = "second") public class ExampleSecondSubElement extends ExampleBaseSubElement { private int version; @XmlAttribute(name = "version") public int getVersion() { return version; } public void setVersion(int version) { this.version = version; } } 注释从类中设置元素名称,因为它不起作用。我试图通过使用嵌套XmlRootElement创建ExampleRootElement来创建所需的XML输出:

ExampleFirstSubElement

这导致:

ExampleRootElement exampleRootElement = new ExampleRootElement();
exampleRootElement.setVersion(1);
ExampleFirstSubElement exampleFirstSubElement = new ExampleFirstSubElement();
exampleFirstSubElement.setVersion(1);
exampleRootElement.setSubElement(exampleFirstSubElement);

JAXBContext jaxbContext = JAXBContext.newInstance(ExampleRootElement.class);
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);

marshaller.marshal(exampleRootElement, System.out);

期望是:

<root version="1">
    <subElement/>
</root>

好的,我知道这不起作用。简单地忽略了注释。可能是因为JAXB没有解析扩展类型,这可以解释为什么嵌套元素的属性<root version="1"> <first version="1"/> </root> 也会丢失。而且我非常乐观地认为,解组这个问题会更加困难......

所以我的问题是:我在这里错过了某种神奇的注释,所以这可以按预期工作,或者这完全是错误的方法,如果是这样,最佳做法是什么?

1 个答案:

答案 0 :(得分:0)

好的,在修补了不同的注释(基本上是强制性的)后,我提出了以下解决方案:

XmlSeeAlso添加到抽象基类ExampleBaseSubElement

@XmlSeeAlso({
        ExampleFirstSubElement.class,
        ExampleSecondSubElement.class
})
public abstract class ExampleBaseSubElement {
}

XmlElementRef内向subElement的getter添加ExampleRootElement

@XmlRootElement(name = "root")
public class ExampleRootElement {
    private int version;
    private ExampleBaseSubElement subElement;

    @XmlAttribute(name = "version")
    public int getVersion() {
        return version;
    }

    public void setVersion(int version) {
        this.version = version;
    }

    @XmlElementRef // here!
    public ExampleBaseSubElement getSubElement() {
        return subElement;
    }

    public void setSubElement(ExampleBaseSubElement subElement) {
        this.subElement = subElement;
    }
}

现在产生预期的输出:

<root version="1">
    <first version="1"/>
</root>

我仍然不确定这一般是坏还是实际上应该怎么做。它有效,我希望这有助于其他人面临同样的问题。