將布爾值序列化為整數,使用 Jackson

Jackson
Remote
0
09:29 PM · Nov 30 ,2025

1. 引言

Jackson 庫是 Java 世界中處理 JSON 的事實標準。儘管 Jackson 具有明確定義的默認值,但對於將 Boolean 值映射到 Integer 時,我們仍然需要進行手動配置。

當然,一些開發者會想知道如何以最佳方式和最小的努力來實現這一點。

在本文中,我們將解釋如何將 Boolean 值序列化為 Integer 值(以及數字字符串)以及反之,在 Jackson 中。

2. 序列化

最初,我們將研究序列化部分。為了測試 BooleanInteger 序列化的過程,我們先定義我們的模型,Game

public class Game {

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

    // constructors, getters and setters
}

如往常一樣,Game 對象的默認序列化將使用 Jackson 的 ObjectMapper

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

不出所料,Boolean 字段的輸出將是默認的——truefalse

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

但是,我們旨在從我們的 Game 對象中獲得以下 JSON 輸出作為最終結果:

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

2.1. 字段級別配置

一種相對簡單的方法是為我們的 Boolean 字段添加 @JsonFormat 註解,並將 Shape.NUMBER 設置為它:

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

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

然後,我們嘗試在測試方法中進行序列化:

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

正如我們在 JSON 輸出中觀察到的,我們的 pausedover 字段已轉換為數字 10。我們可以看到,由於沒有用引號括起來,因此值以整數格式表示。

2.2. 全局配置

有時,為每個字段添加註解並不實用。例如,根據要求,我們可能需要全局配置我們的 BooleanInteger 序列化。

幸運的是,Jackson 允許我們通過在 ObjectMapper 中覆蓋默認值來全局配置 @JsonFormat

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. 反序列化

類似於地,我們也可以在反序列化 JSON 字符串為我們的模型時,從數字中獲取 Boolean 值。

幸運的是,Jackson 可以解析數字——僅 10 ——為 Boolean 值,默認情況下。因此,我們不需要使用 @JsonFormat 註解或任何其他配置。

因此,無需配置,讓我們通過另一個測試方法來查看這種行為:

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

因此,IntegerBoolean 反序列化在 Jackson 中默認支持

4. 數字字符串而不是整數

另一個用例是使用數字字符串——“1”“0”——而不是整數。在這種情況下,將Boolean值序列化為數字字符串或反序列化為Boolean需要更多的努力。

4.1. 序列化為數字字符串

為了將Boolean值序列化為數字字符串等效值,我們需要定義一個自定義序列化器。

因此,讓我們通過擴展 Jackson 的 JsonSerializer 創建我們的 NumericBooleanSerializer

public class NumericBooleanSerializer extends JsonSerializer<Boolean> {

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

作為旁註,通常Boolean類型可以是null。但是,Jackson 內部處理這種情況,並且在value字段為null時,它不會考慮我們的自定義序列化器。因此,我們在這裏是安全的。

接下來,我們將自定義序列化器註冊到 Jackson 中,以便 Jackson 能夠識別並使用它。

如果我們需要這種行為僅限於有限數量的字段,我們可以選擇字段級別配置,使用 @JsonSerialize 註解。

相應地,我們標註我們的 Boolean 字段,pausedover

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

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

然後,我們嘗試在測試方法中進行序列化:

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\"}");

雖然測試方法實現幾乎與之前的實現相同,但我們應該注意引號——“paused”:”1″, “over”:”0″——圍繞數字值的引號。這無疑表明這些值是實際的字符串,其中包含數字內容。

最後但並非最不重要,如果我們需要在任何地方執行此自定義序列化,Jackson 支持通過 Jackson 模塊向 ObjectMapper 添加序列化器以進行全局配置。

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\"}");

結果是,Jackson 將所有 Boolean 類型的字段序列化為數字字符串,只要我們使用相同的 ObjectMapper 實例。

4.2. 從數字字符串反序列化

類似於序列化,現在我們將定義一個自定義反序列器來將數字字符串解析為 Boolean 值。

讓我們通過擴展 JsonDeserializer 創建我們的類 NumericBooleanDeserializer

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

}

接下來,我們再次標註我們的 Boolean 字段,但這次使用 @JsonDeserialize:

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

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

因此,我們寫另一個測試方法來查看我們的 NumericBooleanDeserializer 在行動中的情況:

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

或者,我們也可以通過 Jackson 模塊全局配置我們的自定義反序列器:

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. 結論

在本文中,我們描述瞭如何將 Boolean 值序列化為整數和數字字符串,以及如何將它們反序列化回原樣。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.