Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert Guava HashMultimap to json

I want to print HashMultiMap as json.

HashMultimap<String,Object> multimap = HashMultimap.create();
multimap.put("a",Obj1);
multimap.put("a",Obj3);
multimap.put("b",Obj2);

to

{ 
  "a":[Obj1,Obj3],
  "b":[Obj2]
}

Obj1 and other objects should again be in json(to keep it clean, I have shown it as objects)
I can iterate over the individual keys and convert set of Objects to json using libraries such as Gson.

But to get the entire snapshot of the HashMultimap, I want to convert it to json and inspect it.

Gson could not convert the entire map, but could do individual values(list of objects to json)

like image 500
sat Avatar asked Sep 04 '14 19:09

sat


2 Answers

Call asMap() on the MultiMap first. This converts the MultiMap to a standard Map where each value is a Collection.

In your example, the type of the resulting Map is Map<String, Collection<Object>>. Gson should be able to serialise this correctly.

like image 153
Wesley Avatar answered Oct 19 '22 10:10

Wesley


You need to write a JsonAdapter or both JsonDeserializer and JsonSerializer. It's rather terrible, but I wanted to try.

Basically, you delegate everything to a Map<String, Collection<V>>.

static class MultimapAdapter implements JsonDeserializer<Multimap<String, ?>>, JsonSerializer<Multimap<String, ?>> {
    @Override public Multimap<String, ?> deserialize(JsonElement json, Type type,
            JsonDeserializationContext context) throws JsonParseException {
        final HashMultimap<String, Object> result = HashMultimap.create();
        final Map<String, Collection<?>> map = context.deserialize(json, multimapTypeToMapType(type));
        for (final Map.Entry<String, ?> e : map.entrySet()) {
            final Collection<?> value = (Collection<?>) e.getValue();
            result.putAll(e.getKey(), value);
        }
        return result;
    }

    @Override public JsonElement serialize(Multimap<String, ?> src, Type type, JsonSerializationContext context) {
        final Map<?, ?> map = src.asMap();
        return context.serialize(map);
    }

    private <V> Type multimapTypeToMapType(Type type) {
        final Type[] typeArguments = ((ParameterizedType) type).getActualTypeArguments();
        assert typeArguments.length == 2;
        @SuppressWarnings("unchecked")
        final TypeToken<Map<String, Collection<V>>> mapTypeToken = new TypeToken<Map<String, Collection<V>>>() {}
        .where(new TypeParameter<V>() {}, (TypeToken<V>) TypeToken.of(typeArguments[1]));
        return mapTypeToken.getType();
    }
}

The full code including a test can be found here.

like image 31
maaartinus Avatar answered Oct 19 '22 11:10

maaartinus