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.