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,因为此处的顺序不正确。 但除此之外,在这种情况下,我得到Second
和First
, Third
,失去了。
无法在超类型上注释属性,并且可以逐步添加子映射。 以下是一种可以支持您所使用的所有用例的方法。 需要注意的一件事是,对象层次结构中的所有级别都支持同一组元素。 您需要使用外部validation方法来限制所需的值。
如果Thing
是一个类而不是一个接口,并且First
和Second
扩展了Thing
那么你可能会对使用@XmlElementRef
而不是@XmlElements
感兴趣(参见: http : //blog.bdoughan.com/2010/11/jaxb-and-inheritance -using-substitution.html )。 它将以一些validation为代价提供更多灵活性(很难限制有效值集)。
酒吧
我们将使用@XmlTransient
对Bar
进行注释,以便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 { }