Перейти к основному содержимому

Поваренная книга десериализации Gson

· 4 мин. чтения

В этой кулинарной книге мы изучаем различные способы преобразования JSON в объекты Java с использованием популярной библиотеки Gson .

1. Десериализовать JSON в один базовый объект

Начнем с простого — мы собираемся преобразовать простой json в объект Java — Foo :

public class Foo {
public int intValue;
public String stringValue;

// + standard equals and hashCode implementations
}

И решение:

@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. Десериализовать JSON в общий объект

Далее — давайте определим объект с помощью дженериков:

public class GenericFoo<T> {
public T theValue;
}

И разместите некоторый json в объекте такого типа:

@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. Десериализуйте JSON с дополнительными неизвестными полями для объекта

Далее — давайте десериализуем какой-нибудь сложный json, содержащий дополнительные неизвестные поля :

@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");
}

Как видите, Gson игнорирует неизвестные поля и просто сопоставляет поля, которые может.

4. Десериализуйте JSON с несовпадающими именами полей в объект

Теперь давайте посмотрим, как Gson справляется со строкой json, содержащей поля, которые просто не соответствуют полям нашего объекта Foo :

@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");
}

Обратите внимание, что мы зарегистрировали пользовательский десериализатор — он смог правильно проанализировать поля из строки json и сопоставить их с нашим 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. Десериализовать массив JSON в массив объектов Java

Далее мы собираемся десериализовать массив json в массив Java объектов Foo :

@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. Десериализовать массив JSON в коллекцию Java

Затем массив json прямо в коллекцию Java :

@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. Десериализуйте JSON во вложенные объекты

Далее давайте определим наш вложенный объект — FooWithInner :

public class FooWithInner {
public int intValue;
public String stringValue;
public InnerFoo innerFoo;

public class InnerFoo {
public String name;
}
}

А вот как десериализовать ввод, содержащий этот вложенный объект:

@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. Десериализуйте JSON с помощью пользовательского конструктора

Наконец, давайте посмотрим, как принудительно использовать определенный конструктор во время десериализации вместо конструктора по умолчанию — без аргументов — с помощью InstanceCreator :

public class FooInstanceCreator implements InstanceCreator<Foo> {

@Override
public Foo createInstance(Type type) {
return new Foo("sample");
}
}

А вот как использовать наш FooInstanceCreator в десериализации:

@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");
}

Обратите внимание, что вместо null Foo.stringValue равняется образцу , поскольку мы использовали следующий конструктор:

public Foo(String stringValue) {
this.stringValue = stringValue;
}

9. Заключение

В этой статье показано, как использовать библиотеку Gson для анализа входных данных JSON , рассматривая наиболее распространенные варианты использования как для одного, так и для нескольких объектов.

Реализацию всех этих примеров и фрагментов кода можно найти в моем проекте на github — это проект на основе Eclipse, поэтому его легко импортировать и запускать как есть.