java系列 - fastjson, jackjson, Gson三者异同

起源

当后端接口向前端返回数据时,有时response数据是null, 十分不利于前端处理。

因此为了统一格式,需要返回在:

  • 接口返回得数据是String类型时,不返回null,而返回 “”
  • 接口返回得数据是Map类型时,不返回null,而返回 {}
  • 接口返回得数据是List类型时,不返回null,而返回 []

为了解决这个问题,就到了选择json序列化工具得时候,目前有三种工具:

  • fastjson 是阿里巴巴2011年的开源 json 解析库
  • jackjson 是 spring boot 官方内置得 json 解析库
  • Gson 是 Google 官方2008年开源得 json 解析库

如何选择?

选择 jackson.( 2.13.0+版本)速度与性能安全,功能完善适中得选项。

如何使用?

添加坐标

<properties>
	......
    <jackson.version>2.13.2</jackson.version>
    ......
</properties>

</dependencies>
	...
   <!-- json序列化 工具类 -->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>${jackson.version}</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-annotations</artifactId>
        <version>${jackson.version}</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
        <version>${jackson.version}</version>
    </dependency>
    ...
</dependencies>

全局配置文件:JacksonConfig.java

package com.springblog.config;


import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Collection;

/**
 * <p>
 * json序列化
 * </p>
 *
 * @author ifredom@gmail.com
 * @since 2022-05-09
 */

@Configuration
public class JacksonConfig {
    @Bean
    @Primary
    @ConditionalOnMissingBean(ObjectMapper.class)
    public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
        ObjectMapper objectMapper = builder.createXmlMapper(false).build();
        objectMapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>() {
            @Override
            public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
                String fieldName = jsonGenerator.getOutputContext().getCurrentName();
                try {
                    Field field = jsonGenerator.getCurrentValue().getClass().getDeclaredField(fieldName);
                    if (CharSequence.class.isAssignableFrom(field.getType())) {
                        // 字符串空值 “”
                        jsonGenerator.writeString("");
                    } else if (Collection.class.isAssignableFrom(field.getType())) {
                        //列表型空值返回[]
                        jsonGenerator.writeStartArray();
                        jsonGenerator.writeEndArray();
                    } else {
                        //map类型空值,或者bean对像,返回{}
                        jsonGenerator.writeStartObject();
                        jsonGenerator.writeEndObject();
                    }
                } catch (NoSuchFieldException ignoredException) {
                    // 忽略该异常
                }
            }
        });
        return objectMapper;
    }
}

原理讲解

jackson有三个核心模块,如下,括号内是maven的artifactId:

  • Stre
  • aming(jackson-core):低阶API库,提供流式解析工具JsonParser,流式生成工具JsonGenerator;
  • Annotations(jackson-annotations):jackson注解;
  • Databind (jackson-databind):基于java对象的序列化、反序列化能力,需要前面两个模块的支持才能实现;

当我们用jackson做JSON操作时,常用的是 Databind 模块 的 ObjectMapper 类,对处于核心位置的jackson-core反倒是很少直接用到,那么该模块有什么作用呢?

jackson-core 中,有一个叫做 BeanSerializer 的功能类,其 serialize 方法负责 将java对象转为JSON字符串,方法中的处理逻辑就是调用JsonGenerator提供的API,而JsonGenerator就是jackson-core中负责序列化的主要功能类
在这里插入图片描述

