Course – LS (cat=JSON/Jackson)

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE

1. Introduction

The Jackson Library is a de facto standard in the Java world when it comes to processing JSON. Despite Jackson’s well-defined defaults, for mapping a Boolean value to Integer, we still need to do manual configurations.

Certainly, some developers wonder how to achieve this in the best way and with minimum effort.

In this article, we’ll explain how to serialize Boolean values as Integers — plus, numeric strings — and vice versa in Jackson.

2. Serialization

Initially, we’ll look into the serialization part. To test Boolean to Integer serialization, let’s define our model, Game:

public class Game {

    private Long id;
    private String name;
    private Boolean paused;
    private Boolean over;

    // constructors, getters and setters
}

As usual, the default serialization of the Game object will use Jackson’s ObjectMapper:

ObjectMapper mapper = new ObjectMapper();
Game game = new Game(1L, "My Game");
game.setPaused(true);
game.setOver(false);
String json = mapper.writeValueAsString(game);

Not surprisingly, the output for Boolean fields will be the default — true or false:

{"id":1, "name":"My Game", "paused":true, "over":false}

However, we aim to get the following JSON output from our Game object in the end:

{"id":1, "name":"My Game", "paused":1, "over":0}

2.1. Field Level Configuration

One pretty straightforward way of serializing into Integer is annotating our Boolean fields with @JsonFormat and setting the Shape.NUMBER for it:

@JsonFormat(shape = Shape.NUMBER)
private Boolean paused;

@JsonFormat(shape = Shape.NUMBER)
private Boolean over;

Then, let’s try our serialization in a test method:

ObjectMapper mapper = new ObjectMapper();
Game game = new Game(1L, "My Game");
game.setPaused(true);
game.setOver(false);
String json = mapper.writeValueAsString(game);

assertThat(json)
  .isEqualTo("{\"id\":1,\"name\":\"My Game\",\"paused\":1,\"over\":0}");

As we notice in our JSON output, our Boolean fields — paused and over — formed into numbers 1 and 0. We can see that the values are in integer format since they aren’t surrounded by quotes.

2.2. Global Configuration

Sometimes, annotating every field isn’t practical. For example, depending on requirements, we may need to configure our Boolean to Integer serialization globally.

Luckily, Jackson allows us to globally configure @JsonFormat by overriding the defaults in ObjectMapper:

ObjectMapper mapper = new ObjectMapper();
mapper.configOverride(Boolean.class)
  .setFormat(JsonFormat.Value.forShape(Shape.NUMBER));

Game game = new Game(1L, "My Game");
game.setPaused(true);
game.setOver(false);
String json = mapper.writeValueAsString(game);

assertThat(json)
  .isEqualTo("{\"id\":1,\"name\":\"My Game\",\"paused\":1,\"over\":0}");

3. Deserialization

Similarly, we may also want to obtain Boolean values from numbers while deserializing JSON strings into our models.

Fortunately, Jackson can parse numbers — only 1 and 0 — into Boolean values by default. So, we don’t need to use @JsonFormat annotation or any additional configuration either.

Thus, with no configuration, let’s see this behavior with the help of another test method:

ObjectMapper mapper = new ObjectMapper();
String json = "{\"id\":1,\"name\":\"My Game\",\"paused\":1,\"over\":0}";
Game game = mapper.readValue(json, Game.class);

assertThat(game.isPaused()).isEqualTo(true);
assertThat(game.isOver()).isEqualTo(false);

Consequently, Integer to Boolean deserialization is supported out of the box in Jackson.

4. Numeric Strings Instead of Integers

Another use case is using numeric strings — “1” and “0” — instead of integers. In this case, serializing Boolean values into numeric strings or deserializing them back to Boolean needs some more effort.

4.1. Serializing Into Numeric Strings

To serialize a Boolean value into numeric string equivalents, we need to define a custom serializer.

So, let’s create our NumericBooleanSerializer by extending Jackson’s JsonSerializer:

public class NumericBooleanSerializer extends JsonSerializer<Boolean> {

    @Override
    public void serialize(Boolean value, JsonGenerator gen, SerializerProvider serializers)
      throws IOException {
        gen.writeString(value ? "1" : "0");
    }
}

