我们正在使用Jersey(Java REST库)进行过去几个月的项目并热爱它。但本周JAXB遇到了一个问题。
我所拥有的是一个有2个孩子的元素,每个孩子都有 孩子们,他们的一些孩子互相参照。
让我展示一些代码。
Root root = new Root();
Parent parent1 = new Parent();
Parent parent2 = new Parent();
root.add(parent1);
root.add(parent2);
Child child1 = new Child();
Child child2 = new Child();
Child child3 = new Child();
parent1.add(child1);
parent1.add(child2);
parent2.add(child2);
parent2.add(child3);
所以我们有1个根,2个父母和3个孩子。
如果我在JAXB路径上下来发送,我似乎找回了4个孩子 每个Parent都有自己的child2副本。
有没有让JAXB序列化关系并显示parent1和parent2都指向同一个对象?
我们最近才发现这个问题,当时传输的元素更复杂。
如果没有办法让JAXB做到这一点(这就是我现在所相信的那样),有没有人有任何建议可以让我在泽西岛做一些魔术来重新恢复关系?
答案 0 :(得分:8)
JAXB使用@ XmlID / @ XmlIDREF的组合支持树中对象之间的非包含引用。对此的要求是树中的所有对象也必须由包含关系引用。在你的模型中,这可能涉及给Root一个Child的集合。
以下是您的代码的修改版本:
Root root = new Root();
Parent parent1 = new Parent();
Parent parent2 = new Parent();
root.add(parent1);
root.add(parent2);
Child child1 = new Child();
child1.id = "1";
root.add(child1);
parent1.add(child1);
Child child2 = new Child();
child2.id = "2";
root.add(child2);
parent1.add(child2);
parent2.add(child2);
Child child3 = new Child();
child3.id = "3";
root.add(child3);
parent2.add(child3);
然后你的模型类看起来像:
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class Root {
public List<Parent> parent = new ArrayList<Parent>();
public List<Child> child = new ArrayList<Child>();
public void add(Parent parent1) {
parent.add(parent1);
}
public void add(Child child1) {
child.add(child1);
}
}
import javax.xml.bind.annotation.XmlIDREF;
public class Parent {
@XmlIDREF
public List<Child> child = new ArrayList<Child>();
public void add(Child child1) {
child.add(child1);
}
}
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlID;
public class Child {
@XmlID
@XmlAttribute
public String id;
}
生成的XML看起来像:
<root>
<parent>
<child>1</child>
<child>2</child>
</parent>
<parent>
<child>2</child>
<child>3</child>
</parent>
<child id="1"/>
<child id="2"/>
<child id="3"/>
</root>
答案 1 :(得分:3)
这对JAXB来说不是问题,因为它对您的模型有问题。当XML没有提供标准机制来表达时,您希望JAXB如何在XML中呈现您的关系? XML的消费者和生产者都需要有一层商业逻辑,这些逻辑将在代表中达成一致。
我建议您需要重新构建数据。例如,不要让孩子被包含在父母中,你可以将事情弄平:
<parent id="parent1">
<child ref="child1"/>
<child ref="child2"/>
</parent>
<parent id="parent2">
<child ref="child2"/>
<child ref="child3"/>
</parent>
<child id="child1"/>
<child id="child2"/>
<child id="child3"/>
无论什么机制读写,这个结构都必须知道它的意思,但我没有看到任何其他好方法。
另一个兴趣点是XStream在序列化/反序列化对象图时确实有support for object references,但它是一个完全专有的机制。
答案 2 :(得分:1)
你可以通过为Root类编写一个适配器类来实现它,在解组时可以清理子对象以删除重复项。
答案 3 :(得分:0)
快速思考一下:Child
对象是否实现了正确的equals()
方法?
答案 4 :(得分:0)
正如其他答案中所述。这是JAXB的设计。
您可以做的是在序列化之前手动粘贴您认为是同一对象的多个副本。那么你不需要你自己的对象的不同ID,这样你就可以区分其他对象。