«1. Обзор

В этом уроке мы узнаем, как сериализовать и десериализовать примитивные значения с помощью Gson. Google разработала библиотеку Gson для сериализации и десериализации JSON. Кроме того, мы узнаем о некоторых особенностях библиотеки Gson при работе с примитивами.

С другой стороны, если нам нужно работать с массивами, коллекциями, вложенными объектами или другими настройками, у нас есть дополнительные руководства по сериализации с помощью Gson и десериализации с помощью Gson.

2. Зависимость от Maven

Для работы с Gson мы должны добавить зависимость от Gson к pom:

<dependency> 
    <groupId>com.google.code.gson</groupId> 
    <artifactId>gson</artifactId> 
    <version>2.8.5</version> 
</dependency>

3. Сериализация примитивных типов

Сериализация с Gson довольно проста. В качестве примера мы будем использовать следующую модель:

public class PrimitiveBundle {
    public byte byteValue;
    public short shortValue;
    public int intValue;
    public long longValue;
    public float floatValue;
    public double doubleValue;
    public boolean booleanValue;
    public char charValue;
}

Сначала давайте инициализируем экземпляр с некоторыми тестовыми значениями:

PrimitiveBundle primitiveBundle = new PrimitiveBundle();
primitiveBundle.byteValue = (byte) 0x00001111;
primitiveBundle.shortValue = (short) 3;
primitiveBundle.intValue = 3;
primitiveBundle.longValue = 3;
primitiveBundle.floatValue = 3.5f;
primitiveBundle.doubleValue = 3.5;
primitiveBundle.booleanValue = true;
primitiveBundle.charValue = 'a';

Затем мы можем его сериализовать:

Gson gson = new Gson();
String json = gson.toJson(primitiveBundle);

Наконец, мы можно увидеть сериализованный результат:

{  
   "byteValue":17,
   "shortValue":3,
   "intValue":3,
   "longValue":3,
   "floatValue":3.5,
   "doubleValue":3.5,
   "booleanValue":true,
   "charValue":"a"
}

Следует отметить несколько деталей из нашего примера. Во-первых, значение байта не сериализуется в виде строки битов, как это было в модели. Вдобавок к этому нет разницы между short, int и long. Кроме того, нет различия между float и double.

Еще одна вещь, на которую следует обратить внимание, это то, что строка представляет символьное значение.

На самом деле эти последние три вещи не имеют ничего общего с Gson, но именно так определяется JSON.

3.1. Сериализация специальных значений с плавающей запятой

В Java есть константы Float.POSITIVE_INFINITY и NEGATIVE_INFINITY для представления бесконечности. Gson не может сериализовать эти специальные значения:

public class InfinityValuesExample {
    public float negativeInfinity;
    public float positiveInfinity;
}
InfinityValuesExample model = new InfinityValuesExample();
model.negativeInfinity = Float.NEGATIVE_INFINITY;
model.positiveInfinity = Float.POSITIVE_INFINITY;

Gson gson = new Gson();
gson.toJson(model);

Попытка сделать это вызывает исключение IllegalArgumentException.

Попытка сериализовать NaN также вызывает исключение IllegalArgumentException, поскольку это значение не разрешено спецификацией JSON.

По той же причине при попытке сериализации Double.POSITIVE_INFINITY, NEGATIVE_INFINITY или NaN также возникает исключение IllegalArgumentException.

4. Десериализация примитивных типов

Давайте теперь посмотрим, как бы мы десериализовали строку JSON, полученную в предыдущем примере.

Gson gson = new Gson();
PrimitiveBundle model = gson.fromJson(json, PrimitiveBundle.class);

Десериализация так же проста, как и сериализация:

assertEquals(17, model.byteValue);
assertEquals(3, model.shortValue);
assertEquals(3, model.intValue);
assertEquals(3, model.longValue);
assertEquals(3.5, model.floatValue, 0.0001);
assertEquals(3.5, model.doubleValue, 0.0001);
assertTrue(model.booleanValue);
assertEquals('a', model.charValue);

