Jackson ObjectMapper 简介

概述

本教程重点介绍如何理解 Jackson ObjectMapper 类,以及如何将 Java 对象序列化为 JSON,以及如何将 JSON 字符串反序列化为 Java 对象

依赖关系

让我们首先将以下依赖项添加到 pom.xml:

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

此依赖项还将以传递方式将以下库添加到类路径中:

  • jackson-annotations
  • jackson-core

使用 ObjectMapper 进行读写

让我们从基本的读取和写入操作开始。
ObjectMapper 的简单 readValue API 是一个很好的入口点。我们可以使用它来解析或反序列化 JSON 内容到 Java 对象中。
此外,在写入方面,我们可以使用 writeValue API 将任何 Java 对象序列化为 JSON 输出。
在本文中,我们将使用以下带有两个字段的 Car 类作为序列化或反序列化的对象:

public class Car {
    private String color;
    private String type;
    // standard getters setters
}
Java Object to JSON

让我们看一个使用 ObjectMapper 类的 writeValue 方法将 Java 对象序列化为 JSON 的第一个示例:

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

文件中上述内容的输出将为:

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

ObjectMapper类的方法 writeValueAsString 和 writeValueAsBytes 从Java对象生成JSON,并以字符串或字节数组的形式返回生成的JSON:

String carAsString = objectMapper.writeValueAsString(car);
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);
JSON to Jackson JsonNode

也可以将 JSON 解析为 JsonNode 对象,并用于从特定节点检索数据:

String json = "{ \"color\" : \"Black\", \"type\" : \"FIAT\" }";
JsonNode jsonNode = objectMapper.readTree(json);
String color = jsonNode.get("color").asText();
// Output: color -> Black
从 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>>(){});
从 JSON 字符串创建 Java Map

同样,我们可以将JSON解析为Java Map:

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

高级功能

Jackson 库的最大优势之一是高度可自定义的序列化和反序列化过程。
在本节中,我们将介绍一些高级功能,其中输入或输出 JSON 响应可能与生成或使用响应的对象不同。

配置序列化或反序列化功能

将 JSON 对象转换为 Java 类时,如果 JSON 字符串包含一些新字段,则默认过程将导致异常:

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

上述示例中对类 Car 的 Java 对象的默认解析过程中的 JSON 字符串将导致“无法识别 PropertyException ”异常。
通过 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,它确定在反序列化为Java基元类型(如‘int’或‘Double’)时遇到JSON NULL是否为错误。如果是,则抛出 JsonProcessingException;如果不是,则使用缺省值(0代表‘int’,0.0代表Double,与JVM使用的缺省值相同)。
默认情况下,该功能处于禁用状态。

objectMapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, false);

同样,FAIL_ON_NUMBERS_FOR_ENUM, 它确定JSON整数是否是用于反序列化Java枚举值的有效值的功能。
如果设置为 false,则数字是可接受的,并用于映射到匹配枚举值的 ordinal();如果设置为 true,则不允许使用数字,并将引发JsonMappingException。
如果担心可能会发生从整数值到枚举的意外映射(以及当枚举始终被序列化为JSON字符串时),后一种行为是有意义的。
默认情况下,该功能处于禁用状态。控制是否允许将枚举值序列化/反序列化为数字:

objectMapper.configure(DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS, false);
创建自定义序列化程序或反序列化程序

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

以下是 Car 作为JSON的输出:

{"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);
处理日期格式

java.util.Date 的默认序列化会生成一个数字,即 epoch 时间戳(自 1970 年 1 月 1 日 UTC 以来的毫秒数)。但这不是很人性化,需要进一步转换才能以人类可读的格式显示。

让我们使用 datePurchased 属性包装到目前为止在 Request 类中使用的 Car 实例:

public class Request {
    private Car car;
    private Date datePurchased;
    // standard getters setters
}

要控制日期的字符串格式并将其设置为,例如,yy-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"}
处理集合

通过反序列化功能类提供的另一个小而有用的功能是能够从 JSON 数组响应生成我们想要的集合类型。

例如,我们可以将结果生成为数组:

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 是一个可靠而成熟的 Java JSON 序列化/反序列化库。ObjectMapper API 提供了一种简单明了的方法来解析和生成 JSON 响应对象,并且具有很大的灵活性。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值