JSON序列化:将实体类对象转为JSON字符串
JSON反序列化:将JSON字符串转为实体类
jackson作为Spring MVC和Spring Boot默认的JSON解析器,其与gson的工作原理不一样。
jackson通过调用实体类每个属性get/set方法进行注入,而gson则是通过设置每个属性为可访问后注入。
jackson工作原理大致如下
//获取Class对象
Class<Order.OrderStatus> orderStatusClass = Order.OrderStatus.class;
//创建实例
Order.OrderStatus orderStatus=orderStatusClass.newInstance();
//获取实体类某个属性的get方法
Method setIsAllocated = orderStatusClass.getDeclaredMethod("setIsDelayed", Boolean.class);
//调用该方法,把值设置为true
setIsAllocated.invoke(orderStatus,true);
gson工作原理大致如下
//获取Class对象
Class<Order.OrderStatus> orderStatusClass = Order.OrderStatus.class;
//创建实例
Order.OrderStatus orderStatus=orderStatusClass.newInstance();
//获取Field对象
Field isDelayed = orderStatusClass.getDeclaredField("isDelayed");
//设置属性可写
isDelayed.setAccessible(true);
//注入值
isDelayed.set(orderStatus,true);
ObjectMapper objectMapper=new ObjectMapper();
String json="{\"isAllocated\":true,\"isCheckout\":true}";
try {
//将JSON字符串转为实体类
orderStatus = objectMapper.readValue(json, Order.OrderStatus.class);
}
catch (JsonProcessingException e) {
e.printStackTrace();
}
有一个实体类
public static class OrderStatus{
private Boolean isDelayed;
private Boolean isBulk;
private Boolean isCheckout;
private Boolean isAllocated;
//构造器以及get和set方法省略.......
}
现在从前端传过来的是不定字段的JSON字符串,比如
"{"isAllocated":true,"isCheckout":true}"
,也可能是"{"isAllocated":true,"isBulk":true}"
,即JSON字符串中永远只有值为true
的字段,
如果使用readValue()
默认的JSON解析器进行解析,得到的结果中不存在字段值为null
,比如"{"isAllocated":true,"isCheckout":true}"
的到的是
如果想将null值的字段解析为false应该如何处理?
jackson库中有一个抽象类JsonDeserializer
,其中要实现一个抽象方法deserialize
public abstract T deserialize(JsonParser var1, DeserializationContext var2) throws IOException, JacksonException;
我们定义自己的Deserializer并继承JsonDeserializer
public class OrderStatusDeserializer extends JsonDeserializer<Order.OrderStatus> {
@Override
public Order.OrderStatus deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException {
//解析Json
TreeNode treeNode = jsonParser.getCodec().readTree(jsonParser);
Set<String> fieldSet=new HashSet<>();
//遍历Json字符串里面存在属性,并存在set中
Iterator<String> iterator = treeNode.fieldNames();
while(iterator.hasNext()){
fieldSet.add(iterator.next());
}
//创建实例
Order.OrderStatus orderStatus=new Order.OrderStatus();
//获取Class实例
Class<Order.OrderStatus> orderStatusClass = Order.OrderStatus.class;
//获取Class的所有属性
Field[] declaredFields = orderStatusClass.getDeclaredFields();
for(Field field:declaredFields){
field.setAccessible(true);
//如果JSON字符串存在该属性则设置true
if(fieldSet.contains(field.getName())) {
try {
field.set(orderStatus,true);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
//否则设置false
else {
try {
field.set(orderStatus,false);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
return orderStatus;
}
}
将OrderStatusDeserializer
进行注册
@Test
void testMyDeserializer() throws JsonProcessingException {
String json="{\"isAllocated\":true,\"isCheckout\":true}";
ObjectMapper objectMapper=new ObjectMapper();
//通过simpleModule进行注册
SimpleModule simpleModule=new SimpleModule();
simpleModule.addDeserializer(Order.OrderStatus.class, new OrderStatusDeserializer());
//注册simpleModule
objectMapper.registerModule(simpleModule);
Order.OrderStatus orderStatus = objectMapper.readValue(json, Order.OrderStatus.class);
System.out.println(orderStatus);
}
也可以通过注解进行注册
@JsonDeserialize(using= OrderStatusDeserializer.class)
public static class OrderStatus{
private Boolean isDelayed;
private Boolean isBulk;
private Boolean isCheckout;
private Boolean isAllocated;
}
@Test
void testMyDeserializer() throws JsonProcessingException {
String json="{\"isAllocated\":true,\"isCheckout\":true}";
ObjectMapper objectMapper=new ObjectMapper();
//使用注解注册后直接调用即可
Order.OrderStatus orderStatus = objectMapper.readValue(json, Order.OrderStatus.class);
System.out.println(orderStatus);
}
得到的结果为
可以看到:JSON字符串中不存在的字段,都设置为false了
前面提到jackson默认通过反射,使用get/set方法进行注入,那么在此之前必定会调用空参构造函数构造一个实例,如
//获取Class对象
Class<Order.OrderStatus> orderStatusClass = Order.OrderStatus.class;
//创建实例
Order.OrderStatus orderStatus=orderStatusClass.newInstance();
然后再调用JSON字符串中存在的字段的set方法。那么如果在构造器初始化时,默认设置每个属性都为false,然后任由jackson调用对应的set方法设置true,不也一样能达到同样的效果吗?
修改空参构造函数,另外取消自定义的JsonDeserializer
public OrderStatus() {
System.out.println("jackson调用了空参构造函数");
this.isDelayed=false;
this.isBulk=false;
this.isCheckout=false;
this.isAllocated=false;
}
结果证明确实调用了空参构造,另外同样能实现将null设置为false