JAXBinheritance冲突 – 在子类上重新注释

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

public abstract class Foo { private List things; public List getThings() { return this.things; } } public abstract class Bar extends Foo { @XmlElements({@XmlElement(name = "first", type = First.class)}) public List getThings() { return super.getThings(); } } public class Bobar extends Bar { @XmlElements({@XmlElement(name = "second", type = Second.class)}) public List getThings() { return super.getThings(); } } 

对于以下XML文档

  blablabla blublublu  

当我做

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

Bar object在集合中只有一个元素,而不是2.第First元素完全丢失,当我尝试执行object.getThings() ,它的大小为1,集合中唯一的对象是Second的实例。 有人可以帮助我如何实现在集合中获取两个对象? 如果那是不可能的,我怎样才能实现与此相似的东西?

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

编辑:

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

  blablabla blublublu  

在这种情况下,我只在集合中获得First的实例,而Second则丢失。 更改方案,我得到了有趣的结果:

 public abstract class Foo { private List things; public List 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 getThings() { return super.getThings(); } } public class Bobar extends Bar { @XmlElements({@XmlElement(name = "second", type = Second.class)}) public List getThings() { return super.getThings(); } } 

如果我做

  bliblibli blablabla blublublu  

从理论上讲,我认为这不应该针对由此生成的XML Schema进行validation,因为此处的顺序不正确。 但除此之外,在这种情况下,我得到SecondFirstThird ,失去了。

无法在超类型上注释属性,并且可以逐步添加子映射。 以下是一种可以支持您所使用的所有用例的方法。 需要注意的一件事是,对象层次结构中的所有级别都支持同一组元素。 您需要使用外部validation方法来限制所需的值。

如果Thing是一个类而不是一个接口,并且FirstSecond扩展了Thing那么你可能会对使用@XmlElementRef而不是@XmlElements感兴趣(参见: http : //blog.bdoughan.com/2010/11/jaxb-and-inheritance -using-substitution.html )。 它将以一些validation为代价提供更多灵活性(很难限制有效值集)。

酒吧

我们将使用@XmlTransientBar进行注释,以便JAXB实现不处理它。

 package forum11698160; import java.util.List; import javax.xml.bind.annotation.XmlTransient; @XmlTransient public abstract class Bar extends Foo { public List getThings() { return super.getThings(); } } 

Bobar则

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

 package forum11698160; import java.util.List; import javax.xml.bind.annotation.*; @XmlRootElement public class Bobar extends Bar { @XmlElementRef public List getThings() { return super.getThings(); } } 

事情

由于JAXB实现不能使用reflection来查找类型的所有子类,因此我们可以使用@XmlSeeAlso注释来帮助。 如果不使用此批注,则需要在引导JAXBContext时包含所有子类型。

 package forum11698160; import javax.xml.bind.annotation.XmlSeeAlso; @XmlSeeAlso({First.class, Second.class}) public class Thing { } 

第一

我们需要使用@XmlRootElement注释First

 package forum11698160; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement public class First extends Thing { } 

第二

Second也需要用@XmlRootElement注释:

 package forum11698160; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement public class Second extends Thing { } 

演示

 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); } } 

input.xml中/输出

      

其他文件

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

 package forum11698160; import java.util.*; public abstract class Foo { private List things = new ArrayList(); public List getThings() { return this.things; } } 

以下是利用@XmlTransient映射此用例的@XmlTransient

Bobar则

您不能在子类中扩展映射,因此您需要确保在执行@XmlElements映射时执行所有操作(请参阅: http : //blog.bdoughan.com/2010/10/jaxb-and-xsd-choice -xmlelements.html )。

 package forum11698160; import java.util.List; import javax.xml.bind.annotation.*; @XmlRootElement public class Bobar extends Bar { @XmlElements({ @XmlElement(name = "first", type = First.class), @XmlElement(name = "second", type = Second.class) }) public List getThings() { return super.getThings(); } } 

酒吧

您也无法覆盖inheritance的属性。 因此,我们需要在类型级别使用@XmlTransient来指示我们不希望我们的JAXB实现处理超类型(请参阅: http : //blog.bdoughan.com/2011/06/ignoring-inheritance-with -xmltransient.html )。

 package forum11698160; import java.util.List; import javax.xml.bind.annotation.*; @XmlTransient public abstract class Bar extends Foo { public List getThings() { return super.getThings(); } } 

演示

以下演示代码可用于演示一切正常:

 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); } } 

input.xml中/输出

      

其他文件

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

 package forum11698160; import java.util.*; public abstract class Foo { private List things = new ArrayList(); public List getThings() { return this.things; } } 

事情

 package forum11698160; public interface Thing { } 

第一

 package forum11698160; public class First implements Thing { } 

第二

 package forum11698160; public class Second implements Thing { }