Jackson ObjectMapper 入門

Data,Jackson
Remote
1
10:37 PM · Nov 30 ,2025

1. 概述

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

要了解更多關於 Jackson 庫的知識,Jackson 教程是一個不錯的起點。

2. 依賴項

首先,將以下依賴項添加到 pom.xml 中:

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

此依賴項還將 transitively 添加以下庫到 classpath 中:

  1. jackson-annotations
  2. jackson-core

始終從 Maven central 倉庫中使用最新版本 jackson-databind

3. Reading and Writing Using ObjectMapper

Let’s start with the basic read and write operations.

The simple readValue API of the ObjectMapper is a good entry point. We can use it to parse or deserialize JSON content into a Java object.

Also, on the writing side, we can use the writeValue API to serialize any Java object as JSON output.

We’ll use the following Car class with two fields as the object to serialize or deserialize throughout this article:

public class Car {

    private String color;
    private String type;

    // standard getters setters
}

3.1. Java Object to JSON

Let’s see a first example of serializing a Java object into JSON using the writeValue method of the ObjectMapper class:

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

The output of the above in the file will be:

{“color”:“yellow”,“type”:“renault”}

The methods writeValueAsString and writeValueAsBytes of the ObjectMapper class generate a JSON from a Java object and return the generated JSON as a string or as a byte array:

String carAsString = objectMapper.writeValueAsString(car);

3.2. JSON to Java Object

Below is a simple example of converting a JSON String to a Java object using the ObjectMapper class:

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

The readValue() function also accepts other forms of input, such as a file containing JSON string:

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

or an URL:

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

3.3. JSON to Jackson JsonNode

Alternatively, a JSON can be parsed into a JsonNode object and used to retrieve data from a specific node:

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

3.4. Creating a Java List From a JSON Array String

We can parse a JSON in the form of an array into a Java object list using a TypeReference:

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

3.5. Creating Java Map From JSON String

Similarly, we can parse a JSON into a Java Map:

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

4. Advanced Features

One of the greatest strengths of the Jackson library is the highly customizable serialization and deserialization process.

In this section, we’ll go through some advanced features where the input or the output JSON response can be different from the object that generates or consumes the response.

4.1. Configuring Serialization or Deserialization Feature

While converting JSON objects to Java classes, in case the JSON string has some new fields, the default process will result in an exception:

String jsonString 
  = "{ \"color\" : \"Black\", \"type\" : \"Fiat\", \"year\" : \"1970\" }";

The JSON string in the above example in the default parsing process to the Java object for the Class Car will result in the UnrecognizedPropertyException exception.

Through the configure method, we can extend the default process to ignore the new fields:

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

Yet another option is based on the FAIL_ON_NULL_FOR_PRIMITIVES, which defines if the null values for primitive values are allowed:

objectMapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, false);

Similarly, FAIL_ON_NUMBERS_FOR_ENUM controls if enum values are allowed to be serialized/deserialized as numbers:

objectMapper.configure(DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS, false);

You can find the comprehensive list of serialization and deserialization features on the official site.

4.2. Creating Custom Serializer or Deserializer

Another essential feature of the ObjectMapper class is the ability to register a custom serializer and deserializer.

Custom serializers and deserializers are very useful in situations where the input or the output JSON response is different in structure than the Java class into which it must be serialized or deserialized.

Below is an example of a custom JSON serializer:

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

This custom serializer can be invoked like this:

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

Here’s what the Car looks like (as JSON output) on the client side:

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

And here’s an example of a custom JSON deserializer:

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

This custom deserializer can be invoked in this way:

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. Handling Date Formats

The default serialization of java.util.Date produces a number, i.e., epoch timestamp (number of milliseconds since January 1, 1970, UTC). But this is not very human readable and requires further conversion to be displayed in a human-readable format.

Let’s wrap the Car instance we used so far inside the Request class with the datePurchased property:

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

    // standard getters setters
}

To control the String format of a date and set it to, e.g., yyyy-MM-dd HH:mm a z, consider the following snippet:

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

To learn more about serializing dates with Jackson, read our more in-depth write-up.

Please note that in some cases, we need to specify Locale as well while creating SimpleDateFormat so that it gives consistent output across all machines irrespective of the region in which that machine is running.

To specify Locale we can do:

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

4.4. Handling Collections

Another small but useful feature available through the DeserializationFeature class is the ability to generate the type of collection we want from a JSON Array response.

For example, we can generate the result as an 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

Or as a List:

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

More information about handling collections with Jackson is available here.

5. Builder Pattern for 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 實例的構建器類。

5.2. Builder in Action

讓我們使用 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.