As a side note, normally, Boolean types can be null. However, Jackson handles this internally and doesn’t take our custom serializer into account when the value field is null. Therefore, we’re safe here.

Next, we’ll register our custom serializer so that Jackson recognizes and uses it.

If we need this behavior only for a limited number of fields, we can choose the field level configuration with the @JsonSerialize annotation.

Accordingly, let’s annotate our Boolean fields, paused and over:

@JsonSerialize(using = NumericBooleanSerializer.class)
private Boolean paused;

@JsonSerialize(using = NumericBooleanSerializer.class)
private Boolean over;

Then, likewise, we try the serialization in a test method:

ObjectMapper mapper = new ObjectMapper();
Game game = new Game(1L, "My Game");
game.setPaused(true);
game.setOver(false);
String json = mapper.writeValueAsString(game);

assertThat(json)
  .isEqualTo("{\"id\":1,\"name\":\"My Game\",\"paused\":\"1\",\"over\":\"0\"}");

Although the test method implementation is almost identical to the previous ones, we should pay attention to the quotes — “paused”:”1″, “over”:”0″ — around the number values. Surely, this indicates those values are actual strings containing numeric contents.

Last but not least, in case we need to perform this custom serialization everywhere, Jackson supports global configuration of serializers by adding them to ObjectMapper via Jackson Modules:

ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(Boolean.class, new NumericBooleanSerializer());
mapper.registerModule(module);

Game game = new Game(1L, "My Game");
game.setPaused(true);
game.setOver(false);
String json = mapper.writeValueAsString(game);

assertThat(json)
  .isEqualTo("{\"id\":1,\"name\":\"My Game\",\"paused\":\"1\",\"over\":\"0\"}");

As a result, Jackson serializes all Boolean typed fields as numeric strings as long as we use the same ObjectMapper instance.

4.2. Deserializing From Numeric Strings

Similar to serializing, this time we’ll define a custom deserializer to parse numeric strings into Boolean values.

Let’s create our class NumericBooleanDeserializer by extending JsonDeserializer:

public class NumericBooleanDeserializer extends JsonDeserializer<Boolean> {

    @Override
    public Boolean deserialize(JsonParser p, DeserializationContext ctxt)
      throws IOException {
        if ("1".equals(p.getText())) {
            return Boolean.TRUE;
        }
        if ("0".equals(p.getText())) {
            return Boolean.FALSE;
        }
        return null;
    }

}

Next, we annotate our Boolean fields once more, but this time with @JsonDeserialize:

@JsonSerialize(using = NumericBooleanSerializer.class)
@JsonDeserialize(using = NumericBooleanDeserializer.class)
private Boolean paused;

@JsonSerialize(using = NumericBooleanSerializer.class)
@JsonDeserialize(using = NumericBooleanDeserializer.class)
private Boolean over;

So, let’s write another test method to see our NumericBooleanDeserializer in action:

ObjectMapper mapper = new ObjectMapper();
String json = "{\"id\":1,\"name\":\"My Game\",\"paused\":\"1\",\"over\":\"0\"}";
Game game = mapper.readValue(json, Game.class);

assertThat(game.isPaused()).isEqualTo(true);
assertThat(game.isOver()).isEqualTo(false);

Alternatively, a global configuration of our custom deserializer is also possible via Jackson Modules:

ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(Boolean.class, new NumericBooleanDeserializer());
mapper.registerModule(module);

String json = "{\"id\":1,\"name\":\"My Game\",\"paused\":\"1\",\"over\":\"0\"}";
Game game = mapper.readValue(json, Game.class);

assertThat(game.isPaused()).isEqualTo(true);
assertThat(game.isOver()).isEqualTo(false);

5. Conclusion

In this article, we described how to serialize Boolean values into integers and numeric strings and how to deserialize them back.

As always, the source code for the samples and more are available over on GitHub.

Course – LS (cat=JSON/Jackson)

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE
res – Jackson (eBook) (cat=Jackson)
Comments are open for 30 days after publishing a post. For any issues past this date, use the Contact form on the site.