Search code examples
eclipselinkmarshallingmoxy

Moxy List<Map<String,String>> not expected marshalling


I'm trying to marshal this class:

package otherTest;

import java.util.Collection;
import java.util.List;
import java.util.Map;

public class SearchResult {


    private List<Map<String,String>> listOfMap;

    private Map<String,Collection<String>> mapWithList;


    public List<Map<String, String>> getListOfMap() {
        return listOfMap;
    }

    public void setListOfMap(List<Map<String, String>> listOfMap) {
        this.listOfMap = listOfMap;
    }

    public Map<String, Collection<String>> getMapWithList() {
        return mapWithList;
    }

    public void setMapWithList(Map<String, Collection<String>> mapWithList) {
        this.mapWithList = mapWithList;
    }
    public SearchResult(){}

}

oxm.xml

<?xml version="1.0"?>
<xml-bindings 
    xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
    package-name="otherTest" 
    xml-mapping-metadata-complete="true">
    <java-types>
        <java-type name="SearchResult">
            <xml-root-element/>
            <java-attributes>
                <xml-element java-attribute="listOfMap"/>
                <xml-element java-attribute="mapWithList"/>
            </java-attributes>
        </java-type>
    </java-types>
</xml-bindings>

Demo.java

package otherTest;

import java.io.InputStream;
import java.util.*;

import javax.xml.bind.*;
import org.eclipse.persistence.jaxb.JAXBContextProperties;

public class Demo {

    public static void main(String[] args) throws Exception {
        Map<String, Object> properties = new HashMap<String , Object>();
        ClassLoader classLoader = Demo.class.getClassLoader();
        InputStream modelStream = classLoader.getResourceAsStream("otherTest/oxm.xml");
        properties.put(JAXBContextProperties.OXM_METADATA_SOURCE, modelStream);
        JAXBContext jc = JAXBContext.newInstance(new Class[] {SearchResult.class}, properties);

        List<Map<String,String>> results = new ArrayList<Map<String,String>>();
        Map<String,String> test = new HashMap<String,String>();

        Map<String,Collection<String>> daMashalare = new HashMap<String,Collection<String>>();


        test.put("id","10");
        test.put("publicationTitle","20");
        test.put("paginazione","boh");
        test.put("pageSize", "10");
        results.add(test);

        Collection<String> listaString = new ArrayList<String>();
        listaString.add("testlist");
        daMashalare.put("nothing",listaString);

        SearchResult result = new SearchResult();
        result.setListOfMap(results);
        result.setMapWithList(daMashalare);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(result, System.out);
    }

}

Unluckly the output that I get is:

<?xml version="1.0" encoding="UTF-8"?>
<searchResult>
   <listOfMap>{id=10, paginazione=boh, pageSize=10, publicationTitle=20}</listOfMap>
   <mapWithList>
      <entry>
         <key>nothing</key>
         <value>testlist</value>
      </entry>
   </mapWithList>
</searchResult>

So As you can see the listOfMap attribute is not how I would like to see it

<?xml version="1.0" encoding="UTF-8"?>
<searchResult>
   <listOfMap>
      <id>10</id>
      <paginazione>boh</paginazione>
      <pageSize>10</pageSize>
      <publicationTitle>20</publicationTitle>
   </listOfMap>
   <mapWithList>
      <entry>
         <key>nothing</key>
         <value>testlist</value>
      </entry>
   </mapWithList>
</searchResult>

How Can I set an adapter to solve this problem? I have also included this test package: that you can download and test it http://bit.ly/14aWIu1

Thank you


