14

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.

zb226
  • 9,586
  • 6
  • 49
  • 79
ovunccetin
  • 8,443
  • 5
  • 42
  • 53

1 Answers1

8

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;
}
marathon
  • 7,881
  • 17
  • 74
  • 137
  • I get `com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions` for `Parameters.java` at the line where the `Map` is declared. – koppor Feb 09 '17 at 08:43
  • 1
    The answer https://www.tomasmalmsten.com/2012/05/unmarshall-marshall-java-maps-xml-jaxb/ wraps `List` in another helper class. This prevents that `IllegalAnnotationsException`. – koppor Feb 09 '17 at 09:03