基本介绍
FastJson、JackJson 以及 Gson 是 Java 生态圈中三种常用的 Json 解析器,它们均可将 Java 对象序列化为 Json 格式的字符串,也可将 Json 字符串反序列化为 Java 对象。下面我们讨论一下三者在序列化和反序列化操作中的一些区别。
Spring Boot 默认使用 JackJson 作为 Json 解析器。
序列化
FastJson 和 JackJson 会根据 getter 方法(如 getXXX)或 is 方法(如 isXXX)获取属性名(XXX),然后调用 getter 方法或 is 方法获取属性值,最终将属性和属性值添加到 Json 字符串中。而 Gson 则是通过遍历实体类中的所有属性并直接获取属性值(未调用 getter 方法)来完成序列化操作。
isXXX 方法生效的前提条件是其返回值的类型为 boolean 或 Boolean。
引入 FashJson 和 Gson 的依赖:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.58</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.9</version>
</dependency>
创建实体类 User:
public class User {
private Integer id;
private String name;
public void setId(Integer id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
}
测试:
public class Test {
public static void main(String[] args) throws JsonProcessingException {
User user = new User();
user.setId(1);
user.setName("John同学");
// FastJson 序列化
String json1 = JSONObject.toJSONString(user);
System.out.println("FastJson 解析结果: " + json1);
// Gson 序列化
Gson gson = new Gson();
String json2 = gson.toJson(user);
System.out.println("Gson 解析结果: " + json2);
// JackJson 序列化
ObjectMapper objectMapper = new ObjectMapper();
String json3 = objectMapper.writeValueAsString(user);
System.out.println("JackJson 解析结果: " + json3);
}
}
测试结果:
FastJson 解析结果: {}
Gson 解析结果: {"id":1,"name":"John同学"}
Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class com.example.test.User and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS)
在 User 类中,我们并未添加任何的 getter 方法,因此 FastJson 返回了一个 "空串"。由于 Gson 不依赖 getter,所以它可以解析出完整的属性以及属性值。默认情况下,若 JackJson 未获取到任何属性(通过 getter 方法),那么程序将抛出异常。根据提示,我们可以通过关闭 SerializationFeature.FAIL_ON_EMPTY_BEANS
来忽略该异常。
关闭 SerializationFeature.FAIL_ON_EMPTY_BEANS
:
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
String json3 = objectMapper.writeValueAsString(user);
System.out.println("JackJson 解析结果: " + json3);
测试结果:
FastJson 解析结果: {}
Gson 解析结果: {"id":1,"name":"John同学"}
JackJson 解析结果: {}
下面我们为 User 类添加 getter 方法和 is 方法,再次测试序列化操作:
public boolean isRemoved() {
return false;
}
public Integer getId() {
return id;
}
public String getName() {
return name;
}
测试结果:
FastJson 解析结果: {"id":1,"name":"John同学","removed":false}
Gson 解析结果: {"id":1,"name":"John同学"}
JackJson 解析结果: {"id":1,"name":"John同学","removed":false}
可见,FashJson 和 JackJson 均解析出了 removed 属性,虽然该属性并未在 User 类中定义,但由于我们添加了 isRemoved 方法且该方法的返回值类型为 boolean,因此 removed 会出现在 Json 串中。反观 Gson,其仅会将 User 类中定义的属性进行序列化。
反序列化
FastJson 和 JackJson 会根据 Json 字符串中的属性,在实体类中查找对应的 setter 方法来为该属性赋值。若未查找到属性对应的 setter 方法,那么 FastJson 会忽略该属性,Jackson 则会抛出异常。相比之下,Gson 会根据 Json 串中的属性以及属性值来填充实体类中对应的属性。
测试:
public class Test {
public static void main(String[] args) throws JsonProcessingException {
// FastJson 反序列化
String json = "{\"id\":1,\"name\":\"John同学\",\"removed\":false}";
User user1 = JSONObject.parseObject(json, User.class);
System.out.println("FastJson 解析结果: " + user1);
// Gson 反序列化
Gson gson = new Gson();
User user2 = gson.fromJson(json, User.class);
System.out.println("Gson 解析结果: " + user2);
// JackJson 反序列化
ObjectMapper objectMapper = new ObjectMapper();
User user3 = objectMapper.readValue(json, User.class);
System.out.println("JackJson 解析结果: " + user3);
}
}
测试结果:
FastJson 解析结果: User{id=1, name='John同学'}
Gson 解析结果: User{id=1, name='John同学'}
Exception in thread "main" com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "removed" (class com.example.test.User), not marked as ignorable (2 known properties: "id", "name")
上述代码中,我们在 Json 串中添加了一个 User 类中没有的属性,即 removed。FastJson 和 Gson 均会将该属性忽略,而 JackJson 则抛出了异常,该异常提示 "removed 为不能识别的属性"。当然,我们也可以通过配置 ObjectMapper 来忽略该异常:
// JackJson 反序列化
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
User user3 = objectMapper.readValue(json, User.class);
System.out.println("JackJson 解析结果: " + user3);
测试结果:
FastJson 解析结果: User{id=1, name='John同学'}
Gson 解析结果: User{id=1, name='John同学'}
JackJson 解析结果: User{id=1, name='John同学'}
虽然 FastJson 和 JackJson 在反序列化时均会依赖 setter 方法,但二者之间也存在一些区别。如果我们在实体类中未添加某个属性的 setter 方法,那么 FastJson 将不会为该属性赋值,而 JackJson 则会进一步查找同名的属性,接着完成赋值操作。下面我们注释掉 User 类中的 setName 方法:
// public void setName(String name) {
// this.name = name;
// }
再次测试反序列化操作:
FastJson 解析结果: User{id=1, name='null'}
Gson 解析结果: User{id=1, name='John同学'}
JackJson 解析结果: User{id=1, name='John同学'}