Created
May 21, 2017 00:59
-
-
Save jingyuyao/3030571e9051142c3a7ec498435a0c3c to your computer and use it in GitHub Desktop.
Gson serializer/deserializer for ListMultimap from Guava
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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