1.Jackson基础信息
Jackson是当前用得比较广泛的序列化和反序列化 json 的 Java 开源框架。Jackson社区相对比较活跃,更新速度也比较快,从Github中的统计来看,Jackson 是最流行的 json 解析器之一 。 Spring MVC和Spring Boot的默认 json解析器便是 Jackson。Jackson 的核心模块由三部分组成:
-
jackson-core: 核心包,提供基于"流模式"解析的相关 API,它包括 JsonPaser 和 JsonGenerator。 Jackson内部实现正是通过高性能的流模式API的JsonGenerator 和 JsonParser 来生成和解析 json。
-
jackson-annotations: 注解包,提供标准注解功能。
-
jackson-databind: 数据绑定包, 提供基于"对象绑定" 解析的相关 API ( ObjectMapper ) 和"树模型" 解析的相关 API (JsonNode);基于"对象绑定" 解析的 API 和"树模型"解析的 API 依赖基于"流模式"解析的 API。
maven依赖
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.1</version>
</dependency>
jackson-databind 依赖 jackson-core 和 jackson-annotations,当添加 jackson-databind 之后, jackson-core 和 jackson-annotations 也随之添加到 Java 项目工程中。在添加相关依赖包之后,就可以使用 Jackson。
2.ObjectMapper配置信息
Jackson提供了ObjectMapper来供程序员“定制化控制”序列化、反序列化的过程。objectMapper在调用writeValue()序列化 或 调用readValue()反序列化方法之前,往往需要设置 ObjectMapper 的相关配置信息,这些配置信息作用在 java 对象的所有属性上,表示在进行序列化和反序列化时进行一些特殊的处理。ObjectMapper的相关的配置属性主要在Feature这个枚举类里,Feature的源码和其作用如下:
public enum Feature {
// Low-level I/O handling features:支持低级I/O操作特性
* 自动关闭源:默认true_启用(即:解析json字符串后,自动关闭输入流)
* 该特性,决定了解析器是否可以自动关闭非自身的底层输入源
* 1.禁用:应用程序将分开关闭底层的{@link InputStream} and {@link Reader}
* 2.启用:解析器将关闭上述对象,其自身也关闭,此时input终止且调用{@link JsonParser#close}
AUTO_CLOSE_SOURCE(true),
* Support for non-standard data format constructs:支持非标准数据格式的json
* 该特性,决定了解析器是否可以解析含有Java/C++注释样式的JSON串(如:/*或//的注释符)
* 默认false:不解析含有注释符(即:true时能解析含有注释符的json串)
* 注意:该属性默认是false,因此必须显式允许,即通过JsonParser.Feature.ALLOW_COMMENTS 配置为true。
ALLOW_COMMENTS(false),
* 默认false:不解析含有另外注释符
* 该特性,决定了解析器是否可以解析含有以"#"开头并直到一行结束的注释样式(这样的注释风格通常也用在脚本语言中)
* 注意:标准的json字符串格式没有含有注释符(非标准),然而则经常使用<br>
ALLOW_YAML_COMMENTS(false),
* 这个特性决定parser是否能解析属性名字没有加双引号的json串(这种形式在Javascript中被允许,但是JSON标准说明书中没有)。
*(默认情况下,标准的json串里属性名字都需要用双引号引起来。比如:{age:12, name:"曹操"}非标准的json串,默认不能解析)
* 注意:由于JSON标准上需要为属性名称使用双引号,所以这也是一个非标准特性,默认是false的。
* 同样,需要设置JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES为true,打开该特性。
ALLOW_UNQUOTED_FIELD_NAMES(false),
* 默认false:不解析含有单引号的字符串或字符
* 该特性,决定了解析器是否可以解析单引号的字符串或字符(如:单引号的字符串,单引号'\'')
* 注意:可作为其他可接受的标记,但不是JSON的规范
ALLOW_SINGLE_QUOTES(false),
* 允许:默认false不解析含有结束语控制字符
* 该特性,决定了解析器是否可以解析结束语控制字符(如:ASCII<32,包含制表符\t、换行符\n和回车\r)
* 注意:设置false(默认)时,若解析则抛出异常;若true时,则用引号即可转义
ALLOW_UNQUOTED_CONTROL_CHARS(false),
* 可解析反斜杠引用的所有字符,默认:false,不可解析
ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER(false),
* 可解析以"0"为开头的数字(如: 000001),解析时则忽略0,默认:false,不可解析,若有则抛出异常
ALLOW_NUMERIC_LEADING_ZEROS(false),
* 可解析非数值的数值格式(如:正无穷大,负无穷大,Integer或浮点数类型属性赋值NaN的JSON串)
* 该特性允许parser可以识别"Not-a-Number" (NaN)标识集合作为一个合法的浮点数。
* 默认:false,不能解析
ALLOW_NON_NUMERIC_NUMBERS(false),
* 默认:false,不检测JSON对象重复的字段名,即:相同字段名都要解析
* true时,检测是否有重复字段名,若有,则抛出异常{@link JsonParseException}
* 注意:检查时,解析性能下降,时间超过一般情况的20-30%
STRICT_DUPLICATE_DETECTION(false),
* 默认:false,底层的数据流(二进制数据持久化,如:图片,视频等)全部被output,若读取一个位置的字段,则抛出异常
* true时,则忽略未定义
IGNORE_UNDEFINED(false),
* 默认:false,JSON数组中不解析漏掉的值,若有,则会抛出异常{@link JsonToken#VALUE_NULL}
* true时,可解析["value1",,"value3",]最终为["value1", null, "value3", null]空值作为null
ALLOW_MISSING_VALUES(false);
(1)忽略未知字段
默认情况下Jackson要求JSON字符串消息 和 Java类中的字段必须一一相对应,否则反序列解析JSON字符串时会报错。当然也可以通过配置Jackson的ObjectMapper属性使Jackson在反序列化时,忽略在 json字符串中存在但 Java 对象不存在的属性。
#1)java对象属性
@Data
public class User implements Serializable {
private Integer age;
private String name;
#2)需要反序列化JSON字符串
public static void main(String[] args) throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
String json = "{\"age\":10,\"name\":\"曹操\",\"class\":\"语文\"}";
#会报错:因为json字符串的属性和java对象属性没有一一对应
User user = objectMapper.readValue(json, User.class);
System.out.println(user);
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "class"
#3)解决办法:忽略未知字段 DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES默认是true。
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
(2)属性为NULL不被序列化
如果java对象的属性为NULL则不参与序列化,即java对象序列化后的json串里不出现属性为null的字段。该功能可以使用@JsonInclude注解,也可以设置objectMapper属性。
#1)java对象属性
@Data
public class User implements Serializable {
private Integer age;
private String name;
#2)序列化属性有为null的对象
public static void main(String[] args) throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
User user = new User();
user.setAge(10);
String string = objectMapper.writeValueAsString(user);
System.out.println(string);
#输出:json字段带null
{"age":10,"name":null}
#3)解决办法:关闭属性为NULL还序列化功能,默认是开启。
@JsonInclude(JsonInclude.Include.NON_NULL) 注解可以加到类或属性上,加到类上表示多所有属性都有效。objectMapper.setSerializationInclusion(Include.NON_NULL)
(3)对象属性为空时,默认序列化会失败
默认情况下ObjectMapper序列化没有属性的空对象时会抛异常。可以通过SerializationFeature.FAIL_ON_EMPTY_BEANS设置当对象没有属性时,让其序列化能成功,不抛异常。
#1)java对象属性:没有任何属性
@Data
public class User implements Serializable {
#2)默认序列化失败,会抛异常
public static void main(String[] args) throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
#默认是true,空对象不让序列化
//objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, true);
User user = new User();
String string = objectMapper.writeValueAsString(user); #会抛异常
System.out.println(string);
#抛异常:com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class com.igetcool.common.model.User and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS)
#3)解决办法:关闭空对象不让序列化功能
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
(4)json字符串值带反斜杠("\"),默认反序列化会失败
当反序列化的JSON串里带有反斜杠时,默认objectMapper反序列化会失败,抛出异常Unrecognized character escape。可以通过Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER来设置当反斜杠存在时,能被objectMapper反序列化。
#1)java对象属性
@Data
public class User implements Serializable {
private Integer age;
private String name;
#2)反序列化字符串带反斜杠,会抛异常。
public static void main(String[] args) throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
#objectMapper默认是false
objectMapper.configure(Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER, false);
#name的值带反斜杠,默认情况下objectMapper解析器会反序列化失败
String json = "{\"age\":10,\"name\":\"曹\\操\"}";
User user = objectMapper.readValue(json, User.class);
System.out.println(user);
#输出:com.fasterxml.jackson.databind.JsonMappingException: Unrecognized character escape '操' (code 25805 / 0x64cd)
#3)解决办法:设置解析能识别JSON串里的注释符
objectMapper.configure(Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER, true);
(5)json字符串带注释符,默认反序列化会失败
当json字符串里带注释符时,默认情况下解析器不能解析。Feature.ALLOW_COMMENTS特性决定解析器是否允许解析使用Java/C++ 样式的注释(包括'/'+'*' 和'//' 变量)。
#1)例如:如下反序列化JSON串里带注释,默认情况下objectMapper不能反序列化解析成对象,需要设置ALLOW_COMMENTS。
"age": 10
//"name": "曹操"
#2)默认情况下,上面这种带注释的JSON串,objectMapper解析器是不能解析的。
public static void main(String[] args) throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
#默认是false,不能解析带注释的JSON串
objectMapper.configure(Feature.ALLOW_COMMENTS, true);
String json = "{"
+"\"age\"" + ":" + 10 +
"/*" + "," +
"\"name\"" + ":" + "\"曹操\"*/" +
//Feature.ALLOW_COMMENTS打开时,JSON里的注释符会被过滤掉,解析器能解析
User user = objectMapper.readValue(json, User.class);
System.out.println(user);
#输出:User(age=10, name=null)
(6)Json字符串里数字类型值为正无穷、负无穷或NaN时,默认反序列化会失败
objectMapper解析器默认不能识别识别 "Not-a-Number" (NaN)标识集合作为一个合法的浮点数 或 一个int数,objectMapper默认该功能是关闭的。
#1)例如:反序列化的JSON串里包含了数字类型的属性值为NaN,默认objectMapper解析器是不能解析的。
"age": NaN,
"name": "曹操"
#java对象属性:age是数字类型
@Data
public class User implements Serializable {
private Integer age;
private String name;
#2)数字类型 或 浮点类型值为NaN时,默认objectMapper解析器是不能解析的,需要开启Feature.ALLOW_NON_NUMERIC_NUMBERS。
public static void main(String[] args) throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(Feature.ALLOW_NON_NUMERIC_NUMBERS, true);
String json = "{\"age\":NaN, \"name\":\"曹操\"}";
User user = objectMapper.readValue(json, User.class);
System.out.println(user);
//输出是无穷大
System.out.println(0.0/0.0);
User(age=NaN, name=曹操)
#注意:浮点类型 或 数字类型都可以接受NaN值,反序列化需要开启Feature.ALLOW_NON_NUMERIC_NUMBERS
(7)反序列化可解析以"0"为开头的数字
默认情况下objectMapper解析器是不能解析以"0"为开头的数字,需要开启Feature.ALLOW_NUMERIC_LEADING_ZEROS才能使用。
#1)例如java对象属性age是int类型
@Data
public class User implements Serializable {
private Integer age;
private String name;
#2)JSON字符串的age值是"0"为开头的数字,objectMapper默认是不能解析的
public static void main(String[] args) throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(Feature.ALLOW_NUMERIC_LEADING_ZEROS, true);
//“0”开头的数字
String json = "{\"age\":0012, \"name\":\"曹操\"}";
User user = objectMapper.readValue(json, User.class);
System.out.println(user);
#输出:User(age=12, name=曹操)
#注意:除了int类型,浮点数也一样。
(8)Json反序列化可以解析单引号包住的属性名称和字符串值
parser解析器默认情况下不能识别单引号包住的属性和属性值,默认下该属性也是关闭的。需要设置JsonParser.Feature.ALLOW_SINGLE_QUOTES为true。
#1)objectMapper默认情况下是不能解析带单引号的json串的,需要开启JsonParser.Feature.ALLOW_SINGLE_QUOTES属性
public static void main(String[] args) throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
#需要开启单引号解析属性,默认是false
objectMapper.configure(Feature.ALLOW_SINGLE_QUOTES, true);
String json = "{'age':12, 'name':'曹操'}";
User user = objectMapper.readValue(json, User.class);
System.out.println(user);
#输出:如果Feature.ALLOW_SINGLE_QUOTES设置为false时,解析器会解析失败
User(age=12, name=曹操)
(9)反序列Json字符串中包含制控制字符
Feature.ALLOW_UNQUOTED_CONTROL_CHARS该特性决定parser是否允许JSON字符串包含非引号控制字符(值小于32的ASCII字符,包含制表符\t、换行符\n和回车\r)。 如果该属性关闭,则如果遇到这些字符,则会抛出异常。
#默认情况下parser解析器是不能解析包含控制字符的json字符串,需要设置ALLOW_UNQUOTED_CONTROL_CHARS属性
#1)处理问题:JSON串里属性或属性值包含控制字符,解析器能解析。
"age": 12,
"name": "曹操\n"
#2)示列
public static void main(String[] args) throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
//开启单引号解析
objectMapper.configure(Feature.ALLOW_SINGLE_QUOTES, true);
//开启JSON字符串包含非引号控制字符的解析(\n换行符)
objectMapper.configure(Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
String json = "{'age':12, 'name':'曹操\n'}";
User user = objectMapper.readValue(json, User.class);
System.out.println(user);
#输出:输出有换行效果
User(age=12, name=曹操)
(10)反序列Json字符串中属性名没有双引号
默认情况下,标准的json串里属性名字都需要用双引号引起来。比如:{age:12, name:"曹操"}非标准的json串,解析器默认不能解析,需要设置Feature.ALLOW_UNQUOTED_FIELD_NAMES属性来处理这种没有双引号的json串。
#1)ALLOW_UNQUOTED_FIELD_NAMES处理的问题:属性名没有双引号的非标准json字符串,能被解析器识别。
age: 12,
name: "曹操"
#2)示列
public static void main(String[] args) throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
//开启单引号解析
objectMapper.configure(Feature.ALLOW_SINGLE_QUOTES, true);
//开启属性名没有双引号的非标准json字符串
objectMapper.configure(Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
String json = "{age:12, name:'曹操'}";
User user = objectMapper.readValue(json, User.class);
System.out.println(user);
User(age=12, name=曹操)
(11)时间格式化
Jackson对时间(Date)序列化的转换格式默认是时间戳,可以取消时间的默认时间戳转化格式;默认时间戳转化格式取消后在序列化时日期格式默认为 yyyy-MM-dd'T'HH:mm:ss.SSSZ,同时需要设置要展现的时间格式。
#(1)Jackson对时间(Date)序列化的转换格式默认是时间戳
public static void main(String[] args) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
//WRITE_DATES_AS_TIMESTAMPS属性值默认就是true
//mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, true);
String date = mapper.writeValueAsString(new Date());
System.out.println("默认是时间戳格式:" + date);
//输出:
默认是时间戳格式:1605848842390
#(2)取消时间的默认时间戳转化格式后,再序列化时日期格式默认为 yyyy-MM-dd'T'HH:mm:ss.SSSZ
public static void main(String[] args) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
//WRITE_DATES_AS_TIMESTAMPS属性值默认就是true
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
String date = mapper.writeValueAsString(new Date());
System.out.println("默认时格式:" + date);
//输出:
默认时格式:"2020-11-20T05:12:22.868+0000"
#(3)取消Jackson时间的默认时间戳转化格式,并设置需要展现的时间格式
public static void main(String[] args) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
//取消时间的转化格式默认是时间戳,可以取消,同时需要设置要表现的时间格式
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
String date = mapper.writeValueAsString(new Date());
System.out.println("指定时间时格式:" + date);
//输出:
指定时间时格式:"2020-11-20 13:14:56"
Springboot使用的默认json解析框架是jackjson框架,在格式化Model时对Date属性指定时间格式方式有以下三种方法:
#(1)配置文件:将spring的jackson日期格式写在配置文件中即可。
spring:
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
serialization:
write-dates-as-timestamps: false
#或者写成以下格式(主要取决于配置文件是什么格式的)
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8
spring.jackson.serialization.write-dates-as-timestamps=false
#(2)注解:在实体Date类型的字段上使用@JsonFormat注解格式化日期
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT + 8")
private Date createTime;
#(3)设置ObjectMapper属性:通过下面方式取消timestamps形式,并设置时间格式
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
最后是自己的一点感慨:又荒废一个多月没更新文章,坚持了几个月的博客习惯,又得重新开始。人的惰性太可怕了,在不知不觉中就让人养成了不好的习惯,最可怕的是自己还觉察、感知不到。今天看了一份统计局的报告,包含内容主要有三点:
-
(1)低收入群体平均每天看电视的时间,将近高收入群体的两倍。
-
(2)高收入群体平均每天阅读的时间,是低收入群体的3.2倍。
-
(3)高收入群体里有21%有很好的阅读习惯,低收入群体里有阅读行为的占6.6%。
看到这份报告联想到今年比较火的经济学的一本书《贫穷的本质》里的观点,基本是一致的,陷入贫穷陷阱的原因是那么的相似。
2020年11月22日 晚 于北京记
Jackson是当前用的比较广泛的,用来序列化和反序列化 json 的 Java 的开源框架。Jackson社区相对比较活跃,更新速度也比较快,从Github中的统计来看,Jackson 是最流行的 json 解析器之一 。 Spring MVC和Spring Boot的默认 json解析器便是 Jackson。Jackson 的核心模块由三部分组成:...
ObjectMapper
类(com.fasterxml.
jackson
.databind.
ObjectMapper
)是
Jackson
的主要类,它可以帮助我们快速的进行各个类型和
Json
类型的相互转换。
1、引入
Jackson
的依赖
<!-- 根据自己需要引入相关版本依赖。 -->
<dependency>
<groupId>com.fasterxml.
jackson
.core</groupId>
<artifactId>
介绍
Jackson
ObjectMapper
本文聚焦
Jackson
ObjectMapper
类————如何序列化
java
对象为
json
以及
json
字符串反序列化为
java
对象。
首先增加下列依赖:
compile group: 'com.fasterxml.
jackson
.core', name: '
jackson
-databind', version: '2.9.8'
该依赖...
Jackson
之
ObjectMapper
对象的使用一、简介二、
Jackson
的数据绑定三、
Jackson
ObjectMapper
对象示例四、反序列化五、序列化六、
Jackson
的日期格式化七、
Jackson
的树模型
Jackson
ObjectMapper
类(com.fasterxml.
jackson
.databind.
ObjectMapper
)是使用
Jackson
解析
JSON
最简单的方法。
Jackson
ObjectMapper
可以从字符串、流或文件解析
JSON
,并创建
Java
对象或对象图来
Simple On/off Features
Following on/off features are defined in DeserializationConfig.Feature (
Jackson
1.x) or
DeserializationFeature (
Jackson
2.x), and include:
<dependency>
<groupId>com.fasterxml.
jackson
.core</groupId>
<artifactId>
jackson
-databind</artifactId>
<version>2.9.9</version>
</dependency>
ObjectMapper
属性
配置
//序列化所有属性,对象中属性为null