Наконец, мы можем убедиться, что модель содержит нужные значения:

4.1. Десериализация строковых значений

String json = "{\"byteValue\": \"15\", \"shortValue\": \"15\", "
  + "\"intValue\": \"15\", \"longValue\": \"15\", \"floatValue\": \"15.0\""
  + ", \"doubleValue\": \"15.0\"}";

Gson gson = new Gson();
PrimitiveBundleInitialized model = gson.fromJson(json, PrimitiveBundleInitialized.class);
assertEquals(15, model.byteValue);
assertEquals(15, model.shortValue);
assertEquals(15, model.intValue);
assertEquals(15, model.longValue);
assertEquals(15, model.floatValue, 0.0001);
assertEquals(15, model.doubleValue, 0.0001);

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

Стоит отметить, что строковые значения не могут быть десериализованы в логические типы.

String json = "{\"byteValue\": \"\", \"shortValue\": \"\", "
  + "\"intValue\": \"\", \"longValue\": \"\", \"floatValue\": \"\""
  + ", \"doubleValue\": \"\"}";

Gson gson = new Gson();
gson.fromJson(json, PrimitiveBundleInitialized.class);

4.2. Десериализация пустых строковых значений

С другой стороны, давайте попробуем десериализовать следующий JSON с пустыми строками:

Это вызовет исключение JsonSyntaxException, поскольку при десериализации примитивов пустые строки не ожидаются.

public class PrimitiveBundleInitialized {
    public byte byteValue = (byte) 1;
    public short shortValue = (short) 1;
    public int intValue = 1;
    public long longValue = 1L;
    public float floatValue = 1.0f;
    public double doubleValue = 1;
}

4.3. Десериализация пустых значений

String json = "{\"byteValue\": null, \"shortValue\": null, "
  + "\"intValue\": null, \"longValue\": null, \"floatValue\": null"
  + ", \"doubleValue\": null}";

Gson gson = new Gson();
PrimitiveBundleInitialized model = gson.fromJson(json, PrimitiveBundleInitialized.class);

assertEquals(1, model.byteValue);
assertEquals(1, model.shortValue);
assertEquals(1, model.intValue);
assertEquals(1, model.longValue);
assertEquals(1, model.floatValue, 0.0001);
assertEquals(1, model.doubleValue, 0.0001);

Попытка десериализовать поле со значением null приведет к тому, что Gson проигнорирует это поле. Например, для следующего класса:

Gson игнорирует пустые поля:

{"value": 300}

4.4. Десериализация значений, которые переполняются

class ByteExample {
    public byte value;
}

Это очень интересный случай, с которым Gson неожиданно справляется. Попытка десериализации:

С моделью:

В результате объект имеет значение 44. Он обрабатывается плохо, потому что в этих случаях вместо этого может быть возбуждено исключение. Это предотвратит распространение необнаруженных ошибок в приложении.

{"value": 2.3}

4.5. Десериализация чисел с плавающей запятой

Далее попробуем десериализовать следующий JSON в объект ByteExample:

Здесь Gson поступает правильно и создает исключение JsonSyntaxException, подтипом которого является NumberFormatException. Неважно, какой дискретный тип мы используем (byte, short, int или long), мы получаем один и тот же результат.

Если значение заканчивается на «.0», Gson десериализует число, как и ожидалось.

{"value": 1}

4.6. Десериализация числовых логических значений

class BooleanExample {
    public boolean value;
}

Иногда логическое значение кодируется как 0 или 1 вместо «истина» или «ложь». Gson не разрешает это по умолчанию. Например, если мы попытаемся десериализовать:

в модель:

«

«Gson вызывает JsonSyntaxException с подтипом исключения IllegalStateException. Это отличается от исключения NumberFormatException, возникающего, когда числа не совпадают. Если бы мы хотели изменить это, мы могли бы использовать собственный десериализатор.

{"value": "\u00AE"}

4.7. Десериализация символов Unicode

Стоит отметить, что десериализация символов Unicode не требует дополнительной настройки.

Например, JSON:

приведет к символу ®.