Solution

  • This is a generic solution for Map: MapAdapter<K,V>

        package otherTest;    
        import java.util.HashMap;
        import java.util.Map;
        import javax.xml.bind.annotation.adapters.XmlAdapter;
    
        public class MapAdapter<K, V> extends XmlAdapter<MapType<K, V>, Map<K, V>> {
    
            @Override
            public Map<K, V> unmarshal(MapType<K, V> v) throws Exception {
                HashMap<K, V> map = new HashMap<K, V>();
    
                for (MapEntryType<K, V> mapEntryType : v.getEntry()) {
                    map.put(mapEntryType.getKey(), mapEntryType.getValue());
                }
                return map;
            }
    
            @Override
            public MapType marshal(Map<K, V> v) throws Exception {
                MapType<K, V> mapType = new MapType<K, V>();
    
                for (Map.Entry<K, V> entry : v.entrySet()) {
                    MapEntryType<K, V> mapEntryType = new MapEntryType<K, V>();
                    mapEntryType.setKey(entry.getKey());
                    mapEntryType.setValue(entry.getValue());
                    mapType.getEntry().add(mapEntryType);
                }
                return mapType;
            }
        }
    

    MapEntryType<K,V>

        package otherTest;
    
        import java.util.Map;
        import javax.xml.bind.annotation.XmlAccessType;
        import javax.xml.bind.annotation.XmlAccessorType;
        import javax.xml.bind.annotation.XmlElement;
    
    
        @XmlAccessorType(XmlAccessType.PROPERTY)
        public class MapEntryType<K, V> {
    
            private K key;
            private V value;
    
            public MapEntryType() {
            }
    
            public MapEntryType(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;
            }
        }
    

    MapType<K,V>

        package otherTest;
    
        import java.util.ArrayList;
        import java.util.List;
        import java.util.Map;
    
    
        public class MapType<K, V> {
    
            private List<MapEntryType<K, V>> entry = new ArrayList<MapEntryType<K, V>>();
    
            public MapType() {
            }
    
            public MapType(Map<K, V> map) {
                for (Map.Entry<K, V> e : map.entrySet()) {
                    entry.add(new MapEntryType<K, V>(e));
                }
            }
    
            public List<MapEntryType<K, V>> getEntry() {
                return entry;
            }
    
            public void setEntry(List<MapEntryType<K, V>> entry) {
                this.entry = entry;
            }
        }
    

    SearchResult

        package otherTest;
    
        import java.util.Collection;
        import java.util.List;
        import java.util.Map;
    
        import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
    
        public class SearchResult {
    
    
            private List<Map<String,String>> listOfMap;
    
            private Map<String,Collection<String>> mapWithList;
    
            @XmlJavaTypeAdapter(MapAdapter.class)
            public List<Map<String, String>> getListOfMap() {
                return listOfMap;
            }
    
            public void setListOfMap(List<Map<String, String>> listOfMap) {
                this.listOfMap = listOfMap;
            }
    
            public Map<String, Collection<String>> getMapWithList() {
                return mapWithList;
            }
    
            public void setMapWithList(Map<String, Collection<String>> mapWithList) {
                this.mapWithList = mapWithList;
            }
            public SearchResult(){}
    
        }
    

    Test

        package otherTest;
    
        import java.io.InputStream;
    
        import java.util.ArrayList;
        import java.util.HashMap;
        import java.util.List;
        import java.util.Map;
    
        import javax.xml.transform.TransformerException;
        import javax.xml.bind.JAXBContext;
        import javax.xml.bind.JAXBException;
        import javax.xml.bind.Marshaller;
    
        import org.eclipse.persistence.jaxb.JAXBContextProperties;
    
    
            public class Test {
    
                public static void main(String[] args) throws TransformerException, Exception {
    
                    Map<String, Object> properties = new HashMap<String, Object>();
                    Marshaller marshaller = null;
                    ClassLoader classLoader = Test.class.getClassLoader();
    
                    List<Map<String,String>> results = new ArrayList<Map<String,String>>();
                    Map<String,String> test = new HashMap<String,String>();
                    test.put("id","10");
                    test.put("publicationTitle","20");
                    test.put("paginazione","boh");
                    test.put("pageSize", "10");
                    results.add(test);
    
                    InputStream modelStream = classLoader.getResourceAsStream("test/oxm.xml");
                    JAXBContext ctx = null;
                    properties.put(JAXBContextProperties.OXM_METADATA_SOURCE, modelStream );
                    try {
                        ctx = JAXBContext.newInstance(new Class[] {SearchResult.class}, properties);
                    } catch (JAXBException e) {
                        e.printStackTrace();
                    }
                    marshaller = ctx.createMarshaller();
                    marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
                    SearchResult result = new SearchResult();
                    result.setListOfMap(results);
                    marshaller.marshal(result, System.out);
    
                }
    
            }
    

    Output

    <?xml version="1.0" encoding="UTF-8"?>
    <listOfMap>
       <entry>
          <key xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xsd:string">id</key>
          <value xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xsd:string">10</value>
       </entry>
       <entry>
          <key xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xsd:string">paginazione</key>
          <value xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xsd:string">boh</value>
       </entry>
       <entry>
          <key xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xsd:string">pageSize</key>
          <value xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xsd:string">10</value>
       </entry>
       <entry>
          <key xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xsd:string">publicationTitle</key>
          <value xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xsd:string">20</value>
       </entry>
    </listOfMap>