在上月末的时候收到一条关于fastjson安全漏洞的消息,突然想到先前好像已经有好多次这样的事件了(在fastjson上面)。关于安全方面,虽然中枪的机率微小,但是在这个信息越来越复杂的时代,安全性也变得越来越重要,就像DevSecOps的诞生,在软件交付的整个价值流中我们也需要注重安全这方面。当然我们现在不谈关于FastJson的优劣,因为我们本文的目标是让大家了解和掌握Jackson。


概览

Jackson是一个非常流行和高效的基于Java的库,它可以序列化java对象或将java对象映射到JSON,反之亦然。当然除了Jackson,在Java中同类型的优秀的库也有很多,比如:

关于哪一个最好或者哪一个最流行,没有明确的答案。技术的种类繁多,每个人对与不同技术的态度也是不一样。言归正传,文章主要还是讨论Jackson的。本文主要讲解我们处理Json中最常见的两个操作:

  • 将Java对象序列化为JSON
  • JSON字符串反序列化为Java对象

JavaObject to Json

ObjectMapper

ObjectMapper是一个映射器(或数据绑定器或编解码器),提供了在Java对象(bean的实例)和JSON之间进行转换的功能。

首先定义一个简单的Java类

public class Car {
private String color;
private String type;
// standard getters setters
}

将Java对象转换成Json

我们使用ObjectMapper的writeValue相关Api来对Java对象进行序列化操作

ObjectMapper objectMapper = new ObjectMapper();
Car car = new Car("blue","c1");
System.out.println(objectMapper.writeValueAsString(car));

此时输出

{"color":"blue","type":"c1"}

更多

ObjectMapper的writeValue相关Api还提供了很多便利的Json序列化操作方法,比如:将对象序列化成Json字节数组的writeValueAsBytes()方法、自定义输出源的writeValue()方法...

ObjectMapper objectMapper = new ObjectMapper();
Car car = new Car("blue","c1");
objectMapper.writeValue(new File("./xxx.txt"),car);

运行上述代码,Java对象的序列化Json将被输出到xxx.txt文件。


Json to JavaObject

将Json String转换成Java Object

ObjectMapper objectMapper = new ObjectMapper();
String json = "{\"color\":\"blue\",\"type\":\"c1\"}";
Car car = objectMapper.readValue(json, Car.class);

readValue()方法也接受其他形式的输入,比如包含JSON字符串的文件:

ObjectMapper objectMapper = new ObjectMapper();
Car car = objectMapper.readValue(new File("./xxx.txt"), Car.class);
System.out.println(car);

JSON to Jackson JsonNode

JsonNode

一个JSON可以被解析成一个JsonNode对象,用来从一个特定的节点检索数据.

使用readTree()方法,我们可以将Json字符串转换成JsonNode

ObjectMapper objectMapper = new ObjectMapper();
String json = "{ \"color\" : \"Black\", \"type\" : \"FIAT\" }";
JsonNode jsonNode = objectMapper.readTree(json);
System.out.println(jsonNode.findValue("type").asText());
// 打印出“FAIT”

JSONArrayString to JavaList

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

JSONString to JavaMap

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

Jackson库最大的优点之一是高度可定制的序列化和反序列化过程。接下来将介绍一些高级特性,其中输入或输出JSON响应可以与生成或使用响应的对象不同。

配置序列化和反序列化特性

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

假设使用如上json字符串来反序列化成Java对象,按照默认解析过程将导致UnrecognizedPropertyException exception异常。

通过配置序列化和反序列化特性来解决此问题:

ObjectMapper objectMapper = new ObjectMapper();
String jsonString = "{ \"color\" : \"Black\", \"type\" : \"Fiat\", \"year\" :\"1970\" }";
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
Car car = objectMapper.readValue(jsonString, Car.class);

如上,我们在ObjectMapper中配置了DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES=false,从而实现忽略新的字段。

类似:另一个选项FAIL_ON_NULL_FOR_PRIMITIVES,它定义了是否允许原始值的空值;FAIL_ON_NUMBERS_FOR_ENUM控制是否允许enum值被序列化/反序列化为数字...


自定义序列化器或反序列化器

自定义序列化器

public static 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) throws IOException {
jsonGenerator.writeStartObject();
jsonGenerator.writeStringField("car_brand", car.getType());
jsonGenerator.writeEndObject();
}
}

如上,通过集成StdSerializer类,我们实现了一个自定义的序列化器。

使用自定义的序列化器:

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", "enault");
System.out.println(mapper.writeValueAsString(car));
//输出{"car_brand":"enault"}

自定义反序列化器

public static class CustomCarDeserializer extends StdDeserializer<Car> {

        public CustomCarDeserializer() {
this(null);
} protected CustomCarDeserializer(Class<?> vc) {
super(vc);
} @Override
public Car deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
Car car = new Car();
ObjectCodec codec = p.getCodec();
JsonNode node = codec.readTree(p);
// try catch block
JsonNode colorNode = node.get("color");
String color = colorNode.asText();
car.setColor(color);
return car;
}
}

如上,通过集成StdDeserializer类,我们实现了一个自定义的序列化器。

使用自定义的反序列化器:

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);
//此时的car {color='Black', type='null'}

处理时间格式

️:此处仅展示对于Java8的LocalDate&LocalDateTime的处理

首先创建一个带日期时间字段的Car类

public class Car {
private String color;
private String type;
@JsonFormat(pattern = "yyyy-MM-dd")
private LocalDateTime produceTime;
// standard getters setters
}

