JAXB (Java Architecture for XML
Binding), is an easy to use and efficient framework for working with XML
documents in Java. A developer can easily convert an XML into Java objects
(Unmarshaling) and vice versa (Marshaling) using JAXB. Although simple Java
types (String, int) can be directly maps to XML types, sometimes a customized
representation is required. For e.g. consider an XML snippet below
<config>
<properties>
<property name="name 1" value="value 1"/>
<property name="name 2" value="value 2"/>
</properties>
</config>
By default JAXB will bind it to the following Java object structure
@XmlElement (name="properties" type=Properties.class)
public Properties properties;
…….
}
@XmlType
public class Properties {
@XmlElement
Let’s consider the above example
and see how can we achieve the expected output using adapters.
First of all, note that XMLAdapter is a customization on the top of default binding and hence the default classes, mentioned above, i.e. Config, Properties and Property need to be there. Now write a custom adapter. Customer adapters are provided with 2 parameters, one which JAXB will bind and one which you need as output of binding. Within adapter, you need to implement the logic of converting one to another. Here is how our custom adapter would look like.
public class CustomAdapter extends XmlAdapter> {
Poperties
properties = new Properties();
HashMap map = new HashMap(list.size());
for (Property property : list) {
<config>
<properties>
<property name="name 1" value="value 1"/>
<property name="name 2" value="value 2"/>
</properties>
</config>
By default JAXB will bind it to the following Java object structure
@XmlRootElement
public class
Config {@XmlElement (name="properties" type=Properties.class)
public Properties properties;
…….
}
@XmlType
public class Properties {
@XmlElement
public List
property;
…………
}
@XmlType
@XmlType
public class
Property {
@XmlAttribute
public String name;
@XmlAttribute
public String
value;
……….
……….
}
But imagine a scenario where you want the domain object to look like this
public class Config {
But imagine a scenario where you want the domain object to look like this
public class Config {
public
HashMap properties; //Map
of property name and value
}
This is a typical case where you want to read an XML configuration file and maintain the properties in a Map.
To achieve this, you need a mechanism to intercept the default marshaling and unmarshaling of JAXB. And this can be done using XMLAdapter.
JAXB provides interceptors, in the form of XMLAdapters, to customize the marshaling and unmarshaling during binding. The below screen explains the concept.
}
This is a typical case where you want to read an XML configuration file and maintain the properties in a Map.
To achieve this, you need a mechanism to intercept the default marshaling and unmarshaling of JAXB. And this can be done using XMLAdapter.
JAXB provides interceptors, in the form of XMLAdapters, to customize the marshaling and unmarshaling during binding. The below screen explains the concept.
First of all, note that XMLAdapter is a customization on the top of default binding and hence the default classes, mentioned above, i.e. Config, Properties and Property need to be there. Now write a custom adapter. Customer adapters are provided with 2 parameters, one which JAXB will bind and one which you need as output of binding. Within adapter, you need to implement the logic of converting one to another. Here is how our custom adapter would look like.
public class CustomAdapter extends XmlAdapter
@Override
public Properties marshal(HashMap map) throws Exception {
Iterator> itr = map.entrySet().iterator();
public Properties marshal(HashMap
Iterator
ArrayList
list = new
ArrayList(map.entrySet().size());
while (itr.hasNext()) {
Entry entry = itr.next();
Property
property = new Property();
property.setName(entry.getKey());
property.setValue(entry.getValue());
list.add(property);
}
properties.setProperties(list);
return properties;
}
@Override
public HashMap unmarshal(Properties properties) throws Exception {
List
list = properties.getProperties();
for (Property property : list) {
map.put(property.getName(),
property.getValue());
}
}
return map;
}
}
Along with this, now we need to change the root element class a bit, since we want the Hashmap as the value holder now.
Along with this, now we need to change the root element class a bit, since we want the Hashmap as the value holder now.
@XmlRootElement
public class Config {
@XmlJavaTypeAdapter (CustomAdapter.class)
@XmlElement (name="properties", type=Properties.class)
private HashMap properties;
………………
}
Now write a method to test the unmarshaling.
public void testUnmarshal() {
Now write a method to test the unmarshaling.
public void testUnmarshal() {
try {
JAXBContext
context = JAXBContext.newInstance(Config.class);
Config config = (Config) context.createUnmarshaller().unmarshal(new File("config.xml"));
Config config = (Config) context.createUnmarshaller().unmarshal(new File("config.xml"));
Iterator> itr = config.getProperties().entrySet().iterator();
while (itr.hasNext()) {
Entry entry = itr.next();
System.out.println(entry.getKey()
+ " " + entry.getValue());
}
}
catch (JAXBException e) {
e.printStackTrace();
}
}
The output of the above test method would be
The output of the above test method would be
name
1 value 1
name
2 value 2
Conclusion: JAXB provides XMLAdapters as a way to the developer to intercept the marshaling and unmarshaling process and write code to custom mappings.
Conclusion: JAXB provides XMLAdapters as a way to the developer to intercept the marshaling and unmarshaling process and write code to custom mappings.