JAXB 继承冲突 - 在子类上重新注释

SHi*_*KiT 4 java xml jaxb

我目前在我的项目中有这个环境:

public abstract class Foo {

   private List<Thing> things;

   public List<Thing> getThings() { return this.things; }
}

public abstract class Bar extends Foo {


   @XmlElements({@XmlElement(name = "first", type = First.class)})
   public List<Thing> getThings() { return super.getThings(); }

}

public class Bobar extends Bar {

   @XmlElements({@XmlElement(name = "second", type = Second.class)})
   public List<Thing> getThings() { return super.getThings(); }

}
Run Code Online (Sandbox Code Playgroud)

对于以下 XML 文档

<bobar>
   <first>blablabla</first>
   <second>blublublu</second>
</bobar>
Run Code Online (Sandbox Code Playgroud)

当我做

context = JAXBContext.newInstance("the.package.structure");
unmarshaller = context.createUnmarshaller();
Bar object = (Bar) unmarshaller.unmarshal("path-to-xml-document");
Run Code Online (Sandbox Code Playgroud)

Barobject在集合中只有一个元素,而不是 2 个。First元素完全丢失了,当我尝试这样做时object.getThings(),它的大小为 1,并且集合中唯一的对象是 的实例Second。有人可以帮助我如何实现在集合中获取两个对象吗?如果这是不可能的,我怎样才能实现类似的目标?

我这样做的原因是(在我的项目逻辑中)每个Bobar东西集合First在它的集合中都有一个,但不是每个Bar都有一个Second集合中,并且Foo是一个泛型类。

编辑:

当我更改 XML 文档中的顺序时,输出会有所不同。

<bobar>
   <second>blablabla</second>
   <first>blublublu</first>
</bobar>
Run Code Online (Sandbox Code Playgroud)

在这种情况下,我只得到First集合中的一个实例,并且Second丢失了。并且更多地改变场景,我得到了有趣的结果:

public abstract class Foo {

   private List<Thing> things;

   public List<Thing> getThings() { return this.things; }
}

public abstract class Bar extends Foo {


   @XmlElements({@XmlElement(name = "first", type = First.class), @XmlElement(name = "third, type = Third.class)})
   public List<Thing> getThings() { return super.getThings(); }

}

public class Bobar extends Bar {

   @XmlElements({@XmlElement(name = "second", type = Second.class)})
   public List<Thing> getThings() { return super.getThings(); }

}
Run Code Online (Sandbox Code Playgroud)

如果我做

<bobar>
   <third>bliblibli</third>
   <second>blablabla</second>
   <first>blublublu</first>
</bobar>
Run Code Online (Sandbox Code Playgroud)

理论上,我认为这不应该针对由此生成的 XML 模式进行验证,因为这里的顺序不正确。但除此之外,在这种情况下,我得到SecondFirstThird丢失。

bdo*_*han 5

不可能在超类型上注释属性,并让子尝试增量添加到该映射中。下面是一种您可以支持您所追求的所有用例的方法。需要注意的一件事是对象层次结构中的所有级别都将支持相同的元素集。您需要使用外部验证方法来限制所需的值。

如果Thing是一类不是一个接口,并FirstSecond延长Thing,那么你可能有兴趣在使用@XmlElementRef替代@XmlElements(见:http://blog.bdoughan.com/2010/11/jaxb-and-inheritance-using-substitution.html)。它将为您提供更大的灵活性,但需要进行一些验证(难以限制有效值集)。

酒吧

我们将注释Barwith@XmlTransient以便 JAXB 实现不处理它。

package forum11698160;

import java.util.List;

import javax.xml.bind.annotation.XmlTransient;

@XmlTransient
public abstract class Bar extends Foo {

    public List<Thing> getThings() {
        return super.getThings();
    }

}
Run Code Online (Sandbox Code Playgroud)

博巴

@XmlElementRef对应于 XML 模式中替换组的概念。匹配属性的值将基于@XmlRootElement声明。

package forum11698160;

import java.util.List;
import javax.xml.bind.annotation.*;

@XmlRootElement
public class Bobar extends Bar {

    @XmlElementRef
    public List<Thing> getThings() {
        return super.getThings();
    }

}
Run Code Online (Sandbox Code Playgroud)

事物

由于 JAXB 实现不能使用反射来查找一个类型的所有子类,我们可以使用@XmlSeeAlso注解来帮忙。如果您不使用此注释,则在引导JAXBContext.

package forum11698160;

import javax.xml.bind.annotation.XmlSeeAlso;

@XmlSeeAlso({First.class, Second.class})
public class Thing {

}
Run Code Online (Sandbox Code Playgroud)

第一的

我们需要标注First@XmlRootElement

package forum11698160;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class First extends Thing {

}
Run Code Online (Sandbox Code Playgroud)

第二

Second还需要注释@XmlRootElement

package forum11698160;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Second extends Thing {

}
Run Code Online (Sandbox Code Playgroud)

演示

package forum11698160;

import java.io.File;
import javax.xml.bind.*;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Bobar.class);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        File xml = new File("src/forum11698160/input.xml");
        Bobar bobar =  (Bobar) unmarshaller.unmarshal(xml);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(bobar, System.out);
    }

}
Run Code Online (Sandbox Code Playgroud)

输入.xml/输出

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<bobar>
    <first/>
    <second/>
</bobar>
Run Code Online (Sandbox Code Playgroud)

其它文件

以下是运行此示例所需的其他文件:

package forum11698160;

import java.util.*;

public abstract class Foo {

    private List<Thing> things = new ArrayList<Thing>();

    public List<Thing> getThings() {
        return this.things;
    }

}
Run Code Online (Sandbox Code Playgroud)