In this cookbook, we’re exploring the various ways to unmarshall JSON into Java objects, using the popular Gson library.
1. Deserialize JSON to Single Basic Object
Let’s start simple – we’re going to unmarshall a simple json to a Java object – Foo:
public class Foo {
public int intValue;
public String stringValue;
// + standard equals and hashCode implementations
}
And the solution:
@Test
public void whenDeserializingToSimpleObject_thenCorrect() {
String json = "{"intValue":1,"stringValue":"one"}";
Foo targetObject = new Gson().fromJson(json, Foo.class);
assertEquals(targetObject.intValue, 1);
assertEquals(targetObject.stringValue, "one");
}
2. Deserialize JSON to Generic Object
Next – let’s define an object using generics:
public class GenericFoo<T> {
public T theValue;
}
And unmarshall some json into this type of object:
@Test
public void whenDeserializingToGenericObject_thenCorrect() {
Type typeToken = new TypeToken<GenericFoo<Integer>>() { }.getType();
String json = "{"theValue":1}";
GenericFoo<Integer> targetObject = new Gson().fromJson(json, typeToken);
assertEquals(targetObject.theValue, new Integer(1));
}
3. Deserialize JSON With Extra Unknown Fields to Object
Next – let’s deserialize some complex json that contains additional, unknown fields:
@Test
public void givenJsonHasExtraValues_whenDeserializing_thenCorrect() {
String json =
"{"intValue":1,"stringValue":"one","extraString":"two","extraFloat":2.2}";
Foo targetObject = new Gson().fromJson(json, Foo.class);
assertEquals(targetObject.intValue, 1);
assertEquals(targetObject.stringValue, "one");
}
As you can see, Gson will ignore the unknown fields and simply match the fields that it’s able to.
4. Deserialize JSON With Non-Matching Field Names to Object
Now, let’s see how Gson does with a json string containing fields that simply don’t match the fields of our Foo object:
@Test
public void givenJsonHasNonMatchingFields_whenDeserializingWithCustomDeserializer_thenCorrect() {
String json = "{"valueInt":7,"valueString":"seven"}";
GsonBuilder gsonBldr = new GsonBuilder();
gsonBldr.registerTypeAdapter(Foo.class, new FooDeserializerFromJsonWithDifferentFields());
Foo targetObject = gsonBldr.create().fromJson(json, Foo.class);
assertEquals(targetObject.intValue, 7);
assertEquals(targetObject.stringValue, "seven");
}
Notice that we registered a custom deserializer – this was able to correctly parse out the fields from the json string and map them to our Foo:
public class FooDeserializerFromJsonWithDifferentFields implements JsonDeserializer<Foo> {
@Override
public Foo deserialize
(JsonElement jElement, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
JsonObject jObject = jElement.getAsJsonObject();
int intValue = jObject.get("valueInt").getAsInt();
String stringValue = jObject.get("valueString").getAsString();
return new Foo(intValue, stringValue);
}
}
5. Deserialize JSON Array to Java Array of Objects
Next, we’re going to deserialize a json array into a Java array of Foo objects:
@Test
public void givenJsonArrayOfFoos_whenDeserializingToArray_thenCorrect() {
String json = "[{"intValue":1,"stringValue":"one"}," +
"{"intValue":2,"stringValue":"two"}]";
Foo[] targetArray = new GsonBuilder().create().fromJson(json, Foo[].class);
assertThat(Lists.newArrayList(targetArray), hasItem(new Foo(1, "one")));
assertThat(Lists.newArrayList(targetArray), hasItem(new Foo(2, "two")));
assertThat(Lists.newArrayList(targetArray), not(hasItem(new Foo(1, "two"))));
}
6. Deserialize JSON Array to Java Collection
Next, a json array directly into a Java Collection:
@Test
public void givenJsonArrayOfFoos_whenDeserializingCollection_thenCorrect() {
String json =
"[{"intValue":1,"stringValue":"one"},{"intValue":2,"stringValue":"two"}]";
Type targetClassType = new TypeToken<ArrayList<Foo>>() { }.getType();
Collection<Foo> targetCollection = new Gson().fromJson(json, targetClassType);
assertThat(targetCollection, instanceOf(ArrayList.class));
}
7. Deserialize JSON to Nested Objects
Next, let’s define our nested object – FooWithInner:
public class FooWithInner {
public int intValue;
public String stringValue;
public InnerFoo innerFoo;
public class InnerFoo {
public String name;
}
}
And here is how to deserialize an input containing this nested object:
@Test
public void whenDeserializingToNestedObjects_thenCorrect() {
String json = "{\"intValue\":1,\"stringValue\":\"one\",\"innerFoo\":{\"name\":\"inner\"}}";
FooWithInner targetObject = new Gson().fromJson(json, FooWithInner.class);
assertEquals(targetObject.intValue, 1);
assertEquals(targetObject.stringValue, "one");
assertEquals(targetObject.innerFoo.name, "inner");
}
8. Deserialize JSON Using Custom Constructor
Finally, let’s see how to force using a specific constructor during deserializations instead of default – no arguments constructor – using InstanceCreator:
public class FooInstanceCreator implements InstanceCreator<Foo> {
@Override
public Foo createInstance(Type type) {
return new Foo("sample");
}
}
And here is how to use our FooInstanceCreator in deserialization:
@Test
public void whenDeserializingUsingInstanceCreator_thenCorrect() {
String json = "{\"intValue\":1}";
GsonBuilder gsonBldr = new GsonBuilder();
gsonBldr.registerTypeAdapter(Foo.class, new FooInstanceCreator());
Foo targetObject = gsonBldr.create().fromJson(json, Foo.class);
assertEquals(targetObject.intValue, 1);
assertEquals(targetObject.stringValue, "sample");
}
Note that instead of null, the Foo.stringValue equals sample as we used the following constructor:
public Foo(String stringValue) {
this.stringValue = stringValue;
}
9. Conclusion
This articles shows how to leverage the Gson library to parse JSON input – going over the most common usecases for both single and multiple objects.
The implementation of all these examples and code snippets can be found in my github project – this is an Eclipse based project, so it should be easy to import and run as it is.