日常使用序列化功能

  1. 将JSON转换为Java对象
  • 将json字符串序列化为Java对象
    public void jsonDemo() {
        String jsonString = "{ \"title\" : \"json博客标题\", \"description\" : \"json文章描述\" }";
        
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            BlogEntity blog = objectMapper.readValue(jsonString, BlogEntity.class);

            System.out.println("car brand = " + blog.getTitle());
            System.out.println("car doors = " + blog.getDescription());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

jackjson支持从各种类型数据中进行序列化为java对象,支持类型如下:

  • json字符串
ObjectMapper objectMapper = new ObjectMapper();
String json =
        "{ \"title\" : \"标题\", \"description\" :\"描述\" }";
Car car = objectMapper.readValue(json, BlogEntity.class);
  • 文件file
ObjectMapper objectMapper = new ObjectMapper();
File file = new File("data/blog.json");
BlogEntity blog = objectMapper.readValue(file, BlogEntity.class);
  • 字符输入流StringReader
ObjectMapper objectMapper = new ObjectMapper();
String json =
        "{ \"title\" : \"标题\", \"description\" :\"描述\" }";
Reader reader = new StringReader( json);
BlogEntity blog = objectMapper.readValue(file, BlogEntity.class);
  • JSON via URL
ObjectMapper objectMapper = new ObjectMapper();
URL url = new URL("file:data/blog.json");
BlogEntity blog = objectMapper.readValue(url, BlogEntity.class);
  • 字节输入流FileInputStream
ObjectMapper objectMapper = new ObjectMapper();
InputStream input = new FileInputStream("data/blog.json");
BlogEntity blog = objectMapper.readValue(input , BlogEntity.class);
  • 字节数组 List<Bytes>
ObjectMapper objectMapper = new ObjectMapper();
byte[] bytes =
        "{ \"title\" : \"标题\", \"description\" : \“描述\” }".getBytes("UTF-8");
BlogEntity blog = objectMapper.readValue(bytes , BlogEntity.class);
  • JSON数组字符串 :
ObjectMapper objectMapper = new ObjectMapper();
 String jsonArray = "[{\"title\":\"标题\"}, {\"description\":\"描述\"}]"
 // 转换为 Array
 BlogEntity[] blogs = objectMapper.readValue(jsonArray  , BlogEntity.class);

// 转换为List
 List<BlogEntity> blogs2 = objectMapper.readValue(jsonArray, new TypeReference<List<BlogEntity>>(){});
  • JSON字符串Map
ObjectMapper objectMapper = new ObjectMapper();
String jsonObject = "{\"brand\":\"ford\", \"doors\":5}";
Map<String, Object> jsonMap = objectMapper.readValue(jsonObject,
    new TypeReference<Map<String,Object>>(){});
  1. 将java对象转换为json字符串
 BlogEntity blogEntity = new BlogEntity();
 blogEntity.setTitle("新博客");
 blogEntity.setDescription("文章描述");
        
ObjectMapper objectMapper = new ObjectMapper();

String str = objectMapper.writeValueAsString(blogEntity);
System.out.println(str);

日常使用序列化注解

注解用法
@JsonProperty用于属性,把属性的名称序列化时转换为另外一个名称。示例:
@JsonProperty(“birth_date”)
private Date birthDate;
@JsonFormat用于属性或者方法,把属性的格式序列化时转换成指定的格式。示例:
@JsonFormat(timezone = “GMT+8”, pattern = “yyyy-MM-dd HH:mm”) )
public Date getBirthDate(){ }
@JsonPropertyOrder用于类, 指定属性在序列化时 json 中的顺序 , 示例:)
@JsonPropertyOrder({ “birth_Date”, “name” })
public class Person(){ }
@JsonCreator用于构造方法,和 @JsonProperty 配合使用,适用有参数的构造方法。 示例:
@JsonCreator
public Person(@JsonProperty(“name”) String name) {
  …
}
@JsonAnySetter用于属性或者方法,设置未反序列化的属性名和值作为键值存储到 map 中 )
@JsonAnySetter
public void set(String key, Object,value) {
   map.put(key, value);
}
@JsonAnyGetter用于方法 ,获取所有未序列化的属性 public Map<String, Object> any() { return map; }

参考资料

jackjson官方文档
jackjson方法细节
自定义解析


------ 如果文章对你有用,感谢 >>>点赞 | 收藏 <<<

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值