Работа с примитивными значениями в Gson

Работа с примитивными значениями в Gson

1. Overviewс

В этом руководстве мы собираемсяlearn how to serialize and deserialize primitive values with Gson., чтобы Google разработал библиотеку Gson для сериализации и десериализации JSON. Кроме того, мы собираемся узнать о некоторых особенностях библиотеки Gson, когда дело доходит до работы с примитивами.

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

2. Maven Dependency

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


    com.google.code.gson
    gson
    2.8.5

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. Десериализация строковых значений

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

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);

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

4.2. десериализации Пустые строковые значения

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

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

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

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

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

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

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;
}

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

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);

4.4. Десериализация переполняющихся значений

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

{"value": 300}

С моделью:

class ByteExample {
    public byte value;
}

В результате объект имеет значение 44. It is handled poorly because in these cases an exception could be raised instead. Это предотвратит распространение необнаруживаемых ошибок в приложении.

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

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

{"value": 2.3}

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

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

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

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

{"value": 1}

в модель:

class BooleanExample {
    public boolean value;
}

Gson вызываетJsonSyntaxException с подтипом исключенияIllegalStateException. This is in contrast with the NumberFormatException raised when numbers didn’t match. Если бы мы хотели изменить это, мы могли бы использоватьcustom deserializer.

4.7. Десериализация символов Юникода

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

Например, JSON:

{"value": "\u00AE"}

Результатом будет символ ®.

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

Как мы уже видели, Gson предоставляет простой способ работы с примитивными типами JSON и Java. Есть некоторые неожиданные поведения, о которых нужно знать, даже когда имеешь дело с простыми примитивными типами.

Полную реализацию этой статьи можно найти вthe GitHub project - это проект на основе Eclipse, поэтому его будет легко импортировать и запускать как есть.