1

I have two Map objects where I merge them into Guava's Multimap. After merging I am trying to serialize the final map by jackson ObjectMapper with GuavaModule (otherwise it doesn't serialize properly). However, the issue is every value of a key is printed as an element of a list even when there is only one value (objectmapper wraps every value with square brackets). The basic output I get is as below,

{
    "address": {
        "city": ["san francisco"]
    },
    "company": {
        "employees": [
            [{
                "name": "David",
                "lastname": "Foobar",
                "age": 22
            }, {
                "name": "Michael",
                "lastname": "FizBuzz",
                "age": 35
            }]
        ]
    },
    "config": {
        "key1": ["value1", "value3"],
        "key2": ["value2"],
        "key4": ["value4"]
    }
}

As you can see "address" -> "city" -> "san francisco" is wrapped with square brackets, also company -> employees is wrapped twice Additionally, I have tried SerializationFeature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED, true future but nothing is changed.

    Person person = new Person();
    person.setName("David");
    person.setLastname("Foobar");
    person.setAge(22);

    Person person2 = new Person();
    person2.setName("Michael");
    person2.setLastname("FizBuzz");
    person2.setAge(35);

    Map<String, Map<String, Object>> map1 = new ImmutableMap.Builder<String, Map<String, Object>>()
            .put("config", ImmutableMap.of(
                    "key1", "value1",
                    "key2", "value2"))
            .put("address", ImmutableMap.of("city", "san francisco"))
            .put("company", ImmutableMap.of("employees", Arrays.asList(person, person2)))
            .build();

    Map<String, Map<String, Object>> map2 = new ImmutableMap.Builder<String, Map<String, Object>>()
            .put("config", ImmutableMap.of(
                    "key1", "value3",
                    "key4", "value4"))
            .build();

    Map<String, Multimap<String, Object>> merged = new HashMap<>();
    BiFunction<Multimap<String, Object>,
                Multimap<String, Object>,
                Multimap<String, Object>> remappingFunction = (value1, value2) -> {
        Multimap<String, Object> multimap = HashMultimap.<String, Object>create();
        multimap.putAll(value1);
        multimap.putAll(value2);
        return multimap;
    };


    map1.forEach((key, value) -> merged.merge(key, Multimaps.forMap(value), remappingFunction));
    map2.forEach((key, value) -> merged.merge(key, Multimaps.forMap(value), remappingFunction));

    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.registerModule(new GuavaModule());
    objectMapper.configure(SerializationFeature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED, true);
    String str = objectMapper.writeValueAsString(merged);
    System.out.print(str);
}

I appreciate for any help. Thanks

quartaela
  • 2,579
  • 16
  • 63
  • 99

1 Answers1

5

According to the Jackson documentation, the MultimapSerializer "encloses all value sets in JSON Array, regardless of number of values". I believe this means it is effectively ignoring the WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED feature.

You can avoid this problem by converting all your inner Multimap<String, Object> instances into standard Map<String, Collection<Object>> instances before serializing. You can do this by using Multimap.asMap():

Map<String, Map<String, Collection<Object>>> newMerged = new HashMap<>();
merged.forEach((key, value) -> newMerged.put(key, value.asMap()));
String newStr = objectMapper.writeValueAsString(newMerged);
System.out.println(newStr);

This prints the output that you are expecting:

{"address":{"city":"san francisco"},"company":{"employees":[{"name":"David","lastname":"Foobar","age":22},{"name":"Michael","lastname":"FizBuzz","age":35}]},"config":{"key1":["value1","value3"],"key2":"value2","key4":"value4"}}
andersschuller
  • 13,509
  • 2
  • 42
  • 33
  • In theory it might be possible to add support for `WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED` (but it is something all serializers have to take care to handle and can not be implemented centrally), but there may be issues if values themselves are something to serialize as JSON Array. Filing an issue for `jackson-dataformat-guava` would make sense. – StaxMan Apr 06 '16 at 23:43