我目前在我的项目中有这个环境:
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(); }
}
对于以下XML文档
<bobar>
<first>blablabla</first>
<second>blublublu</second>
</bobar>
当我这样做时
context = JAXBContext.newInstance("the.package.structure");
unmarshaller = context.createUnmarshaller();
Bar object = (Bar) unmarshaller.unmarshal("path-to-xml-document");
栏object
在集合中只有一个元素,而不是2. First
元素完全丢失,当我尝试object.getThings()
时,它的大小为1且是唯一的集合中的对象是Second
的实例。有人可以帮助我如何在集合中获取两个对象?如果那是不可能的,我怎样才能实现与此相似的东西呢?
我这样做的原因是(在我的项目逻辑中)每个Bobar
的东西集合在其集合中都有First
,但不是每个Bar
都有{Second
1}}在其集合中,Foo
是一个通用类。
当我更改XML文档中的顺序时,输出是不同的。
<bobar>
<second>blablabla</second>
<first>blublublu</first>
</bobar>
在这种情况下,我只在集合中获得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(); }
}
如果我这样做
<bobar>
<third>bliblibli</third>
<second>blablabla</second>
<first>blublublu</first>
</bobar>
理论上,我认为这不应该针对由此生成的XML Schema进行验证,因为此处的顺序不正确。但除此之外,在这种情况下,我得到Second
和First
,Third
丢失了。
答案 0 :(得分:4)
无法在超类型上注释属性,并且可以逐步添加子映射。以下是一种可以支持您所使用的所有用例的方法。需要注意的一件事是,对象层次结构中的所有级别都支持同一组元素。您需要使用外部验证方法来限制所需的值。
如果Thing
是一个类而不是一个界面,并且First
和Second
延伸Thing
,那么您可能有兴趣使用@XmlElementRef
代替{{ 1}}(参见:http://blog.bdoughan.com/2010/11/jaxb-and-inheritance-using-substitution.html)。它将以一些验证为代价提供更多灵活性(难以限制有效值集)。
<强>酒吧强>
我们将使用@XmlElements
注释Bar
,以便JAXB实现不会处理它。
@XmlTransient
<强> Bobar则强>
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();
}
}
对应于XML模式中替换组的概念。与属性匹配的值将基于@XmlElementRef
声明。
@XmlRootElement
<强>事强>
由于JAXB实现不能使用反射来查找类型的所有子类,因此我们可以使用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();
}
}
注释来帮助解决问题。如果您不使用此注释,则需要在引导@XmlSeeAlso
时包含所有子类型。
JAXBContext
<强>第一强>
我们需要使用package forum11698160;
import javax.xml.bind.annotation.XmlSeeAlso;
@XmlSeeAlso({First.class, Second.class})
public class Thing {
}
注释First
:
@XmlRootElement
<强>第二强>
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 {
}
<强> input.xml中/输出强>
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);
}
}
其他文件
以下是运行此示例所需的其他文件:
<强>富强>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<bobar>
<first/>
<second/>
</bobar>
答案 1 :(得分:2)
以下是利用@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<Thing> getThings() {
return super.getThings();
}
}
<强>酒吧强>
您也无法覆盖继承的属性。因此,我们需要在类型级别使用@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<Thing> 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中/输出强>
<?xml version="1.0" encoding="UTF-8"?>
<bobar>
<first/>
<second/>
</bobar>
其他文件
以下是运行此示例所需的其他文件:
<强>富强>
package forum11698160;
import java.util.*;
public abstract class Foo {
private List<Thing> things = new ArrayList<Thing>();
public List<Thing> getThings() {
return this.things;
}
}
<强>事强>
package forum11698160;
public interface Thing {
}
<强>第一强>
package forum11698160;
public class First implements Thing {
}
<强>第二强>
package forum11698160;
public class Second implements Thing {
}