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. Десериализация строковых значений
Когда допустимое значение помещается в строку, 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. Он плохо обрабатывается, поскольку в этих случаях вместо этого может быть возбуждено исключение. Это предотвратит распространение необнаруженных ошибок в приложении.
4.5. Десериализация чисел с плавающей запятой
Далее попробуем десериализовать следующий JSON в объект ByteExample
:
{"value": 2.3}
Здесь Gson поступает правильно и вызывает JsonSyntaxException
, подтипом которого является NumberFormatException
. Неважно, какой дискретный тип мы используем ( byte
, short
, int
или long
), мы получаем один и тот же результат.
Если значение заканчивается на «.0», Gson десериализует число, как и ожидалось.
4.6. Десериализация числовых логических значений
Иногда логическое значение кодируется как 0 или 1 вместо «истина» или «ложь». Gson не разрешает это по умолчанию. Например, если мы попытаемся десериализовать:
{"value": 1}
в модель:
class BooleanExample {
public boolean value;
}
Gson вызывает JsonSyntaxException
с подтипом исключения IllegalStateException
. Это отличается от исключения NumberFormatException,
возникающего, когда числа не совпадают . Если бы мы хотели изменить это, мы могли бы использовать собственный десериализатор .
4.7. Десериализация символов Unicode
Стоит отметить, что десериализация символов Unicode не требует дополнительной настройки.
Например, JSON:
{"value": "\u00AE"}
Приведет к символу ®.
5. Вывод
Как мы видели, Gson предоставляет простой способ работы с примитивными типами JSON и Java. Есть некоторые неожиданные особенности поведения, о которых следует знать, даже при работе с простыми примитивными типами.
Полную реализацию этой статьи можно найти в проекте GitHub — это проект на основе Eclipse, поэтому его легко импортировать и запускать как есть.