Skip to content

Instantly share code, notes, and snippets.

@jingyuyao
Created May 21, 2017 00:59
Show Gist options
  • Save jingyuyao/3030571e9051142c3a7ec498435a0c3c to your computer and use it in GitHub Desktop.
Save jingyuyao/3030571e9051142c3a7ec498435a0c3c to your computer and use it in GitHub Desktop.
Gson serializer/deserializer for ListMultimap from Guava
package com.jingyuyao.adapters;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap;
import com.google.common.reflect.TypeToken;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Map;
/**
* Serialize and deserialize {@link ListMultimap}.
* <br/>
* References:
* <br/>
* - http://stackoverflow.com/a/17300227
* <br/>
* - https://gist.github.com/alex-rnv/1541945a4ee243390ff5
*/
class ListMultimapAdapter
implements JsonSerializer<ListMultimap>, JsonDeserializer<ListMultimap> {
private static final Type asMapReturnType = getAsMapMethod().getGenericReturnType();
private static Type asMapType(Type multimapType) {
return TypeToken.of(multimapType).resolveType(asMapReturnType).getType();
}
private static Method getAsMapMethod() {
try {
return ListMultimap.class.getDeclaredMethod("asMap");
} catch (NoSuchMethodException e) {
throw new AssertionError(e);
}
}
@Override
public JsonElement serialize(
ListMultimap src, Type typeOfSrc, JsonSerializationContext context) {
return context.serialize(src.asMap(), asMapType(typeOfSrc));
}
@Override
public ListMultimap deserialize(
JsonElement json, Type typeOfT,
JsonDeserializationContext context)
throws JsonParseException {
Map<Object, Collection<Object>> asMap = context.deserialize(json, asMapType(typeOfT));
ListMultimap<Object, Object> listMultimap = ArrayListMultimap.create();
for (Map.Entry<Object, Collection<Object>> entry : asMap.entrySet()) {
listMultimap.putAll(entry.getKey(), entry.getValue());
}
return listMultimap;
}
}
package com.jingyuyao.adapters;
import static com.google.common.truth.Truth.assertThat;
import com.google.common.base.Objects;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ListMultimap;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@RunWith(JUnit4.class)
public class ListMultimapAdapterTest {
private static final String JSON = "[[{\"k\":\"key\"},[{\"v\":\"value\"}]]]";
private Gson gson;
@Before
public void setUp() {
gson = new GsonBuilder()
.enableComplexMapKeySerialization()
.registerTypeAdapter(ListMultimap.class, new ListMultimapAdapter())
.create();
}
@Test
public void serialize() {
ListMultimap<Key, Value> listMultimap = ArrayListMultimap.create();
listMultimap.put(new Key(), new Value());
String json = gson.toJson(listMultimap, new TypeToken<ListMultimap<Key, Value>>() {
}.getType());
assertThat(json).isEqualTo(JSON);
}
@Test
public void deserialize() {
ListMultimap<Key, Value> listMultimap = gson
.fromJson(JSON, new TypeToken<ListMultimap<Key, Value>>() {
}.getType());
assertThat(listMultimap).containsEntry(new Key(), new Value());
}
@Test
public void serialize_deserialize() {
ListMultimap<Key, Value> listMultimap = ArrayListMultimap.create();
listMultimap.put(new Key(), new Value());
String serialized = gson.toJson(listMultimap, new TypeToken<ListMultimap<Key, Value>>() {
}.getType());
ListMultimap<Key, Value> deserialized = gson
.fromJson(serialized, new TypeToken<ListMultimap<Key, Value>>() {
}.getType());
assertThat(listMultimap).isEqualTo(deserialized);
String serializedAgain = gson.toJson(deserialized, new TypeToken<ListMultimap<Key, Value>>() {
}.getType());
assertThat(serialized).isEqualTo(serializedAgain);
}
@Test
public void with_container() {
Container container = new Container();
String json = gson.toJson(container);
Container deserialized = gson.fromJson(json, Container.class);
assertThat(container.map).isEqualTo(deserialized.map);
}
private static class Container {
private ListMultimap<Key, Value> map = ImmutableListMultimap.of(new Key(), new Value());
}
private static class Key {
private String k = "key";
@Override
public boolean equals(Object object) {
if (this == object) {
return true;
}
if (object == null || getClass() != object.getClass()) {
return false;
}
Key key = (Key) object;
return Objects.equal(k, key.k);
}
@Override
public int hashCode() {
return Objects.hashCode(k);
}
}
private static class Value {
private String v = "value";
@Override
public boolean equals(Object object) {
if (this == object) {
return true;
}
if (object == null || getClass() != object.getClass()) {
return false;
}
Value value = (Value) object;
return Objects.equal(v, value.v);
}
@Override
public int hashCode() {
return Objects.hashCode(v);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment