JAXB marshal an ArrayList created by XmlAdapter

前端 未结 1 659
抹茶落季
抹茶落季 2021-01-06 06:36

I want to adapt the XML representation of a HashMap field using XmlAdapter. I use an ArrayList to do that. However, when marshalling t

相关标签:
1条回答
  • 2021-01-06 07:05

    In your XmlAdapter you need to convert the HashMap to an an instance of an object with a List property instead of directly to 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;
            }
        }
    
    }
    

    For More Information

    • http://blog.bdoughan.com/2010/07/xmladapter-jaxbs-secret-weapon.html

    UPDATE

    Thanks, this works. However then I get an additional level of annotation in the produced XML. Is there any way to avoid that?

    If you are using EclipseLink MOXy as your JAXB (JSR-222) provider then you can leverage the @XmlPath extension for this use case. I'll demonstrate below with an example.

    Foo

    On the hashmap property in additional to the @XmlJavaTypeAdapter I have added MOXy's @XmlPath annotation. An XML path of "." indicates that the child should be marshalled into the parents 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 your JAXB provider you need to include a file called jaxb.properties in the same package as your domain model with the following entry (see: http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html).

    javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
    

    Demo

    Since MOXy is JAXB (JSR-222) compliant implementation, the 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 input to and output from running 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>
    

    For More Information

    • http://blog.bdoughan.com/2010/07/xpath-based-mapping.html
    0 讨论(0)
提交回复
热议问题