开发者

抽象类使用Jackson序列化问题

目录
  • 抽象类使用Jackson序列化
  • 记一次jackson序列化Boolean的坑
    • 总结排查思路如下js
  • 总结

    抽象类使用Jackson序列化

    当Java对象中含List<Object>时,如果Object一个抽象类或接口,这里就会出现java多态的现象,比如List<Animal>, 如果Animal是个抽象类,并且有多个子类时,由于List中保存的Animal没有明确指向具体的子类或实现类,json反序列化java对象时就会抛出提示:

    Exception in thread "main" com.fasterXML.jackson.databind.JsonMappingException:Can not construct instance of Animal, problem: abstract types either need to be mapped to concrete types, have custom deserializer, or be instantiated with additional type information

    可以使用@JsonTypeInfo与@JsonSubTypes来解决此类问题,通过注解,可以在序列化时,保存具体的类型信息到json中,当json反序列到java对象时,就可以根据具体类型信息创建正确的java对象。

    • @JsonTypeInfo – indicates details of what type information to include in serialization 指出序列化包含的类型信息细节
    • @JsonSubTypes – indicates sub-types of the annotated type 指出被注解类型的子类
    • @JsonTypeName – defines a logical type name to use for annotated class 定义被注解类使用的逻辑名称
    @JsonTypeInfo(
            use = JsonTypeInfo.Id.NAME,
            include = As.PROPERTY,
            property = "type")
    @JsonSubTypes({
            @JsonSubTypes.Type(value = Dog.class, name = "dog"),
            @JsonSubTypes.Type(value = Cat.class, name = "cat")
    })
    public class Animal {
        public String name;
     
        public Animal(String name) {
        }
    }
     
    @JsonTypeName("dog")
    // 这里在子类中指定的type name必须和抽象类中注解@JsonSubTypes中name属性指定的值保持一致
    public class Dog extends Animal {
        public double barkVolume;
     
        public D编程og(String name) {
            super(name);
            barkVolume = 0.5;
        }
    }
     
    @JsonTypeName("cat")
    public class Cat extends Animal {
        boolean likesCream;
        public int lives;
     
        public Cat(String name) {
            super(name);
            likesCream = true;
            lives = 10;
        }
    }
      
        @Test
        public void whenSerializingPolymorphic_thenCorrect(编程客栈)
                throws JsonProcessingException {
            Zoo.Dog dog = new Zoo.Dog("lacy");
            Zoo zoo = new Zoo(dog);
     
            String result = new ObjectMapper()
                    .writeValueAsString(zoo);
     
            assertThat(result, containsString("type"));
            assertThat(result, containsString("dog"));
        }
     
        序列化zoo对象,结果如下:
            {
             "type":"dog",
           android  "name":"lacy",
             "barkVolume":0
            }
     
        @Test
        public void whenDeserializingPolymorphic_thenCorrect()
                throws IOException {
            String json = "{\"name\":\"lacy\",\"type\":\"cat\"}";
     
            Animal animal =
                    new ObjectMapper().readerFor(Animal.class).readValue(json);
     
            assertE开发者_Js入门quals("lacy", animal.name);
            assertEquals(Cat.class, animal.getClass());
        }

    记一次jackson序列化Boolean的坑

    @Data
    public class CouponTemplateDto {
        /**
         * 优惠券类型id
         */
        private Long couponTypeId;
        /**
         * 优惠券模板id
         */
        private Long couponTemplateId;
        /**
         * 用户id
         */
        private Long userId;
    
        /**
         * 优惠券描述
         */
        private String description;
        /**
         * 面值,满200减30,则此值为30
         */
        private BigDecimal value;
        /**
         * 从次日起,多少天可用
         */
        private Integer delayDays;
        /**
         * 从当日起,多少天可用
         */
        private Integer nowDays;
        /**
         * 满多少可以减,满200减30,则此值为200
         */
        private BigDecimal fullAmount;
    
        /**
         * 券号
         */
        private String couponNo;
    
        /**
         * 有效起始日期
         */
        private Date startTime;
    
        /**
         * 失效日期
         */
        private Date endTime;
    
        /**
         * 创建时间
         */
        private Date createTime;
    
        /**
         * 使用日期
         */
        private Date useTime;
    
        /**
         * 券使用状态:0-未使用 1-已使用 2-已过期
         */
        private Integer couponUseStatus;
        /**
         * 过期前多少天提醒,默认7天
         */
        private Integer overDueRemind;
        /**
         * 优惠券标题
         */
        private String title;
    
        /**
         * 优惠券是否能开始使用
         */
    //    @JsonProperty("isStart")
        private Boolean start;
        /**
         * 优惠券是否过期
         */
    //    @JsonProperty("isEnd")
        private Boolean end;
    
        private Boolean getStart() {
            return startTime.before(new Date());
        }
    
        private Boolean getEnd() {
            return endTime.before(new Date());
        }
    }
    

    我定义了一个这样的类,我们项目用的是Spring Boot,默认底层采用的是jackson序列化,但是在使用中出了一个问题private Boolean start跟private Boolean end这两个字段一直无法序列化

    总结排查思路如下

    1.是boolean还是Boolean,到底是基本数据类型还是包装类,如果是基本数据类型的话(包装类可以使用,但是不推荐),不要使用is开头。我们可以看看阿里http://www.devze.com巴巴规范中的这段话

    【强制】POJO类中的任何布尔类型的变量,都不要加 is,否则部分框架解析会引起序列化错误。

    反例:定义为基本数据类型 boolean isSuccess;的属性,它的方法也是 isSuccess(),RPC框架在反向解析的时候,“以为”对应的属性名称是 success,导致属性获取不到,进而抛出异常。

    2.这个错误也是我犯的错误,我复写了get方法,方法的访问权限被设置成了private级别

    解决方案:

    • 加注解,@JsonProperty(“isEnd”)
    • 将方法级别更正为public

    总结

    以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

    0

    上一篇:

    下一篇:

    精彩评论

    暂无评论...
    验证码 换一张
    取 消

    最新开发

    开发排行榜