Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JAXB and multiple object relationships

Tags:

java

jaxb

jersey

We are using Jersey (Java REST library) for a project for the last few months and loving it. But this week have run into an issue with JAXB.

What I have is an element that has 2 children, each of them have children where some of their children reference each other.

Let me show some 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 back 4 children.
Each Parent has their own copy of child2.

Is there anyway to get JAXB to serialise the relationship and show that both parent1 and parent2 point to the same object?

We only found this issue recently, when more complex elements were being transmitted.

If there is no way to get JAXB to do this (thats what I believe at the moment), does anyone have any suggestions of a way I could do some magic in Jersey to re-instate the relationship?

like image 861
stevemac Avatar asked Dec 17 '22 05:12

stevemac


1 Answers

JAXB does support non-containment references between objects in the tree using a combination of @XmlID/@XmlIDREF. A requirement for this is that all objects in the tree must also be referenced by a containment relationship. In your model this might involve giving Root a collection of Child.

Below would 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:

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 would look like:

<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>
like image 54
bdoughan Avatar answered Jan 04 '23 15:01

bdoughan