JAXB Marshall a Map structure of generic type

Following this example (http://blog.bdoughan.com/2010/07/xmladapter-jaxbs-secret-weapon.html) of Blaise Doughan that works, i am trying to generalize it to any type using generics. I obtained :

import java.util.*;
import javax.xml.bind.annotation.*;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class MyMapType<K, V> {

    public List<MyMapEntryType<K, V>> entry;

    public MyMapType() {
        entry = new ArrayList<MyMapEntryType<K, V>>();
    }

}

and ,

import javax.xml.bind.annotation.*;

public class MyMapEntryType<K, V> {

    @XmlAttribute
    public K key;

    @XmlValue
    public V value;

}

then,

import java.util.*;
import java.util.Map.Entry;

import javax.xml.bind.annotation.adapters.XmlAdapter;

public final class MyMapAdapter<K, V> extends
        XmlAdapter<MyMapType<K, V>, Map<K, V>> {

    @Override
    public MyMapType<K, V> marshal(Map<K, V> arg0) throws Exception {
        MyMapType<K, V> myMapType = new MyMapType<K, V>();
        for (Entry<K, V> entry : arg0.entrySet()) {
            MyMapEntryType<K, V> myMapEntryType = new MyMapEntryType<K, V>();
            myMapEntryType.key = entry.getKey();
            myMapEntryType.value = entry.getValue();
            myMapType.entry.add(myMapEntryType);
        }
        return myMapType;
    }

    @Override
    public Map<K, V> unmarshal(MyMapType<K, V> arg0) throws Exception {
        HashMap<K, V> hashMap = new HashMap<K, V>();
        for (MyMapEntryType<K, V> myEntryType : arg0.entry) {
            hashMap.put(myEntryType.key, myEntryType.value);
        }
        return hashMap;
    }

}

finally,

package forum832656;

import java.util.*;
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Foo<K, V> {

    @XmlJavaTypeAdapter(MyMapAdapter.class)
    Map<K, V> map = new HashMap<K, V>();

    public Foo() {
    }

    public Map<K, V> getMap() {
        return map;
    }

    public void setMap(Map<K, V> map) {
        this.map = map;
    }

}

Then i tried this,

 Foo<Integer,String> f = new Foo<Integer,String>();
    f.getMap().put(1, "HELLO");
    f.getMap().put(2, "WORLD");


    JAXBContext context =   JAXBContext.newInstance(Foo.class,MyMapType.class);
        Marshaller m = context.createMarshaller();
        m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
        m.marshal(f, System.out);

But i obtained a NullPointerException on JAXBContext creation line.... Any idea?

Answers


I solved this with a recursive Adapter:

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.adapters.XmlAdapter;

public class MapAdapter<K, V> extends XmlAdapter<Adapter<K, V>, Map<K, V>> {

    @Override
    public Map<K, V> unmarshal(Adapter<K, V> v) throws Exception {
        if (v == null) {
            return null;
        }
        Map<K, V> map = new HashMap<K, V>();
        for (MyEntry<K, V> mapEntryType : v.getEntries()) {
            map.put(rUnmarshal(mapEntryType.getKey()),     rUnmarshal(mapEntryType.getValue()));
        }
        return map;
    }

    @Override
    public Adapter<K, V> marshal(Map<K, V> v) throws Exception {
        if (v == null) {
            return null;
        }
        return new Adapter<K, V>(v);
    }

    @SuppressWarnings("unchecked")
    private static <T> T rUnmarshal(T obj) throws Exception {
        if (obj instanceof Adapter) {
            return (T) new MapAdapter<>().unmarshal((Adapter<Object, Object>) obj);
        }
        return obj;
    }

    @SuppressWarnings("unchecked")
    static <T> T rMarshal(T obj) throws Exception {
        if (obj instanceof Map) {
            return (T) new MapAdapter<>().marshal((Map<Object, Object>) obj);
        }
        return obj;
    }

    @XmlType
    @XmlRootElement
    public final static class Adapter<K, V> {

        @XmlElement
        protected List<MyEntry<K, V>> fEntries = new LinkedList<MyEntry<K, V>>();

        // needed for JAXB
        @SuppressWarnings("unused")
        private Adapter() {
        }

        public Adapter(Map<K, V> original) throws Exception {
            for (Map.Entry<K, V> entry : original.entrySet()) {
                this.fEntries.add(new MyEntry<K, V>(entry));
            }
        }

        public List<MyEntry<K, V>> getEntries() {
            return this.fEntries;
        }

    }

    @XmlType
    @XmlRootElement
    public final static class MyEntry<K, V> {

        @XmlElement
        protected K fKey;

        @XmlElement
        protected V fValue;

        // needed for JAXB
        @SuppressWarnings("unused")
        private MyEntry() {
        }

        public MyEntry(Map.Entry<K, V> original) throws Exception {
            this.fKey = rMarshal(original.getKey());
            this.fValue = rMarshal(original.getValue());
        }

        public K getKey() {
            return this.fKey;
        }

        public V getValue() {
            return this.fValue;
        }

    }

}

This should avoid your NPE.


Need Your Help

Library for photo-booth style effects

image image-processing photos

Are there any good tools or libraries that do image effects similar to Photo Booth on OS X? It doesn't have to be live, just applying the effect to an image would be enough. As a bonus: python bind...

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.