For the follwing example XML input:
<Participants course="someCourse">
<workers>
<Worker ref="p3">
<Worker ref="p2">
</workers>
<Trainer ref="p1"/>
</Participants>
<Group id="group1" name="some mixed Person group">
<trainers>
<Trainer id="p1" name="John Doe">
</trainers>
<workers>
<Worker id="p2" name="Jim Scott">
<Worker id="p3" name="Walter Peace">
</workers>
</Group>
I am trying to make sure that the PersonList in Participants points to the Persons read from group1. (see code snipptes below for the JaxB annotations used). This is just an example for the more generic approach I am seeking. I need to be generally able to follow id="" and ref="" attributes in a way that the list elements are correctly unmarshalled as references.
With an UnmarshalListener and Unmarshalling twice I get around the problem of the references from the ref attribute to the id attribute. In the first phase the lookup Map is filled from the id attributes. In the second phase the refs are looked up. Unfortunately this solution will create copies instead of references. I could use the parent object to fix this but I am looking for a more generic solution. What would be a good way to achieve the proper dereferencing using ref/id attributes in the manner shown?
/**
* intercept the unmarshalling
*/
public static class ModelElementMarshallerListener extends javax.xml.bind.Unmarshaller.Listener {
public Map<String,Person> lookup=new HashMap<String,Person>();
@Override
public void afterUnmarshal(java.lang.Object target, java.lang.Object parent) {
if (target instanceof Person) {
person=(Person) target;
if (person.getId()!=null) {
lookup.put(person.getId(), person);
}
if (person.getRef()!=null) {
if (lookup.containsKey(person.getRef())) {
Person personRef=lookup.get(person.getRef());
person.copyFrom(personRef);
person.setRef(null);
}
}
}
}
}
@XmlRootElement(name="Participants")
public class Participants {
private List<Worker> workers;
/**
* getter for List<Worker> workers
* @return workers
*/
@XmlElementWrapper(name="workers")
@XmlElement(name="Worker", type=Worker.class)
public List<Worker> getWorkers() {
return workers;
}
...
}
@XmlRootElement(name="Group")
public class Group {
private List<Worker> workers;
/**
* getter for List<Worker> workers
* @return workers
*/
@XmlElementWrapper(name="workers")
@XmlElement(name="Worker", type=Worker.class)
public List<Worker> getWorkers() {
return workers;
}
...
}
@XmlRootElement(name="Trainer")
public class Trainer extends Person {}
@XmlRootElement(name="Worker")
public class Worker extends Person {}
@XmlRootElement(name="Person")
public class Person {
private String name;
/**
* getter for xsd:string/String name
* @return name
*/
@XmlAttribute(name="name")
public String getName() {
return name;
}
public void setName(String name) {
this.name=name;
}
private String ref;
/**
* getter for xsd:string/String id
* @return id
*/
@XmlAttribute(name="ref")
public String getRef() {
return ref;
}
public void setRef(String ref) {
this.ref=ref;
}
private String id;
/**
* getter for xsd:string/String id
* @return id
*/
@XmlAttribute(name="id")
@XmlID
public String getId() {
this.id;
}
/**
* setter for xsd:string/String id
* @param pid - new value for id
*/
public void setId(String pid) {
this.id=pid;
}
}