Jackson Top

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE

1. Overview

In this tutorial, we’re going to learn how to serialize and deserialize primitive values with Gson. Google developed the Gson library to serialize and deserialize JSON. Additionally, we’re going to learn about some specific quirks that the Gson library has when it comes to dealing with primitives.

On the other hand, if we need to work with arrays, collections, nested objects, or other customization, we have additional tutorials on serializing with Gson and deserializing with Gson.

2. Maven Dependency

To work with Gson, we must add the Gson dependency to the pom:

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

3. Serializing Primitive Types

Serializing with Gson is pretty straightforward. We’ll use the following model as an example:

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

First, let’s initialize an instance with some test values:

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

Next, we can serialize it:

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

Finally, we can see the serialized result:

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

We should note a few details from our example. For starters, the byte value is not serialized as a string of bits like it was in the model. In addition to that, there is no distinction between short, int and long. Also, there is no distinction between float and double.

Another thing to notice is that a string represents the character value.

Actually, these last three things don’t have anything to do with Gson, but it is the way JSON is defined.

3.1. Serializing Special Floating-Point Values

Java has constants Float.POSITIVE_INFINITY and NEGATIVE_INFINITY to represent infinity. Gson can’t serialize these special values:

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

Trying to do so raises an IllegalArgumentException.

Trying to serialize NaN also raises an IllegalArgumentException because this value is not allowed by the JSON specification.

For the same reason, trying to serialize Double.POSITIVE_INFINITY, NEGATIVE_INFINITY, or NaN also throws an IllegalArgumentException.

4. Deserializing Primitive Types

Let’s take a look now at how we would deserialize the JSON string obtained in the previous example.

The deserialization is as easy as the serialization:

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

Finally, we can verify the model contains the desired values:

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. Deserializing String Values

When a valid value is put within a String, Gson parses it and handles it expectedly:

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

It is worth noting that string values can’t be deserialized into boolean types.

4.2. Deserializing Empty String Values

On the other hand, let’s try to deserialize the following JSON with empty strings:

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

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

This raises a JsonSyntaxException because empty strings are not expected when deserializing primitives.

4.3. Deserializing Null Values

Trying to deserialize a field with the value null will result in Gson ignoring that field. For example, with the following class:

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 ignores the null fields:

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. Deserializing Values That Overflow

This is a very interesting case that Gson handles unexpectedly. Trying to deserialize:

{"value": 300}

With the model:

class ByteExample {
    public byte value;
}

As a result, the object has a value of 44. It is handled poorly because in these cases an exception could be raised instead. This would prevent undetectable mistakes propagating through the application.

4.5. Deserializing Floating-Point Numbers

Next, let’s try to deserialize the following JSON into a ByteExample object:

{"value": 2.3}

Gson here does the right thing and raises a JsonSyntaxException whose subtype is a NumberFormatException. It doesn’t matter which discrete type we use (byte, shortint or long), we get the same result.

If the value ends in “.0”, Gson will deserialize the number as expected.

4.6. Deserializing Numeric Boolean Values

Sometimes, a boolean is codified as 0 or 1 instead of “true” or “false”. Gson doesn’t allow this by default. For example, if we try to deserialize:

{"value": 1}

into the model:

class BooleanExample {
    public boolean value;
}

Gson raises a JsonSyntaxException with an exception subtype of IllegalStateException. This is in contrast with the NumberFormatException raised when numbers didn’t match. If we wanted to change that we could use a custom deserializer.

4.7. Deserializing Unicode Characters

It is worth noting that deserialization of Unicode characters requires no extra configuration.

For example, the JSON:

{"value": "\u00AE"}

Will result in the ® character.

5. Conclusion

As we have seen, Gson provides a straightforward way to work with JSON and Java primitive types. There are some unexpected behaviors to be aware of, even when dealing with simple primitive types.

The full implementation of this article can be found in the GitHub project – this is an Eclipse based project, so it should be easy to import and run as it is.

Jackson bottom

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE