Search code examples
javajaxbjaxb2

JAXB java.util.Map binding


I have a Json response which looks like the following:

{
    "data": [
        {
            "param1": "value1",
            "param2": "value2",
                    .
                    .
                    .
            "paramN": "valueN"
        }
    ]
}

I don't know the name and the number of the parameters. So, I need and want to bind all these parameters to a java.util.Map field consisting of <"paramX", "valueX"> tuples. To do this, I tried the following code but "parametersMap" field returns null.

@XmlRootElement(name="data")
@XmlAccessorType(XmlAccessType.FIELD)
public class Parameters {
    @XmlElement
    private Map<String,String> parametersMap;

    // Getter and setter for parametersMap
}

How can I achieve such a binding with JAXB annotations?

Thanks in advance.


Solution

  • Basically you need an xml adapter. You can fiddle with the names on the KeyValue class to get the specific output you desire.

    Parameter.java

    import javax.xml.bind.annotation.XmlAccessType;
    import javax.xml.bind.annotation.XmlAccessorType;
    import javax.xml.bind.annotation.XmlRootElement;
    import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
    import java.util.Map;
    
    @XmlRootElement(name = "data")
    @XmlAccessorType(XmlAccessType.FIELD)
    public class Parameters {
    
        @XmlJavaTypeAdapter(value = Adapter.class)
        private Map<String, String> parametersMap;
    
        // Getter and setter for parametersMap
    }
    

    Adapter.java

    import javax.xml.bind.annotation.adapters.XmlAdapter;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    
    public class Adapter extends XmlAdapter<List<KeyValue>, Map<String, String>> {
    
        @Override
        public Map<String, String> unmarshal(List<KeyValue> v) throws Exception {
            Map<String, String> map = new HashMap<>(v.size());
            for (KeyValue keyValue : v) {
                map.put(keyValue.key, keyValue.value);
            }
            return map;
        }
    
        @Override
        public List<KeyValue> marshal(Map<String, String> v) throws Exception {
            Set<String> keys = v.keySet();
            List<KeyValue> results = new ArrayList<>(v.size());
            for (String key : keys) {
                results.add(new KeyValue(key, v.get(key)));
            }
            return results;
        }
    }
    

    KeyValue.java Put better JAXB tags here, obviously.

    import javax.xml.bind.annotation.XmlType;
    
    @XmlType
    public class KeyValue {
        public KeyValue() {
        }
    
        public KeyValue(String key, String value) {
            this.key = key;
            this.value = value;
        }
    
        //obviously needs setters/getters
        String key;
        String value;
    }