【Jackson 】 - ObjectMapper对象详解
Jackson ObjectMapper对象详解
1.概述
本文将全面深入的学习Jackson ObjectMapper类,以及如何将Java对象序列化为JSON或者将JSON字符串反序列化为Java对象。
2.添加Jackson依赖
首先,在_pom.xml_中添加jackson依赖:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.3</version>
</dependency>
如果不是maven项目,需要将以下jar包添加到类依赖中:
- jackson-annotations-2.9.8.jar
- jackson-core-2.9.8.jar
- jackson-databind-2.9.8.jar
注意:2.9.x 版本存在安全漏洞,建议使用2.10.x 以上版本。
3.使用ObjectMapper进行读写
我们可以使用ObjectMapper的readValue 方法将JSON内容反序列化为Java对象。同样,我们可也以使用ObjectMapper的writeValue 方法将Java对象序列化为JSON。
我们将使用下面的Car类对象作为实例来序列化或反序列化:
public class Car {
private String name;
private String color;
// standard getters setters
}
3.1.Java对象转JSON
使用_ObjectMapper_类的_writeValue_方法将Java对象序列到JSON文件中:
File resultFile = new File("target/car.json");
ObjectMapper objectMapper = new ObjectMapper();
Car car = new Car("BMW", "Black");
objectMapper.writeValue(resultFile, car);
上述实例输出结果是:
{"name":"BMW","color":"Black"}
如果希望将Java对象转换为字符串或字节数组,可以使用ObjectMapper类的writeValueAsString和writeValueAsBytes方法:
String carAsString = objectMapper.writeValueAsString(car);
3.2. JSON转Java对象
使用_ObjectMapper_类将JSON字符串转换为Java对象:
@Test
public void jsonToJavaObject() throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
String jsonString = "{\"name\":\"BMW\",\"color\":\"Black\"}";
Car car = objectMapper.readValue(jsonString, Car.class);
assertNotNull(car);
System.out.println(car);
}
readValue()函数还接受其他形式的输入,比如从JSON字符串的文件中读取数据:
@Test
public void jsonFileToJavaObject() throws Exception {
File resource = new File("target/car.json");
ObjectMapper objectMapper = new ObjectMapper();
Car car = objectMapper.readValue(resource, Car.class);
System.out.println(car);
}
或从网络获取JSON字符串文件:
@Test
public void fromURLToJavaObject() throws Exception {
URL resource = new URL("file:src/test/resources/json_car.json");
ObjectMapper objectMapper = new ObjectMapper();
Car car = objectMapper.readValue(resource, Car.class);
System.out.println(car);
}
3.3. JSON转JsonNode
可以将JSON解析为_JsonNode_对象,然后从JsonNode对象中获取数据:
@Test
public void jsonToJsonNode() throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
String jsonString = "{\"name\":\"BMW\",\"color\":\"Black\"}";
JsonNode jsonNode = objectMapper.readTree(jsonString);
assertNotNull(jsonNode);
System.out.println(jsonNode);
System.out.println(jsonNode.get("name"));
System.out.println(jsonNode.get("name").asText());
}
// Output:{"name":"BMW","color":"Black"} “BMW" BMW
3.4. JSON数组字符串解析为Java List
使用_TypeReference_将数组形式的JSON解析为Java List:
@Test
public void jsonArrayToList() throws Exception {
String resourceJson = "[{ \"name\" : \"BMW\", \"color\" : \"Black\" }," +
" { \"name\" : \"toyota\", \"color\" : \"Red\" }]";
ObjectMapper objectMapper = new ObjectMapper();
List<Car> listCar = objectMapper.readValue(resourceJson, new TypeReference<List<Car>>() {
});
for (final Car car : listCar) {
System.out.println(car);
}
}
3.5. JSON字符串解析为Java Map
将JSON解析为Java Map:
@Test
public void jsonToMap() throws Exception {
String jsonString = "{\"name\":\"BMW\",\"color\":\"Black\"}";
ObjectMapper objectMapper = new ObjectMapper();
Map<String, Object> map = objectMapper.readValue(jsonString, new TypeReference<Map<String, Object>>() {
});
System.out.println(map);
}
//{name=BMW, color=Black}
4.高级功能
Jackson库的最大优势之一就是高度可定制的序列化和反序列化。下面,我们将介绍一些高级功能。
4.1. 配置序列化或反序列化功能
将JSON对象转换为Java类时,如果JSON字符串中包含Java类中没有的字段,那么,默认解析过程将导致异常:
String jsonString = "{\"name\":\"BMW\",\"color\":\"Black\",\"price\":\"200000\"}";
上面示例的默认解析过程中,将导致_UnrecognizedPropertyException_异常。
通过configure方法,我们可以扩展默认解析过程以忽略新字段,解决以上异常:
@Test
public void failOnUnkownProperties() throws Exception {
String jsonCar = "{\"name\":\"BMW\",\"color\":\"Black\",\"price\":\"230000\"}";
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
Car car = objectMapper.readValue(jsonCar, Car.class);
System.out.println(car);
JsonNode jsonNodeRoot = objectMapper.readTree(jsonCar);
JsonNode jsonNodePrice = jsonNodeRoot.get("price");
String price = jsonNodePrice.asText();
System.out.println(price);
}
另一个选项是基于_FAIL_ON_NULL_FOR_PRIMITIVES的_,它定义了是否允许原始值为空值:
objectMapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, false);
同样,_FAIL_ON_NUMBERS_FOR_ENUM_控制是否允许将枚举值序列化/反序列化为数字:
objectMapper.configure(DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS, false);
您可以在Jackson专辑中找到序列化和反序列化的相关文章。
4.2. 自定义序列化或反序列化
_ObjectMapper_类的另一个基本功能是能够自定义序列化器和反序列化器。当输入或输出的JSON结构和需要进行序列化或反序列化的Java类的结构不同时,自定义序列化器和反序列化器非常有用。
以下是自定义JSON序列化代码:
public class CustomCarSerializer extends StdSerializer<Car> {
public CustomCarSerializer() {
this(null);
}
public CustomCarSerializer(final Class<Car> t) {
super(t);
}
@Override
public void serialize( Car car, JsonGenerator jsonGenerator, SerializerProvider serializer) throws IOException {
jsonGenerator.writeStartObject();
jsonGenerator.writeStringField("name1: ", car.getName());
jsonGenerator.writeStringField("color1: ", car.getColor());
jsonGenerator.writeEndObject();
}
}
调用测试代码:
@Test
public void customSerializer() throws Exception {
ObjectMapper mapper = new ObjectMapper();
SimpleModule serializerModule = new SimpleModule("CustomSerializer", new Version(1, 0, 0, null, null, null));
serializerModule.addSerializer(Car.class, new CustomCarSerializer());
mapper.registerModule(serializerModule);
Car car = new Car("BMW", "Black");
String carJson = mapper.writeValueAsString(car);
System.out.println(carJson);
}
输出结果:
{"name1: ":"BMW","color1: ":"Black"}
以下是一个自定义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) throws IOException {
Car car = new Car();
ObjectCodec codec = parser.getCodec();
JsonNode node = codec.readTree(parser);
try {
JsonNode colorNode = node.get("color");
String color = colorNode.asText();
car.setColor(color);
} catch (final Exception e) {
Logger.debug("parse_exeption: unknown json.");
}
return car;
}
}
运行测试代码:
@Test
public void customDeserializer() throws Exception {
ObjectMapper mapper = new ObjectMapper();
SimpleModule deserializerModule = new SimpleModule("CustomCarDeserializer", new Version(1, 0, 0, null, null, null));
deserializerModule.addDeserializer(Car.class, new CustomCarDeserializer());
mapper.registerModule(deserializerModule);
Car car = mapper.readValue(EXAMPLE_JSON, Car.class);
System.out.println(car);
}
4.3. 处理日期格式
java.util.Date的默认序列化产生一个数字,即epoch时间戳(自1970年1月1日以来,以毫秒为单位,UTC)。但这不是我们日常生活中可读的,需要进一步的转换才能按照我们可读的格式显示。
在这里我们新建一个Student类来演示日期格式处理:
public class Student {
Car car;
Date birthday;
//省略 getters setters
}
我们希望将日期格式设置为yyyy-MM-dd HH:mm:ss ,测试代码如下:
@Test
public void dateFormat() throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
Car car = new Car("BMW", "Black");
Student student = new Student();
student.setCar(car);
student.setBirthday(new Date());
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
objectMapper.setDateFormat(df);
String carAsString = objectMapper.writeValueAsString(student);
System.out.println(carAsString);
}
输出结果如下:
{"car":{"name":"BMW","color":"Black"},"birthday":"2020-05-18 13:56:15"}
要了解有关使用Jackson进行日期序列化的更多信息,请阅读我们更深入的文章。
4.4. 处理集合
DeserializationFeature类提供的另一个小而有用的功能是能够将JSON数组生成我们想要的集合类型。
例如,我们可以将结果生成为数组:
@Test
public void jsonArrayToJavaArray() throws Exception {
String jsonArray = "[{ \"name\" : \"BMW\", \"color\" : \"Black\" }," +
" { \"name\" : \"toyota\", \"color\" : \"Red\" }]";
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.USE_JAVA_ARRAY_FOR_JSON_ARRAY, true);
Car[] cars = objectMapper.readValue(jsonArray, Car[].class);
System.out.println(car);
}
或者时List:
@Test
public void jsonArrayToJavaList() throws Exception {
String jsonArray = "[{ \"name\" : \"BMW\", \"color\" : \"Black\" }," +
" { \"name\" : \"toyota\", \"color\" : \"Red\" }]";
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.USE_JAVA_ARRAY_FOR_JSON_ARRAY, true);
List<Car> listCar = objectMapper.readValue(jsonArray, new TypeReference<List<Car>>(){});
for (Car car : listCar) {
System.out.println(car);
}
}
ObjectMapper 的构建器模式
到目前为止,我们已经了解了配置 ObjectMapper 实例的不同方法。在本节中, 我们将对 ObjectMapperBuilder 类进行原型设计,以创建 ObjectMapper 类的不可变实例。
ObjectMapperBuilder 类
让我们首先创建具有几个配置参数(即 enableIdentation、preserveOrder 和 dateFormat)的 ObjectMapperBuilder 类 :
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;
}
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);

浙公网安备 33010602011771号