In a previous post I introduced EclipseLink JAXB (MOXy)'s @XmlVariableNode extension. In this post I'll demonstrate how @XmlVariableNode could be leveraged to handle an interesting question I came across on Stack Overflow. In that question instead of a collection being represented with an element that appeared multiple times, the element name contained the index. While I would never recommend structuring your XML document this way sometimes you encounter it and need to be able to map it.
XML Input (input.xml)/Output
Below is what the problematic XML looks like. In this example the number of different elements prefixed with phone-number is not known.
<?xml version="1.0" encoding="UTF-8"?> <customer> <phone-number1 type="work">555-1111</phone-number1> <phone-number2 type="home">555-2222</phone-number2> <phone-number3 type="cell">555-3333</phone-number3> </customer>
Java Model
Below is the Java model that we will use for this example.
Customer
package blog.variablenode.enumeratedlist; import java.util.*; import javax.xml.bind.annotation.*; import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; import org.eclipse.persistence.oxm.annotations.XmlVariableNode; @XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) public class Customer { @XmlVariableNode("nodeName") @XmlJavaTypeAdapter(PhoneNumberAdapter.class) private List<PhoneNumber> phoneNumbers = new ArrayList<PhoneNumber>(); }
PhoneNumber
package blog.variablenode.enumeratedlist; import javax.xml.bind.annotation.*; @XmlAccessorType(XmlAccessType.FIELD) public class PhoneNumber { @XmlAttribute private String type; @XmlValue private String number; }
XMLAdapter (PhoneNumberAdapter)
package blog.variablenode.enumeratedlist; import javax.xml.bind.annotation.XmlTransient; import javax.xml.bind.annotation.adapters.XmlAdapter; import org.eclipse.persistence.oxm.annotations.XmlPath; public class PhoneNumberAdapter extends XmlAdapter<PhoneNumberAdapter.AdaptedPhoneNumber, PhoneNumber>{ private int counter = 1; public static class AdaptedPhoneNumber { @XmlTransient public String nodeName; @XmlPath(".") public PhoneNumber phoneNumber; } @Override public AdaptedPhoneNumber marshal(PhoneNumber phoneNumber) throws Exception { AdaptedPhoneNumber adaptedPhoneNumber = new AdaptedPhoneNumber(); adaptedPhoneNumber.nodeName = "phone-number" + counter++; adaptedPhoneNumber.phoneNumber = phoneNumber; return adaptedPhoneNumber; } @Override public PhoneNumber unmarshal(AdaptedPhoneNumber adaptedPhoneNumber) throws Exception { return adaptedPhoneNumber.phoneNumber; } }
Demo
package blog.variablenode.enumeratedlist; import java.io.File; import javax.xml.bind.*; public class Demo { public static void main(String[] args) throws Exception { JAXBContext jc = JAXBContext.newInstance(Customer.class); Unmarshaller unmarshaller = jc.createUnmarshaller(); File xml = new File("src/blog/variablenode/enumeratedlist/input.xml"); Customer customer = (Customer) unmarshaller.unmarshal(xml); Marshaller marshaller = jc.createMarshaller(); PhoneNumberAdapter phoneNumberAdapter = new PhoneNumberAdapter(); marshaller.setAdapter(phoneNumberAdapter); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); marshaller.marshal(customer, System.out); } }
Further Reading
If you enjoyed this post then you may also be interested in:
- JAXB & Collection Properties
- MOXy's @XmlVariableNode - JSON Schema Example
- MOXy's @XmlVariableNode - Using a Map's Key as the Node Name
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.