In the XmlAdapter you need to convert the HashMap into an instance of the object with the List property, and not directly into an ArrayList .
Hashmapadapter
package forum13163430; import java.util.*; import java.util.Map.Entry; import javax.xml.bind.annotation.*; import javax.xml.bind.annotation.adapters.XmlAdapter; public final class HashMapAdapter extends XmlAdapter<HashMapAdapter.AdaptedHashMap, HashMap<String, String>> { @Override public AdaptedHashMap marshal(HashMap<String, String> hashMap) throws Exception { AdaptedHashMap adaptedHashMap = new AdaptedHashMap(); for(Entry<String, String> entry : hashMap.entrySet()) { adaptedHashMap.item.add(new HashMapEntry(entry.getKey(), entry.getValue())); } return adaptedHashMap; } @Override public HashMap<String, String> unmarshal(AdaptedHashMap adaptedHashMap) throws Exception { HashMap<String, String> result = new HashMap<String, String>(); for(HashMapEntry entry : adaptedHashMap.item) result.put(entry.key, entry.value); return result; } public static class AdaptedHashMap { public List<HashMapEntry> item = new ArrayList<HashMapEntry>(); } public static class HashMapEntry { @XmlAttribute public String key; @XmlValue public String value; public HashMapEntry() { } public HashMapEntry(String key, String value) { this.key = key; this.value = value; } } }
Additional Information
UPDATE
Thanks, it works. However, then I get an extra layer of annotation in the prepared XML. Is there any way to avoid this?
If you use EclipseLink MOXy as a JAXB (JSR-222) , you can use the @XmlPath extension for this use case. I will give an example below.
Foo
In the HashMap property, in addition to @XmlJavaTypeAdapter I added the MOXy @XmlPath annotation. XML path "." indicates that the child should be ordered into the parent XML element.
package forum13163430; import java.util.HashMap; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; import org.eclipse.persistence.oxm.annotations.XmlPath; @XmlRootElement public class Foo { private HashMap<String, String> hashMap; public Foo() { this.hashMap = new HashMap<String, String>(); } @XmlPath(".") @XmlJavaTypeAdapter(HashMapAdapter.class) public HashMap<String, String> getHashmap() { return hashMap; } public void setHashmap(HashMap<String, String> hashMap) { this.hashMap = hashMap; } }
jaxb.properties
To specify MOXy as the JAXB provider, you need to include the file named jaxb.properties in the same package as your domain model, with the following entry (see <a3> ).
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Demo
Since MOXy is a JAXB (JSR-222) compliant implementation, standard APIs can be used to convert objects from / to XML.
package forum13163430; import java.io.File; import javax.xml.bind.*; public class Demo { public static void main(String[] args) throws Exception { JAXBContext jc = JAXBContext.newInstance(Foo.class); Unmarshaller unmarshaller = jc.createUnmarshaller(); File xml = new File("src/forum13163430/input.xml"); Foo foo = (Foo) unmarshaller.unmarshal(xml); Marshaller marshaller = jc.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); marshaller.marshal(foo, System.out); } }
Input.xml / output
Below is the entry and exit from the demo code.
<?xml version="1.0" encoding="UTF-8"?> <foo> <item key="b">B</item> <item key="c">C</item> <item key="a">A</item> </foo>
Additional Information