Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jackson JSON - Deserialize Commons MultiMap

i want to serialize and deserialize a MultiMap (Apache Commons 4) using JSON.

Piece of code to test:

MultiMap<String, String> map = new MultiValueMap<>();
map.put("Key 1", "Val 11");
map.put("Key 1", "Val 12");
map.put("Key 2", "Val 21");
map.put("Key 2", "Val 22");

ObjectMapper mapper = new ObjectMapper();
String jsonString = mapper.writeValueAsString(map);
MultiMap<String, String> deserializedMap = mapper.readValue(jsonString, MultiValueMap.class);

The serialization works fine and results in a format I would expect:

{"Key 1":["Val 11","Val 12"],"Key 2":["Val 21","Val 22"]}

Unfortunately the deserialization produces a result that is not the way it should look like: After the deserialization, the Multimap contains an ArrayList inside an ArrayList for the values of a key, not an single ArrayList for the key containing the values.

This result is produced due to the fact that the put() method of the multi map is called to add the array found in the json string, as the MultiMap implements the Map interface.

The MultiMap implementation itself again then creates an ArrayList if a new value is put to a non existing key.

Is there any way to circumvent this?

Thank you for your help!

like image 948
JDC Avatar asked Apr 13 '15 11:04

JDC


People also ask

How to serialize a map<string> to JSON in Jackson?

For a simple case, let's create a Map<String, String> and serialize it to JSON: Map<String, String> map = new HashMap<> (); map.put ( "key", "value" ); ObjectMapper mapper = new ObjectMapper (); String jsonResult = mapper.writerWithDefaultPrettyPrinter () .writeValueAsString (map); ObjectMapper is Jackson's serialization mapper.

How does the Jackson deserializer work with JSON?

As you can see, the deserializer is working with the standard Jackson representation of JSON – the JsonNode. Once the input JSON is represented as a JsonNode, we can now extract the relevant information from it and construct our own Item entity.

How do I deserialize a map into a Java class?

There is another option when we deserialize into a Java class that contains a Map; we can use Jackson's KeyDeserializer class, one of the many Deserialization classes that Jackson offers. Let's annotate our ClassWithAMap with @JsonCreator, @JsonProperty, and @JsonDeserialize:

How do I serialize mypair to JSON in Jackson?

JsonSerializer, as the name suggests, serializes MyPair to JSON using MyPair ‘s toString () method. Furthermore, Jackson provides many Serializer classes to fit our serialization requirements.


1 Answers

Being assured from Oxford dictionary that circumvent means to "find a way around (an obstacle)", here is a simple work around.

First I created a method that generate the same MultiValueMap as yours above. And I use the same approach to parse it as a json string.

I then created the following deserialization method

public static MultiMap<String,String> doDeserialization(String serializedString) throws JsonParseException, JsonMappingException, IOException {

    ObjectMapper mapper = new ObjectMapper();
    Class<MultiValueMap> classz = MultiValueMap.class;
    MultiMap map = mapper.readValue(serializedString, classz);
    return (MultiMap<String, String>) map;


}

Of course this alone falls in the exact issue you mentionned above, therefore I created the doDeserializationAndFormatmethod: it will iterate through each "list inside a list" correponding to a given key and associate one by one the values to the key

public static MultiMap<String, String> doDeserializationAndFormat(String serializedString) throws JsonParseException, JsonMappingException, IOException {
    MultiMap<String, String> source = doDeserialization(serializedString);
    MultiMap<String, String> result  =  new MultiValueMap<String,String>();
    for (String key: source.keySet()) {


        List allValues = (List)source.get(key);
        Iterator iter = allValues.iterator();

        while (iter.hasNext()) {
            List<String> datas = (List<String>)iter.next();

            for (String s: datas) {
                result.put(key, s);
            }
        }

    }

    return result;

}

Here is a simple call in a main method:

MultiValueMap<String,String> userParsedMap = (MultiValueMap)doDeserializationAndFormat(stackMapSerialized);
System.out.println("Key 1 = " + userParsedMap.get("Key 1") );
System.out.println("Key 2 = " + userParsedMap.get("Key 2") );

json to multivaluemap

Hope this helps.

like image 59
alainlompo Avatar answered Sep 19 '22 01:09

alainlompo