知識庫 / JSON / Jackson RSS 訂閱

Jackson ObjectMapper 入門教程

Data,Jackson
HongKong
11
09:56 PM · Dec 05 ,2025

1. 概述

本教程重點介紹 Jackson 的 ObjectMapper 類及其如何將 Java 對象序列化為 JSON 以及如何將 JSON 字符串反序列化為 Java 對象。

要了解 Jackson 庫的更多信息,Jackson 教程是一個不錯的起點。

2. 依賴項

以下依賴項請添加到 `pom.xml</em/> 中:

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.17.2</version>
</dependency>

這個依賴項也會間接添加以下庫到 classpath 中:

  1. jackson-annotations
  2. jackson-core

請始終從 Maven 中央倉庫獲取最新版本 jackson-databind

3. 使用 ObjectMapper 進行讀取和寫入操作

讓我們從基本的讀取和寫入操作開始。

簡單的 readValue API 在 ObjectMapper 中是一個不錯的入門點。 我們可以使用它來解析或反序列化 JSON 內容到 Java 對象。

在寫入方面,我們可以使用 writeValue API 將任何 Java 對象序列化為 JSON 輸出。

在本文中,我們將使用以下 Car 類,該類具有兩個字段,作為要序列化或反序列化的對象:

public class Car {

    private String color;
    private String type;

    // standard getters setters
}

3.1. Java 對象到 JSON

讓我們來看一個使用 writeValue 方法將 Java 對象序列化為 JSON 的第一個示例,該方法位於 ObjectMapper 類中:

ObjectMapper objectMapper = new ObjectMapper();
Car car = new Car("yellow", "renault");
objectMapper.writeValue(new File("target/car.json"), car);

以上文件的輸出將是:

{"color":"yellow","type":"renault"}

writeValueAsStringwriteValueAsBytesObjectMapper 類中的兩個方法,它們分別生成 JSON 字符串並返回,或生成 JSON 字節數組:

String carAsString = objectMapper.writeValueAsString(car);

3.2. JSON 到 Java 對象

以下是一個使用 ObjectMapper 類將 JSON 字符串轉換為 Java 對象的簡單示例:

String json = "{ \"color\" : \"Black\", \"type\" : \"BMW\" }";
Car car = objectMapper.readValue(json, Car.class);	

readValue() 函數也接受其他形式的輸入,例如包含 JSON 字符串的文件:

Car car = objectMapper.readValue(new File("src/test/resources/json_car.json"), Car.class);

或一個 URL:

Car car = 
  objectMapper.readValue(new URL("file:src/test/resources/json_car.json"), Car.class);

3.3. JSON 到 Jackson 的 JsonNode

也可以將 JSON 解析為 JsonNode 對象,並從中檢索特定節點的數據:

String json = "{ \"color\" : \"Black\", \"type\" : \"FIAT\" }";
JsonNode jsonNode = objectMapper.readTree(json);
String color = jsonNode.get("color").asText();
// Output: color -> Black

3.4. 從 JSON 數組字符串創建 Java List

我們可以使用 TypeReference 解析 JSON 格式的數組,將其轉換為 Java 對象列表。

String jsonCarArray = 
  "[{ \"color\" : \"Black\", \"type\" : \"BMW\" }, { \"color\" : \"Red\", \"type\" : \"FIAT\" }]";
List<Car> listCar = objectMapper.readValue(jsonCarArray, new TypeReference<List<Car>>(){});

3.5. 從 JSON 字符串創建 Java Map

類似於地,我們可以將 JSON 解析為 Java 的 Map

String json = "{ \"color\" : \"Black\", \"type\" : \"BMW\" }";
Map<String, Object> map 
  = objectMapper.readValue(json, new TypeReference<Map<String,Object>>(){});

4. 高級功能

Jackson 庫的最大優勢之一是高度可定製的序列化和反序列化過程。

在這一部分,我們將探討一些高級功能,其中輸入或輸出 JSON 響應可以與生成或消耗響應的對象不同。

<h3><strong>4.1. 配置序列化或反序列化功能</strong></h3>
<p>在將 JSON 對象轉換為 Java 類時,如果 JSON 字符串包含新的字段,則默認過程將導致異常。</p>
String jsonString 
  = "{ \"color\" : \"Black\", \"type\" : \"Fiat\", \"year\" : \"1970\" }";

在上述示例中,將 JSON 字符串傳遞給 Java 對象 Class Car 進行默認解析,會導致 UnrecognizedPropertyException 異常。

通過 configure 方法,我們可以擴展默認流程,忽略新的字段。

objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
Car car = objectMapper.readValue(jsonString, Car.class);

JsonNode jsonNodeRoot = objectMapper.readTree(jsonString);
JsonNode jsonNodeYear = jsonNodeRoot.get("year");
String year = jsonNodeYear.asText();

另一個選項基於 FAIL_ON_NULL_FOR_PRIMITIVES,它定義了是否允許對原始類型的值使用 null 值:

objectMapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, false);

同樣,<em>FAIL_ON_NUMBERS_FOR_ENUM</em> 控制枚舉值是否允許被序列化/反序列化為數字:

objectMapper.configure(DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS, false);

你可以找到序列化和反序列化的完整列表,請訪問官方網站

4.2. 創建自定義序列化器或反序列器

ObjectMapper 類的一個關鍵功能是能夠註冊自定義序列化器和反序列器。

自定義序列化器和反序列器在輸入或輸出 JSON 響應與必須序列化或反序列化到 Java 類所具有的結構不同時非常有用。

以下是一個自定義 JSON 序列化器的示例:

public class CustomCarSerializer extends StdSerializer<Car> {
    
    public CustomCarSerializer() {
        this(null);
    }

    public CustomCarSerializer(Class<Car> t) {
        super(t);
    }

    @Override
    public void serialize(
      Car car, JsonGenerator jsonGenerator, SerializerProvider serializer) {
        jsonGenerator.writeStartObject();
        jsonGenerator.writeStringField("car_brand", car.getType());
        jsonGenerator.writeEndObject();
    }
}

此自定義序列化器可以這樣調用:

ObjectMapper mapper = new ObjectMapper();
SimpleModule module = 
  new SimpleModule("CustomCarSerializer", new Version(1, 0, 0, null, null, null));
module.addSerializer(Car.class, new CustomCarSerializer());
mapper.registerModule(module);
Car car = new Car("yellow", "renault");
String carJson = mapper.writeValueAsString(car);

以下是翻譯後的內容:

以下是客户端的 汽車 (以 JSON 格式輸出) 所示:

var carJson = {"car_brand":"renault"}

以下是一個自定義 JSON 反序列化器示例:

public class CustomCarDeserializer extends StdDeserializer<Car> {
    
    public CustomCarDeserializer() {
        this(null);
    }

    public CustomCarDeserializer(Class<?> vc) {
        super(vc);
    }

    @Override
    public Car deserialize(JsonParser parser, DeserializationContext deserializer) {
        Car car = new Car();
        ObjectCodec codec = parser.getCodec();
        JsonNode node = codec.readTree(parser);
        
        // try catch block
        JsonNode colorNode = node.get("color");
        String color = colorNode.asText();
        car.setColor(color);
        return car;
    }
}

可以使用以下方式調用此自定義反序列器:

String json = "{ \"color\" : \"Black\", \"type\" : \"BMW\" }";
ObjectMapper mapper = new ObjectMapper();
SimpleModule module =
  new SimpleModule("CustomCarDeserializer", new Version(1, 0, 0, null, null, null));
module.addDeserializer(Car.class, new CustomCarDeserializer());
mapper.registerModule(module);
Car car = mapper.readValue(json, Car.class);

4.3. 處理日期格式

默認情況下,java.util.Date 的序列化會產生一個數字,即從協調世界時(UTC)1970 年 1 月 1 日以來的毫秒數(時間戳)。但這種格式不太易於人類閲讀,需要進行進一步轉換才能以人類可讀的格式顯示。

讓我們將我們之前使用的 Car 實例包裹在 Request 類中,並添加 datePurchased 屬性:

public class Request 
{
    private Car car;
    private Date datePurchased;

    // standard getters setters
}

為了控制日期的格式並將其設置為,例如 yyyy-MM-dd HH:mm a z,請考慮以下代碼片段:

ObjectMapper objectMapper = new ObjectMapper();
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm a z");
objectMapper.setDateFormat(df);
String carAsString = objectMapper.writeValueAsString(request);
// output: {"car":{"color":"yellow","type":"renault"},"datePurchased":"2016-07-03 11:43 AM CEST"}

為了更深入地瞭解使用 Jackson 序列化日期,請閲讀我們的詳細説明文檔。

請注意,在某些情況下,創建 SimpleDateFormat 時,我們需要明確指定 Locale,以便在不受地域影響的機器上獲得一致的輸出。

要指定 Locale,可以這樣做:

SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm a z", Locale.ENGLISH);

4.4. 處理集合 (Handling Collections)

另一個通過 <em >DeserializationFeature</em> 類提供的實用功能是,能夠從 JSON Array 響應中生成我們所需的集合類型。

例如,我們可以將結果生成為數組:

String jsonCarArray = 
  "[{ \"color\" : \"Black\", \"type\" : \"BMW\" }, { \"color\" : \"Red\", \"type\" : \"FIAT\" }]";
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.USE_JAVA_ARRAY_FOR_JSON_ARRAY, true);
Car[] cars = objectMapper.readValue(jsonCarArray, Car[].class);
// print cars

或者,以列表形式:

String jsonCarArray = 
  "[{ \"color\" : \"Black\", \"type\" : \"BMW\" }, { \"color\" : \"Red\", \"type\" : \"FIAT\" }]";
ObjectMapper objectMapper = new ObjectMapper();
List<Car> listCar = objectMapper.readValue(jsonCarArray, new TypeReference<List<Car>>(){});
// print cars

有關使用 Jackson 處理集合的更多信息,請參閲這裏。

5. 使用 Builder 模式為 ObjectMapper 構建

到目前為止,我們已經學習了配置 ObjectMapper 實例的不同方法。 在本節中,我們將創建一個 ObjectMapperBuilder 類,以創建 ObjectMapper 類的不可變實例。

5.1. ObjectMapperBuilder

讓我們首先創建一個 ObjectMapperBuilder 類,並配置一些參數,包括 enableIdentationpreserveOrderdateFormat

public class ObjectMapperBuilder {
    private boolean enableIndentation;
    private boolean preserveOrder;
    private DateFormat dateFormat;
}

必須注意的是,ObjectMapper 實例有多種可能配置。我們目前僅關注為原型構建用例選擇的一組配置子集。

接下來,讓我們添加方法,以便在創建 ObjectMapper 類實例時,將相應的配置屬性設置為構建器。

ObjectMapperBuilder enableIndentation() {
    this.enableIndentation = true;
    return this;
}

ObjectMapperBuilder dateFormat() {
    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm a z");
    simpleDateFormat.setTimeZone(TimeZone.getTimeZone(ZoneId.of("Asia/Kolkata")));
    this.dateFormat = simpleDateFormat;
    return this;
}

ObjectMapperBuilder preserveOrder(boolean order) {
    this.preserveOrder = order;
    return this;
}

最後,讓我們添加build()方法,以返回帶有配置參數的最終 ObjectMapper 實例:

public ObjectMapper build() {
    ObjectMapper objectMapper = new ObjectMapper();

    objectMapper.configure(SerializationFeature.INDENT_OUTPUT, this.enableIndentation);
    objectMapper.setDateFormat(this.dateFormat);
    if (this.preserveOrder) {
        objectMapper.enable(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS);
    }

    return objectMapper;
}

太棒了!我們已成功原型化了 ObjectMapper 實例的 builder 類。

5.2. Builder 示例

讓我們通過使用 ObjectMapperBuilder 類,創建一個 ObjectMapper 類的實例:

ObjectMapper mapper = new ObjectMapperBuilder()
  .enableIndentation()
  .dateFormat()
  .preserveOrder(true)
  .build();

現在,讓我們定義 Car 類及其序列化的 JSON 字符串:

Car givenCar = new Car("White", "Sedan");
String givenCarJsonStr = "{ \"color\" : \"White\", \"type\" : \"Sedan\" }";

繼續進行,我們使用 mapper 對象來反序列化 givenCarJsonStr

Car actual = mapper.readValue(givenCarJsonStr, Car.class);
Assertions.assertEquals("White", actual.getColor());
Assertions.assertEquals("Sedan", actual.getType());

完美!看來我們已經搞定了。

最後,讓我們驗證 Request 類的一個實例的序列化流程:

Request request = new Request();
request.setCar(givenCar);
Date date = new Date(1684909857000L);
request.setDatePurchased(date);

String actual = mapper.writeValueAsString(request);
String expected = "{\n" + "  \"car\" : {\n" + "    \"color\" : \"White\",\n" +
    "    \"type\" : \"Sedan\"\n" + "  },\n" + "  \"datePurchased\" : \"2023-05-24 12:00 PM IST\"\n" +
    "}";
Assertions.assertEquals(expected, actual);

太好了!我們已通過 ObjectMapperBuilder 類成功驗證了序列化和反序列化操作。

6. 結論

Jackson 是一款穩定且成熟的 Java JSON 序列化/反序列化庫。ObjectMapper API 提供了一種簡單直接的方式來解析和生成 JSON 響應對象,具有很大的靈活性。此外,我們對 ObjectMapperBuilder 類進行了原型設計,以創建 ObjectMapper 類的不可變實例。本文討論了使該庫如此流行的主要功能。

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

發佈 評論

Some HTML is okay.