How to handle advanced XML IDREF links with JAXB XmlAdapter during unmarshal?

Is it possible to handle direct references of XML IDREF elements in the JAXB XmlAdapter during a non- XmlAdapter process? For example, I have the following XML complexType :

 <xs:complexType name="person"> <xs:complexContent> <xs:sequence> <xs:element name="dateOfBirth" type="xs:dateTime" minOccurs="0"/> <xs:element name="firstName" type="xs:string" minOccurs="0"/> <xs:element name="gender" type="xs:string" minOccurs="0"/> <xs:element name="guardian" type="xs:IDREF" minOccurs="0"/> <xs:element name="homePhone" type="xs:string" minOccurs="0"/> <xs:element name="lastName" type="xs:string" minOccurs="0"/> </xs:sequence> </xs:complexContent> </xs:complexType> 

where the guardian field may refer to another Person -type element elsewhere in the document. I currently use the XmlAdapter when sorting, so the first time an object is joined, it is sorted using localization, and any subsequent events of this object are sorted by reference. See the previous question. However, due to the way my XML instance documents are created, the first occurrence of the Person element may occur after the IDREF for it to happen.

Is it possible? Or do I need to approach this differently? Thanks!

+3
source share
1 answer

I have an answer to your related question . I talked about how the XmlAdapter can be used to implement a use case when the first occurrence of an object was distributed via containment / nesting and all other occurrences were ordered by reference:

Option # 1 - @XmlID / @XmlIDREF

If all your Person objects are represented via nesting, and you want to introduce some key-based relationships, it is best to use @XmlID to designate the field / property as the key and @XmlID to display the field / property as a foreign key. Your Person class will look something like this:

 @XmlAccessorType(XmlAccessType.FIELD) public class Person { @XmlID private String id; @XmlIDREF private Person guardian; } 

Additional Information

Option # 2 - Using the XmlAdapter

If you updated the XmlAdapter from my previous answer :

 package forum7587095; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlSeeAlso; import javax.xml.bind.annotation.XmlType; import javax.xml.bind.annotation.adapters.XmlAdapter; public class PhoneNumberAdapter extends XmlAdapter<PhoneNumberAdapter.AdaptedPhoneNumber, PhoneNumber>{ private List<PhoneNumber> phoneNumberList = new ArrayList<PhoneNumber>(); private Map<String, PhoneNumber> phoneNumberMap = new HashMap<String, PhoneNumber>(); @XmlSeeAlso(AdaptedWorkPhoneNumber.class) @XmlType(name="phone-number") public static class AdaptedPhoneNumber { @XmlAttribute public String id; public String number; public AdaptedPhoneNumber() { } public AdaptedPhoneNumber(PhoneNumber phoneNumber) { id = phoneNumber.getId(); number = phoneNumber.getNumber(); } public PhoneNumber getPhoneNumber() { PhoneNumber phoneNumber = new PhoneNumber(); phoneNumber.setId(id); phoneNumber.setNumber(number); return phoneNumber; } } @XmlType(name="work-phone-number") public static class AdaptedWorkPhoneNumber extends AdaptedPhoneNumber { public String extension; public AdaptedWorkPhoneNumber() { } public AdaptedWorkPhoneNumber(WorkPhoneNumber workPhoneNumber) { super(workPhoneNumber); extension = workPhoneNumber.getExtension(); } @Override public WorkPhoneNumber getPhoneNumber() { WorkPhoneNumber phoneNumber = new WorkPhoneNumber(); phoneNumber.setId(id); phoneNumber.setNumber(number); phoneNumber.setExtension(extension); return phoneNumber; } } @Override public AdaptedPhoneNumber marshal(PhoneNumber phoneNumber) throws Exception { AdaptedPhoneNumber adaptedPhoneNumber; if(phoneNumberList.contains(phoneNumber)) { if(phoneNumber instanceof WorkPhoneNumber) { adaptedPhoneNumber = new AdaptedWorkPhoneNumber(); } else { adaptedPhoneNumber = new AdaptedPhoneNumber(); } adaptedPhoneNumber.id = phoneNumber.getId(); } else { if(phoneNumber instanceof WorkPhoneNumber) { adaptedPhoneNumber = new AdaptedWorkPhoneNumber((WorkPhoneNumber)phoneNumber); } else { adaptedPhoneNumber = new AdaptedPhoneNumber(phoneNumber); } phoneNumberList.add(phoneNumber); } return adaptedPhoneNumber; } @Override public PhoneNumber unmarshal(AdaptedPhoneNumber adaptedPhoneNumber) throws Exception { PhoneNumber phoneNumber = phoneNumberMap.get(adaptedPhoneNumber.id); if(null != phoneNumber) { if(adaptedPhoneNumber.number != null) { phoneNumber.setNumber(adaptedPhoneNumber.number); } return phoneNumber; } phoneNumber = adaptedPhoneNumber.getPhoneNumber(); phoneNumberMap.put(phoneNumber.getId(), phoneNumber); return phoneNumber; } } 

You can then decouple the XML documents, which look like this, where the link first occurs:

 <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <customer> <phone-number id="A"/> <phone-number id="B"> <number>555-BBBB</number> </phone-number> <phone-number id="A"> <number>555-AAAA</number> </phone-number> <phone-number xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="work-phone-number" id="W"> <number>555-WORK</number> <extension>1234</extension> </phone-number> <phone-number xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="work-phone-number" id="W"/> </customer> 
+6
source

All Articles