美文网首页
Jackson全面解析--注解全讲解十(多态序列化方案@Json

Jackson全面解析--注解全讲解十(多态序列化方案@Json

作者: 牧羊人刘俏 | 来源:发表于2020-12-10 15:00 被阅读0次

    @JsonTypeInfo

    在java里面由于有多态的用法,所以在涉及到多态的序列化和反序列化的时候,需要指定一些子类的相关信息告诉Jackson,这样Jackson在序列化和反序列的时候才不出错,我们先举个例子,如下

    @AllArgsConstructor(staticName = "of")
        @NoArgsConstructor
        @Getter
        @Setter
        class View{
    
            private List<Sharp> sharps;
    
    
        }
    
        abstract class Sharp{
    
    
        }
    
        @AllArgsConstructor(staticName = "of")
        @NoArgsConstructor
        class Circle extends Sharp{
    
            @Getter
            @Setter
            private String radius;
        }
    
        @AllArgsConstructor(staticName = "of")
        @NoArgsConstructor
        class Rectangle extends Sharp{
    
            @Getter
            @Setter
            private String length;
    
    
            @Getter
            @Setter
            private String width;
    
        }
    

    测试代码如下

    @Test
        public void JsonTypeInfoTest() throws Exception{
    
            CombineJacksonAnnotation.Circle circle = CombineJacksonAnnotation.Circle.of("12");
            CombineJacksonAnnotation.Rectangle rectangle = CombineJacksonAnnotation.Rectangle.of("12","13");
    
            CombineJacksonAnnotation.View view =  CombineJacksonAnnotation.View.of(Lists.newArrayList(circle,rectangle));
            System.out.println(om.writeValueAsString(view));
    
        }
    

    结果如下

    {
      "sharps" : [ {
        "radius" : "12"
      }, {
        "length" : "12",
        "width" : "13"
      } ]
    }
    

    看上面的序列化结果貌似没有什么问题,但是如果我们直接的使用这个Json串继续做反序列化,看看会发生什么

    com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `com.ittx.cbt.report.service.jackson.CombineJacksonAnnotation$Sharp` (no Creators, like default construct, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information
     at [Source: (String)"{
      "sharps" : [ {
        "name" : "circleType",
        "radius" : "12"
      }, {
        "name" : "rectangleType",
        "length" : "12",
        "width" : "13"
      } ]
    }"; line: 2, column: 16] (through reference chain: com.ittx.cbt.report.service.jackson.CombineJacksonAnnotation$View["sharps"]->java.util.ArrayList[0])
    
        at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67)
    

    究其原因,是因为在反序列化的时候,我们没有告诉Jackson其多态信息,Jackson在反序列化的时候,就直接的按照常规的方式去反序列化成Sharp,由于Sharp是个抽象对象,实例化的时候肯定会出错的,即使Sharp不是抽象类,属性也会匹配不上而报错。
    Jackson提供了@JsonTypeInfo来处理多态的序列化和反序列化,如下,我们在Sharp打上如下的标签

    @JsonTypeInfo(use = JsonTypeInfo.Id.NAME,include = JsonTypeInfo.As.PROPERTY,property = "name")
    

    序列化结果如下

    {
      "sharps" : [ {
        "name" : "CombineJacksonAnnotation$Circle",
        "radius" : "12"
      }, {
        "name" : "CombineJacksonAnnotation$Rectangle",
        "length" : "12",
        "width" : "13"
      } ]
    }
    

    可以看到在加上@JsonTypeInfo注解之后,在序列化的时候,会将类的信息也序列化到Json串里面。
    现在简单的介绍下@JsonTypeInfo里面几个属性的作用
    1 use 非空就是子类在序列化的手,使用什么样式序列化到Json串里面去,可选值如下
    NONE 与不写一样
    CLASS 使用类的全限定名作为value,默认使用@class作为key值,但是可以使用@JsonTypeInfo里面的property属性定义新的key值,如下

    "@class" : "com.ittx.cbt.report.service.jackson.CombineJacksonAnnotation$Circle",
    

    MINIMAL_CLASS 使用最小类型作为value,默认使用@c作为key值,但是可以使用@JsonTypeInfo里面的property属性定义新的key值,如下

    "@c" : ".CombineJacksonAnnotation$Circle",
    

    @NAME 使用类名作为value,默认使用@type作为key值,但是可以使用@JsonTypeInfo里面的property属性定义新的key值,如下

    "@type" : "CombineJacksonAnnotation$Circle",
    

    @CUSTOM 自定义

    2include 默认是
    PROPERTY 就是说序列化后的类型信息会默认作为pojo的属性输出
    WRAPPER_OBJECT 使用包装类型输出,如下

     "CombineJacksonAnnotation$Circle" : {
          "radius" : "12"
        }
    

    WRAPPER_ARRAY 使用包装数组输出,如下

    [ "CombineJacksonAnnotation$Circle", {
        "radius" : "12"
      } ]
    

    EXTERNAL_PROPERTY与EXISTING_PROPERTY较相识,不介绍

    但是我们再反序列化的时候还是会报错,如下

    com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Could not resolve type id 'CombineJacksonAnnotation$Circle' as a subtype of [simple type, class com.ittx.cbt.report.service.jackson.CombineJacksonAnnotation$Sharp]: known type ids = [] (for POJO property 'sharps')
     at [Source: (String)"{
      "sharps" : [ {
        "name" : "CombineJacksonAnnotation$Circle",
        "radius" : "12"
      }, {
        "name" : "CombineJacksonAnnotation$Rectangle",
        "length" : "12",
        "width" : "13"
      } ]
    }"; line: 3, column: 14] (through reference chain: com.ittx.cbt.report.service.jackson.CombineJacksonAnnotation$View["sharps"]->java.util.ArrayList[0])
    
        at com.fasterxml.jackson.databind.exc.InvalidTypeIdException.from(InvalidTypeIdException.java:43)
    

    这个是因为我们没有将子类与序列化之后的类型信息关联起来,我们在Sharp上面添加下面的注解@JsonSubTypes

    @JsonSubTypes(value = {@JsonSubTypes.Type(value =Circle.class),@JsonSubTypes.Type(value =Rectangle.class)})
    

    这个注解意思是,Sharp包含多少个subType,然后在Circle上面再打上注解如下

    @JsonTypeName("circleType")
    

    在Rectangle打上注解如下

    @JsonTypeName("rectangleType")
    

    序列化之后的结果如下

    {
      "sharps" : [ {
        "name" : "circleType",
        "radius" : "12"
      }, {
        "name" : "rectangleType",
        "length" : "12",
        "width" : "13"
      } ]
    }
    

    反序列化也成功了,该注解主要用于多态的场景,在关键时候是解决问题的利器。

    相关文章

      网友评论

          本文标题:Jackson全面解析--注解全讲解十(多态序列化方案@Json

          本文链接:https://www.haomeiwen.com/subject/xrzlgktx.html