自定义时间格式处理

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.findAndRegisterModules();
Car car = new Car().setColor("blue").setType("c1").setProduceTime(LocalDateTime.now());
String carAsString = objectMapper.writeValueAsString(car);
System.out.println(carAsString);
//此时输出:{"color":"blue","type":"c1","produceTime":"2020-06-06"}

处理集合

DeserializationFeature类提供的另一个小但有用的特性是能够从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);

如上,我们将一个JsonArray字符串转换成了对象数组。

我们也可以将其转换成集合:

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响应对象,具有很大的灵活性。


关注笔者公众号,推送各类原创/优质技术文章 ️

除了FastJson,你也应该了解一下Jackson(一)的更多相关文章

  1. jersey 用FastJson替换掉默认的Jackson

    @Bean public ResourceConfig resourceConfig() { ResourceConfig resourceConfig = new ResourceConfig(); ...

  2. 除了FastJson,你也应该了解一下Jackson(二)

    概览 上一篇文章介绍了Jackson中的映射器ObjectMapper,以及如何使用它来实现Json与Java对象之间的序列化和反序列化,最后介绍了Jackson中一些序列化/反序列化的高级特性.而本 ...

  3. springboot利用fastjson序列化输出(默认是jackson)

    在@SpringBootApplication类中添加 @Bean public HttpMessageConverters fastJsonHttpMessageConverters() { //创 ...

  4. dubbox REST服务使用fastjson替换jackson

    上一节讲解了resteasy如何使用fastjson来替换默认的jackson,虽然dubbox内部采用的就是resteasy,但是大多数情况下,dubbox服务是一个独立的app,并不需要以war包 ...

  5. Jackson替换fastjson

    为什么要替换fastjson 工程里大量使用了fastjson作为序列化和反序列化框架,甚至ORM在处理部分字段也依赖fastjson进行序列化和反序列化.那么作为大量使用的基础框架,为什么还要进行替 ...

  6. jackson、fastjson、kryo、protostuff等序列化工具性能对比

    简介 实际项目中,我们经常需要使用序列化工具来存储和传输对象.目前用得比较多的序列化工具有:jackson.fastjson.kryo.protostuff.fst 等,本文将简单对比这几款工具序列化 ...

  7. 封装fastjson为spring mvc的json view

    可以将其中的main方法删掉.测试用的.我测试的结果是,jackson比fastjson快. fastjson是1.1.36 jackson是2.2.3 jdk是1.7.40,client cpu是i ...

  8. No message body writer has been found for class com.alibaba.fastjson.JSONObject, ContentType: */*

    1:当使用 cxf 发布服务时,要求返回值类型为xml,或者json等 @Path("/searchProductByText") @GET @Produces({"ap ...

  9. SpringBoot2.0整合fastjson的正确姿势

            SpringBoot2.0如何集成fastjson?在网上查了一堆资料,但是各文章的说法不一,有些还是错的,可能只是简单测试一下就认为ok了,最后有没生效都不知道.恰逢公司项目需要将J ...

随机推荐

  1. myeclipse 创建maven web项目

    在项目开发中常用到maven进行项目管理!在这里记录下maven创建web项目的过程方便以后查看! 第一步.新建maven项目 选择maven project点击下一步 一直next后最后一步设置:在 ...

  2. java学习笔记之原型模式及深浅拷贝

    一.原型模式的基本介绍 在聊原型模式之前,我们来思考一个小问题,传统的方式我们是如何克隆对象呢? 那我们以多利羊(Sheep)为例,来说明上述这个问题,具体代码见下面: 多利羊(Sheep) publ ...

  3. Python 图像处理 OpenCV (2):像素处理与 Numpy 操作以及 Matplotlib 显示图像

    前文传送门: 「Python 图像处理 OpenCV (1):入门」 普通操作 1. 读取像素 读取像素可以通过行坐标和列坐标来进行访问,灰度图像直接返回灰度值,彩色图像则返回B.G.R三个分量. 需 ...

  4. 最短路径——floyd算法代码(c语言)

    最短路径问题 昨天自己试了试写一下dijkstra的算法博客 dijkstra链接在这← 今天来更floyd算法,感觉非常简单果然暴力才是解决一切的王道 一.总体思想 floyd算法就是每一次从邻接矩 ...

  5. Django之AJAX简单使用

    AJAX简介: AJAX(Asynchronous Javascript And XML)翻译成中文就是“异步的Javascript和XML”.即使用Javascript语言与服务器进行异步交互,传输 ...

  6. Djano之ORM多表查询操作

    # 把 model 转化为 迭代器去循环 MODEL.objects.all().iterator() # 等同于 values, values_list, 但是 only 这种方式 获取字段属性依旧 ...

  7. 第一章 Python 基础

    1. 为什么学习 Python? 答题路线:a.python的优点,b.python的应用领域广 具体: 优点 1.python语法非常优雅,简单易学 2.免费开源 3.跨平台,可以自由移植 4.可扩 ...

  8. Redis设计原理简介

    学完MySQL InnoDB之后,又开始学习和研究Redis. 首先介绍下书:<Redis设计与实现>第二版 黄健宏著,机械工业出版社,388页,基于redis3.0版本.版本有点低,这个 ...

  9. BZOJ1040 基环森林 找环+基础树形DP

    1040: [ZJOI2008]骑士 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 4752  Solved: 1831[Submit][Status ...

  10. POJ3255

    题目链接:http://poj.org/problem?id=3255 解题思路: 昨晚两点多睡不着翻起来刷<挑战>的题,结果遇到这道求次短路的题,一脸懵逼.想了半小时没什么思路就看他的解 ...