Trabalhando com valores primitivos no Gson

Trabalhando com valores primitivos no Gson

1. Overview

Neste tutorial, vamoslearn how to serialize and deserialize primitive values with Gson. O Google desenvolveu a biblioteca Gson para serializar e desserializar JSON. Além disso, vamos aprender sobre algumas peculiaridades que a biblioteca Gson tem quando se trata de lidar com primitivas.

Por outro lado, se precisarmos trabalhar com matrizes, coleções, objetos aninhados ou outra customização, temos tutoriais adicionais emserializing with Gsonedeserializing with Gson.

2. Dependência do Maven

Para trabalhar com Gson, devemos adicionar a dependênciaGson ao pom:


    com.google.code.gson
    gson
    2.8.5

3. Serializando Tipos Primitivos

Serializar com o Gson é bem direto. Usaremos o seguinte modelo como exemplo:

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

Primeiro, vamos inicializar uma instância com alguns valores de teste:

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

Em seguida, podemos serializá-lo:

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

Finalmente, podemos ver o resultado serializado:

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

Devemos observar alguns detalhes do nosso exemplo. Para iniciantes, o valor do byte não é serializado como uma sequência de bits como no modelo. Além disso, não há distinção entre short, int e long. Além disso, não há distinção entre float e double.

Outra coisa a notar é que uma string representa o valor do caractere.

Na verdade, essas três últimas coisas não têm nada a ver com Gson, mas é a forma como JSON é definido.

3.1. Serializando Valores Especiais de Ponto Flutuante

Java tem constantesFloat.POSITIVE_INFINITYeNEGATIVE_INFINITY para representar o infinito. Gson não pode serializar estes valores especiais:

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

Tentar fazer isso gera umIllegalArgumentException.

Tentar serializarNaN também gera umIllegalArgumentException porque esse valor não é permitido pela especificação JSON.

Pelo mesmo motivo, tentar serializarDouble.POSITIVE_INFINITY, NEGATIVE_INFINITY ouNaN também gera umIllegalArgumentException.

4. Desserializando Tipos Primitivos

Vamos dar uma olhada agora em como desserializaríamos a string JSON obtida no exemplo anterior.

A desserialização é tão fácil quanto a serialização:

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

Por fim, podemos verificar se o modelo contém os valores desejados:

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. Desserializando valores de string

Quando um valor válido é colocado dentro de uma String, o Gson o analisa e lida com ele de maneira esperada:

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

É importante notar que os valores de string não podem ser desserializados em tipos booleanos.

4.2. Desserializando Valores de string vazios

Por outro lado, vamos tentar desserializar o seguinte JSON com strings vazias:

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

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

Isso gera umJsonSyntaxException porque strings vazias não são esperadas ao desserializar primitivos.

4.3. Desserializando Valores Nulos

Tentar desserializar um campo com o valornull fará com que o Gson ignore esse campo. Por exemplo, com a seguinte classe:

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 ignora os campos nulos:

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. Desserializando valores que transbordam

Este é um caso muito interessante que o Gson trata inesperadamente. Tentando desserializar:

{"value": 300}

Com o modelo:

class ByteExample {
    public byte value;
}

Como resultado, o objeto tem um valor de 44. It is handled poorly because in these cases an exception could be raised instead. Isso evitaria a propagação de erros indetectáveis ​​pelo aplicativo.

4.5. Desserializando Números de Ponto Flutuante

A seguir, vamos tentar desserializar o seguinte JSON em um objetoByteExample:

{"value": 2.3}

Gson aqui faz a coisa certa e aumenta aJsonSyntaxException cujo subtipo é aNumberFormatException. Não importa que tipo discreto usamos (byte,short,int orlong), obtemos o mesmo resultado.

Se o valor terminar em ".0", o Gson desserializará o número conforme o esperado.

4.6. Desserializando valores booleanos numéricos

Às vezes, um booleano é codificado como 0 ou 1 em vez de "verdadeiro" ou "falso". Gson não permite isso por padrão. Por exemplo, se tentarmos desserializar:

{"value": 1}

no modelo:

class BooleanExample {
    public boolean value;
}

Gson levanta umJsonSyntaxException com um subtipo de exceção deIllegalStateException. This is in contrast with the NumberFormatException raised when numbers didn’t match. Se quisermos mudar isso, podemos usar umcustom deserializer.

4.7. Desserializando caracteres Unicode

Vale ressaltar que a desserialização de caracteres Unicode não requer configuração extra.

Por exemplo, o JSON:

{"value": "\u00AE"}

Irá resultar no caractere ®.

5. Conclusão

Como vimos, o Gson fornece uma maneira direta de trabalhar com os tipos primitivos JSON e Java. Existem alguns comportamentos inesperados a serem observados, mesmo ao lidar com tipos primitivos simples.

A implementação completa deste artigo pode ser encontrada emthe GitHub project - este é um projeto baseado em Eclipse, portanto, deve ser fácil de importar e executar como está.