JAXB和多个对象关系

时间:2009-10-07 23:23:25

标签: java jaxb jersey

我们正在使用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做到这一点(这就是我现在所相信的那样),有没有人有任何建议可以让我在泽西岛做一些魔术来重新恢复关系?

5 个答案:

答案 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,这样你就可以区分其他对象。