4

在过去的几个月里,我们在一个项目中使用 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 个孩子。
每个家长都有自己的 child2 副本。

有没有办法让 JAXB 序列化关系并显示 parent1 和 parent2 都指向同一个对象?

我们最近才发现这个问题,当时正在传输更复杂的元素。

如果没有办法让 JAXB 做到这一点(这就是我目前所相信的),有没有人有任何建议我可以在泽西岛做一些魔术来恢复这种关系?

4

5 回答 5

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>
于 2010-07-06T20:40:15.170 回答
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在序列化/反序列化对象图时确实支持对象引用,但它是一种完全专有的机制。

于 2009-10-08T07:24:12.633 回答
1

你可以通过为 Root 类编写一个适配器类来实现它,它在解组时可以清理子对象以删除重复项。

于 2009-10-07T23:57:38.377 回答
0

快速思考一下:Child对象是否实现了正确的equals()方法?

于 2009-10-07T23:38:07.570 回答
0

如其他答案中所述。这就是 JAXB 的设计。

您可以做的是在序列化之前手动粘合您认为是同一对象的多个副本。那么你就不需要你自己的不同对象的 ID,这样你就可以将克隆与其他对象区分开来。

于 2009-10-08T07:54:07.220 回答