jackson自定义反序列化器JsonDeserializer

1.JSON的序列化与反序列化

JSON序列化:将实体类对象转为JSON字符串
JSON反序列化:将JSON字符串转为实体类

2.jackson和gson

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);

3.jackson的简单使用

ObjectMapper objectMapper=new ObjectMapper();
String json="{\"isAllocated\":true,\"isCheckout\":true}";
try {
        //将JSON字符串转为实体类
        orderStatus = objectMapper.readValue(json, Order.OrderStatus.class);
    } 
catch (JsonProcessingException e) {
        e.printStackTrace();
    }

4. 提出需求:将null值的字段解析为false

有一个实体类

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应该如何处理

5.使用自定义JsonDeserializer

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了

6.另辟蹊径

前面提到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
在这里插入图片描述

7. 总结

遇到问题先去看官方文档,如果文档中没有提到相关功能,看源码调试。另外也要对Java反射机制熟悉

你可能感兴趣的:(Spring,Boot,2,Spring,Java,json,java,restful)