Skip to content

Instantly share code, notes, and snippets.

@VallaDanger
Last active April 21, 2016 04:31
Show Gist options
  • Save VallaDanger/268bd0e7c5e5d5ee7ea78f130f7b8259 to your computer and use it in GitHub Desktop.
Save VallaDanger/268bd0e7c5e5d5ee7ea78f130f7b8259 to your computer and use it in GitHub Desktop.
GSON JsonArray to Guava ImmutableList
public static void main(String[] args) {
Type type = getCollectionType(ImmutableList.class, Number.class);
Gson gson = new GsonBuilder().registerTypeAdapter(type, new ImmutableList_TypeAdapter<Number>()).create();
ImmutableList<Number> list = gson.fromJson("[1,2,3]", type);
ListVO vo = gson.fromJson("{\"numbers\":[1,2,3]}", ListVO.class);
}
private static class ListVO {
@Expose @SerializedName("numbers")
ImmutableList<Number> numbers;
public ImmutableList<Number> getNumbers() {
return this.numbers;
}
}
private static <V, C extends Collection<V>> Type getCollectionType(Class<C> collectionType, Class<V> elementsType) {
return new TypeToken<Collection<V>>() {}
.where(new TypeParameter<V>() {}, elementsType)
.getSubtype(collectionType).getType();
}
private static class ImmutableList_TypeAdapter implements JsonDeserializer<ImmutableList<Number>> {
public ImmutableList<Number> deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext context) throws JsonParseException {
if(!jsonElement.isJsonArray()) {
return ImmutableList.of();
}
ImmutableList.Builder<Number> list = ImmutableList.builder();
for(JsonElement element : jsonElement.getAsJsonArray()) {
JsonPrimitive primitive;
if(element.isJsonPrimitive() && (primitive = element.getAsJsonPrimitive()).isNumber()) {
list.add(primitive.getAsNumber());
}
}
return list.build();
}
}
@VallaDanger
Copy link
Author

very simple example on how to deserialize a GSON's JsonArray into a Guava ImmutableList, it could be easily modified to support any type of instance that implements java.util.Collection (such as ImmutableList > List > Collection).

Guava code makes use of static factories to create instances which effectively hides implementations from the user (interface driven APIs, constructors always create instances of a type but methods can create and return instances of any subtype). Guava's ImmutableList is no exception to the rule and so it is non instantiable (abstract class) and GSON has no default adapter for such type, in fact if you attempt to deserialize a JSON array into an ImmutableList (even when it implements java.util.List, also non instantiable but effectively managed by GSON) you get an InstantiationException (unchecked exception).

An instance of ImmutableList is easy to create by calling ImmutableList#copyOf, but if you know in advance that your object is never going to change, why create defensive copies every time when you can simply deserialize into one.

In this example you'd only need a TypeAdapter, but what if you wanted another implementation or what if you need an instance of ImmutableList<MyVeryOwnObject> without having to create an annotated object to hold it and you'd also want to implement some sort of type safety, etc... That's why I also provided a way to define a method to get a Type for a Collection to inform GSON exactly what it is working with.

While this is a very simple example, an experienced developer can make use of the polymorphic characteristics of the language to make it as robust as you may need. Think of a CollectionTypeFactory using guice AssistedInject.

remember do not abuse of conditionals !!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment