Jackson替换FastJson的注意点(坑)
一、Jackson与FastJson的不同默认配置
1、序列化时Jackson与FastJson的默认配置区别
配置 | jackSon | FastJson | Jackson统一配置代码 |
---|---|---|---|
默认是否输出transient字段 | 输出 | 不输出 | mapper.configure(MapperFeature.PROPAGATE_TRANSIENT_MARKER, true); |
默认是否开启排序 | 不开启 | 开启 | mapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true); |
默认都是时间对象都是时间戳输出 | 是 | 是 | mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); |
测试代码:
@Data
@AllArgsConstructor
@NoArgsConstructor
static class User {
private int id;
private String name;
private Date birthDay;
private List feature;
private transient String idCard;
}
@Test
public void serial() {
User user = new User(10, "钟无常", new Date(),new LinkedList(),"350913156158164165x");
/*Jackon序列化*/
ObjectMapper mapper = new ObjectMapper(); // jackson的核心类
//默认都是时间对象都是时间戳输出
//mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
//默认输出transient字段,FastJson默认不输出
mapper.configure(MapperFeature.PROPAGATE_TRANSIENT_MARKER, true);
//默认不开启排序,FastJson根据字典排序(指定order除外)
mapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true);
// java对象转json字符串
String jacksonStr;
try {
jacksonStr = mapper.writeValueAsString(user);
System.out.println("Jackson对象转Json:" + jacksonStr);
} catch (JsonProcessingException e) {
System.out.println("解析失败");
}
/*FastJson序列化*/
String fastJsonStr = JSON.toJSONString(user);
System.out.println("FastJson对象转Json:" + fastJsonStr);
}
2、反序列化时Jackson与FastJson的默认配置区别
配置 | Jackson | FastJson | Jackson统一配置代码 |
---|---|---|---|
是否识别不带引号的key | 关闭 | 开启 | mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true); |
是否识别单引号的key | 关闭 | 开启 | mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true); |
浮点数默认类型 | double | BigDecimal | mapper.configure(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS, true); |
是否无视JavaBean中不存在的字段 | 异常 | 无视 | objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); |
默认开启Json@type指定类型解析 | 是 | 否 | mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); |
默认key或value是null时也输出(只对VO起作用,Map List不起作用) | 输出 | 不输出 | mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY); |
key是否主动常量池交换 | 否 | 是 | FastJson会主动调用key.intern() |
枚举变量名 | 否 | 是 | FastJson获取枚举名时会从枚举name字段获取 |
测试代码:
String str = "{'Switch_1':{\"null\":null,\"date\":2021-06-01T12:23:00.235+08:00,\"age\":1.22},\"女生\":{\"id\":null,\"name\":\"李四\",\"age\":24}}";
@Test
public void deSerial() {
/*Jackson*/
ObjectMapper mapper = new ObjectMapper();
/*区别FastJson的配置,并赋予调整至和FastJson一致配置代码*/
/*反序列化*/
//是否识别不带引号的key-默认关闭,FastJson默认开启
mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
//是否识别单引号的key-默认关闭,FastJson默认开启
mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
//浮点数类型-默认double,FastJson默认BigDecimal
mapper.configure(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS, true);
//默认开启Json@type指定类型解析,FastJson默认关闭
//mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
/*序列化*/
//默认key或value是null时也输出(只对VO起作用,Map List不起作用),FastJson默认不输出
mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
Map<String, User> map2 = null;
try {
map2 = mapper.readValue(str, new TypeReference<Map>() {
});
} catch (IOException e) {
System.out.println("解析失败");
}
System.out.println("Jackson字符串转map:" + map2);
/*FastJson*/
Map map = JSON.parseObject(str);
/*区别Jackson的配置*/
//key字符串默认会调用key.intern()加入常量池
//序列化枚举时会使用枚举名-默认开启
System.out.println("FastJson字符串转map:" + map);
}
二、引用依赖
Spring 支持的三个JSON库(Gson、Jackson、JSON-B)中,Jackson是首选默认库,所以在引用Jackson时Spring项目不需要额外引用依赖。
1、Springboot
spring-boot-starter-web间接引入了Jackson依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
2、Web Starter
web starter中依赖json starter:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-json</artifactId>
</dependency>
2、Maven项目
Maven项目中以来Jackson(version移步去仓库选)
Jackson的Maven地址
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jdk8</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-parameter-names</artifactId>
</dependency>
三、其他坑位
1、非明确转换类型
在断点处我们的预期结果应该是testFastjson,打jackson中是"testFastjson",而在FastJson中它是没有引号的。
其主要原因是指定的默认解析类型是ObjectNode.class,该类型实际解析类型是LinkedHashMap,value值内容将会被完整保留。
故在使用时应结合业务指定具体类型。
2、未知JavaBean字段异常
在FastJson和Gson中解析到映射不上的字段时并不会报错,而Jackson就会报错,该默认配置在会影响到不规范的前端请求,以导致报错。
解决方式:添加以下配置
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); //忽略未知字段
测试代码
@Data
@AllArgsConstructor
@NoArgsConstructor
static class User {
private int id;
private String name;
private Date birthDay;
private List feature;
private transient String idCard;
}
@Test
public void bugTest2() {
String jsonString="{\"id\":11,\n" +
" \"name\":\"钟无艳\",\n" +
" \"birthDay\":\"2021-06-01T12:23:00.235+08:00\",\n" +
" \"feature\":[],\n" +
" \"idCard\":\"35092312316514\",\n" +
"\"other\":null\n" +
"}";
//Jackson解析json
ObjectMapper objectMapper = new ObjectMapper();
//objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
try {
User user = objectMapper.readValue(jsonString, User.class);
System.out.println("Jackson解析结果:"+user);
} catch (IOException e) {
System.err.println(e.getMessage());
}
//FastJson解析
User user1 = JSON.parseObject(jsonString, User.class);
System.out.println("FastJson解析结果:"+user1);
}
异常结果
–eof–