jackson如何根据另个属性来确定实例化具体实现类(基于spring-boot)

对于如果属性在抽象类中这个利用@JsonTypeInfo 和 @JsonSubTypes 很容易实现,如果这个属性与将要反序列化在同一层级,那个应该怎么做,将下面举个例子,基于spring-boot环境

  • public interface Item{
      
    }
    public  class  Person{
      private Integer age;
      private Item item;
    }
    // age<7
    public ChildItem implement Item {
      private String read;
      private String sleep;
    }
    // 7< age < 50
    public AdultItem implement Item {
      private String work;
      private String playGame;
    }
    
    // age > 50
    public OldItem implement Item {
      private String walk;
      private String talk;
    }
    
  • 上面定义Person对象,里面有item,具体实现类是通过age来决定jackson具体实例化那个类

  • 此时使用@JsonTypeInfo 和 @JsonSubTypes不好处理,它针对是json中都相同属性,根据属性值判断,可惜这里属性都不相同?

解决方案

1、完全手动实现反序列化

  • 如果实体不是很复杂这个还是可以接受,如果bean字段特别多,那么不好操作了

  • 也就实现StdDeserializer的deserialize方法

  • 示例代码(spring boot)下

  • @JsonComponent
    public class ItemDeserializer extends StdDeserializer<Item> {
    
        protected ItemDeserializer() {
            super(Item.class);
        }
    
        @Override
        public Item deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
            ObjectMapper mapper = (ObjectMapper) p.getCodec();
            JsonNode itemNode = mapper.readTree(p);
            JsonNode read = itemNode.get("read");
            if (read != null && !read.asText().isEmpty()) {
              ChildItem childItem = new ChildItem();
              childItem.setRead(read.asText());
              childItem.setSleep(itemNode.get("sleep").asText());
              return childItem;
            }
            JsonNode work = itemNode.get("work");
            if (work != null && !work.asText().isEmpty()) {
              AdultItem adultItem = new AdultItem();
              adultItem.setWork(work.asText());
              adultItem.setPlayGame(itemNode.get("playGame").asText());
              return adultItem;
            }
           JsonNode work = itemNode.get("walk");
            if (walk != null && !walk.asText().isEmpty()) {
              OldItem oldItem = new OldItem();
              oldItem.setWalk(walk.asText());
              oldItem.setTalk(itemNode.get("talk").asText());
              return oldItem;
            }
           return null;
        }
    
    }
    
  • 直接根据json字段判断需要实例化那个对象

  • @JsonComponent,将该反序列注册到Jackson中

2、半手动实现反序列化

  • 思路就是补上相同字段,让它标准化

  • 重新序列化操作( 适合字段多的bean)

  • @JsonComponent
    public class PersonDeserializer extends StdDeserializer<Person> {
    
        protected PersonDeserializer() {
            super(Person.class);
        }
    
        @Override
        public Person deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
            ObjectMapper mapper = (ObjectMapper) p.getCodec();
            JsonNode tree = mapper.readTree(p);
            JsonNode itemNode = tree.get("item");
            int age = itemNode.get("age").asInt();
            if (age<7) {
                ((ObjectNode) itemNode).put("type", "child");
            }else if(age < 50){
             ((ObjectNode) itemNode).put("type", "adult");
            }else{
             ((ObjectNode) itemNode).put("type", "old");
            }
            return new ObjectMapper().readValue(tree.toString(), Person.class);
        }
    
    }
    
    // 配置 @JsonTypeInfo注解
    public  class  Person{
      private Integer age;
       @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
        @JsonSubTypes({
                @JsonSubTypes.Type(value = ChildItem.class, name = "child"),
                @JsonSubTypes.Type(value = AdultItem.class, name = "adult"),
                @JsonSubTypes.Type(value = OldItem.class, name = "old"),
          
                })
      private Item item;
    }
    
  • return new ObjectMapper().readValue(tree.toString(), Person.class); 这个一定要注意需要new ObjectMapper() , 如果使用原来的mapper会抛出No content to map due to end-of-input异常

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值