Bootstrap

Jackson替换FastJson的注意点(坑)


Jackson替换FastJson的注意点(坑)


一、Jackson与FastJson的不同默认配置

1、序列化时Jackson与FastJson的默认配置区别
配置jackSonFastJsonJackson统一配置代码
默认是否输出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的默认配置区别
配置JacksonFastJsonJackson统一配置代码
是否识别不带引号的key关闭开启mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
是否识别单引号的key关闭开启mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
浮点数默认类型doubleBigDecimalmapper.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–

悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;