Code examples are available from
Github in the
JAXB-JSON-XML-Marshalling directory.
How to use XmlAdapter and @XmlJavaTypeAdapter to handle Map in JAXB?
In situations where JAXB cannot handle unknown types, the solution is to create an
XmlAdapter and use the
@XmlJavaTypeAdapter in the class referring to the unknown type to indicate JAXB how to deal with it. A Java map is a good example.
We are going to illustrate this with an example. Assuming an object containing a generic map:
@XmlRootElement
public class ObjectWithGenericMap<K, V> {
private Map<K,V> map;
@XmlElement
@XmlJavaTypeAdapter(JaxbMapAdaptor.class)
public Map<K,V> getMap() {
return map;
}
public void setMap(Map<K,V> map) {
this.map = map;
}
}
We are going to need an adaptor:
public class JaxbMapAdaptor<K, V>
extends XmlAdapter<JaxbMapToList<K, V>, Map<K, V>> {
@Override
public Map<K, V> unmarshal(JaxbMapToList<K, V> v)
throws Exception {
HashMap<K, V> result = new HashMap<K, V>();
for (JaxbMapToListEntry<K, V> jme : v.getList()) {
result.put(jme.getKey(), jme.getValue());
}
return result;
}
@Override
public JaxbMapToList marshal(Map<K, V> v) throws Exception {
JaxbMapToList<K, V> result = new JaxbMapToList<K, V>();
for (Map.Entry<K, V> entry : v.entrySet()) {
JaxbMapToListEntry<K, V> jme = new JaxbMapToListEntry<K, V>();
jme.setKey(entry.getKey());
jme.setValue(entry.getValue());
result.getList().add(jme);
}
return result;
}
}
Basically, the above adaptor converts a map into a list of entries (with key and value) when marshalling, and converts this list of entries back into a HashMap when unmarshalling.
The map-to-list and corresponding entries are:
public class JaxbMapToList <K, V> {
private List<JaxbMapToListEntry<K, V>> list
= new ArrayList<JaxbMapToListEntry<K, V>>();
public JaxbMapToList() {}
public JaxbMapToList(Map<K, V> map) {
for (Map.Entry<K, V> e : map.entrySet()) {
list.add(new JaxbMapToListEntry<K, V>(e));
}
}
public List<JaxbMapToListEntry<K, V>> getList() {
return list;
}
public void setList(List<JaxbMapToListEntry<K, V>> entry) {
this.list = entry;
}
}
public class JaxbMapToListEntry<K, V> {
private K key;
private V value;
public JaxbMapToListEntry() { }
public JaxbMapToListEntry(Map.Entry<K, V> e) {
key = e.getKey();
value = e.getValue();
}
@XmlElement
public K getKey() {
return key;
}
public void setKey(K key) {
this.key = key;
}
@XmlElement
public V getValue() {
return value;
}
public void setValue(V value) {
this.value = value;
}
}
Assuming one instantiates the object with generic map with destination and transports:
@XmlRootElement
public class Destination {
private String destination;
public String getDestination() {
return destination;
}
@XmlElement
public void setDestination(String dest) {
this.destination = dest;
}
}
@XmlRootElement
public class Transport {
private String transport;
public String getTransport() {
return transport;
}
@XmlElement
public void setTransport(String transp) {
this.transport = transp;
}
}
public static void main(String[] args) throws JAXBException {
JAXBContext jaxbContext = JAXBContext.newInstance(
ObjectWithGenericMap.class,
Destination.class, Transport.class);
ObjectWithGenericMap<Destination,Transport> owgm
= new ObjectWithGenericMap<Destination,Transport>();
Map<Destination,Transport> map
= new HashMap<Destination,Transport>();
owgm.setMap(map);
Destination d = new Destination();
d.setDestination("Paris");
Transport t = new Transport();
t.setTransport("Plane");
map.put(d,t);
d = new Destination();
d.setDestination("New-York");
t = new Transport();
t.setTransport("Boat");
map.put(d,t);
ObjectWithGenericMap<Destination,Transport> retr
= marshallingUnmarshalling(jaxbContext, owgm);
for (Entry<Destination, Transport> e : retr.getMap().entrySet() ){
Destination retrd = e.getKey();
System.out.print(retrd.getDestination());
Transport retrt = e.getValue();
System.out.println(" " + retrt.getTransport());
}
}
The generated XML and verification is:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<objectWithGenericMap>
<map>
<list>
<key xsi:type="destination" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<destination>New-York</destination>
</key>
<value xsi:type="transport" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<transport>Boat</transport>
</value>
</list>
<list>
<key xsi:type="destination" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<destination>Paris</destination>
</key>
<value xsi:type="transport" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<transport>Plane</transport>
</value>
</list>
</map>
</objectWithGenericMap>
Paris Plane
New-York Boat
How to use: @XmlList, @XmlEnum, @XmlAttribute, @XmlValue, @XmlMimeType, @XmlInlineBinaryData?
To annotate an
enum:
@XmlEnum
public enum MyEnum {
@XmlEnumValue("v1")
VAL_1,
@XmlEnumValue("v2")
VAL_2;
}
To specify the xml tag value and attributes:
@XmlAccessorType(XmlAccessType.FIELD)
public class SpecialItem {
@XmlValue
private String val;
@XmlAttribute
private String attribute1;
@XmlAttribute
private String attribute2;
// Setter & Getters...
}
For remaining annotations and usage of the above:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement
public class MultipleTypes {
@XmlElement
private MyEnum myEnum;
@XmlElement
@XmlList
private List<String> data;
@XmlElement
private List<SpecialItem> specialItems;
@XmlMimeType("image/jpeg")
private Image image;
@XmlInlineBinaryData
private byte[] byteArray;
// Setter & Getters...
}
The generated XML and verification is:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<multipleTypes>
<myEnum>v2</myEnum>
<data>tre pml xng</data>
<specialItems attribute2="ffff" attribute1="aaaa">pppp</specialItems>
<specialItems attribute2="pqgd" attribute1="mer">xxw</specialItems>
<image>/9j/4AAQSkZJRgABAgAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCAALABADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwCxBe6S1ha3ptg4MEYF29lGSXKA5JIznHvmuX1UaCmhapbwxW2023mxkWUSyedsbjPXaOTkdPX+9wieM/EEOlrpkeoEWS7SIfKQj5Rgfw88AflUb+JdVl0O7tHniMMkqbh9njDcq4Pzbcjj0PrXppRo3SuTVqVKrV7aH//Z</image>
<byteArray>AQL9/A==</byteArray>
</multipleTypes>
pppp aaaa ffff
xxw mer pqgd
VAL_2
tre, pml, xng,
1 2 -3 -4
Image is available: true
Remark
We have not covered all JAXB annotations, especially those related to XML schemas, but this tutorial should be enough to get one started and accomplish most objectives with JXTA.
JAXB to XML •
JAXB to JSON •
JAXB Annotations Tutorial Table Of Content