JAXB and Multiple Object Relationships

We have been using Jersey (the Java REST library) for the project over the past few months and love it. But this week ran into a problem with JAXB.

I have an element that has 2 children, each of them has children, where some of their children turn to each other.

Let me show the code.

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); 

So, we have 1 root, 2 parents and 3 children.

If I send this up and down the JAXB path, I seem to get 4 children back.
Each parent has its own copy of child2.

Anyway, to get JAXB to serialize the relationship and show that both parent1 and parent2 point to the same object?

We only recently discovered this problem when more complex elements were passed.

If there is no way to get JAXB to do this (what I believe at the moment), does anyone have any suggestions on how I could do some kind of magic in Jersey to restore the relationship?

+4
source share
5 answers

This is not a problem with JAXB, as it is a problem with your model. How do you want JAXB to display your relationships in XML when XML does not provide a standard mechanism for expressing this? Both the consumer and the XML producer must have a layer of business logic that agrees on representation.

I suggest you redo your data. For example, instead of having children held inside parents, you could flatten:

 <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"/> 

No matter what mechanism reads and writes this structure, he should know what all this means, but I do not see any other pleasant way to do this.

Another interesting topic: XStream has support for object references when it serializes / deserializes object graphs, but it is a completely proprietary mechanism.

+3
source

JAXB supports unrestricted links between objects in the tree using the @ XmlID / @ XmlIDREF combination. The requirement for this is that all objects in the tree must also be referenced by containment relationships. In your model, this may include providing the Root collection to the Child.

Below will be a modified version of your code:

 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); 

Then your model classes would look like this:

 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; } 

The resulting XML will look like this:

 <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> 
+8
source

you could do this by writing an adapter class for the Root class, which when unmarshalling can clear child objects to remove duplicates.

+1
source

Just think: Do Child objects implement the correct equals() method?

0
source

As mentioned in other answers. This is a JAXB design.

What you can do is manually glue several copies of what you think was the same object before serialization. Then you don’t need your own identifier for objects so that you can separate clones from other objects.

0
source

All Articles