【问题标题】:Jackson serialize Animal and Cat with 2 different serializers depending on the field type of a Cat instance (polymorphistic)Jackson 根据 Cat 实例的字段类型(多态),使用 2 个不同的序列化程序对 Animal 和 Cat 进行序列化
【发布时间】:2018-03-09 12:29:15
【问题描述】:

我有一个类动物和一个扩展它的类猫:

class Animal {
  protected String name;
  ...
}
class Cat extends Animal {
  protected int livesLeft;
  ...
}

每个都有一个单独的JsonSerializer

module.addSerializer(Cat.class, new CatSerializer());
module.addSerializer(Animal.class, new AnimalSerializer());

现在我想序列化这个类的一个实例:

class Foo {
   Cat catA = new Cat("Felix", 9);
   Animal catB = new Cat("Madonna", 3);
}

但是当我这样做时,两个字段都使用CatSerializer,所以我得到了

{"catA" : {"name":"Felix", "livesLeft":9},
"catB" : {"name":"Madonna", "livesLeft":3}}

这是我无法反序列化的,因为 AnimalDeserializer 需要知道动物的类型才能构造它。

理想情况下,它会为 Animal catB 字段使用 AnimalSerializer,我会得到:

{"catA" : {"name":"Felix", "livesLeft":9},
"catB" : {"animalType":"Cat", "name":"Madonna", "livesLeft":3}}

可以反序列化。

解决思路:有没有办法在序列化过程中确定字段类型(不仅仅是实例类型)?所以对于字段Animal catB = new Cat("Madonna", 3),它将返回Animal,而不是Cat

【问题讨论】:

    标签: json jackson jackson2


    【解决方案1】:

    既然你说你不想注释字段,你可以定义一个ContextualSerializer,它根据字段类型返回一个序列化器。然后,您可以为每个 Animal 子类型而不是 JsonSerializer 扩展它。例如。 :

    abstract class ByFieldTypeSerializer<T> extends JsonSerializer<T> implements ContextualSerializer {
        @Override
        public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {
            // getType will return the field type i.e. Animal for catB
            // SerializerProvider argument knows about all serializers by type
            return prov.findValueSerializer(property.getType());
        }
    }
    
    class CatSerializer extends ByFieldTypeSerializer<Cat> {
        @Override
        public void serialize(Cat value, JsonGenerator gen, SerializerProvider serializers) throws IOException, JsonProcessingException {
            // serialize a Cat
        }
    }
    

    然后只需将其插入:

    module.addSerializer(Animal.class, new AnimalSerializer());
    // Delegates to AnimalSerializer if the field type is Animal instead of Cat
    module.addSerializer(Cat.class, new CatSerializer()); 
    

    【讨论】:

    • 完美。像魅力一样工作:)
    【解决方案2】:

    我希望此解决方案对您有用,或对此进行任何适当的调整。导致您所期望的行为的原因是 forType(Animal.class) 的使用。

    public static void main(String[] args) throws JsonProcessingException {
        ObjectMapper objectMapper = new ObjectMapper();
        Cat cat = new Cat();
        cat.livesLeft=3;
        cat.name="mycat";
        System.out.println(objectMapper.writer().writeValueAsString(cat));
    
        Animal animal = cat;
        System.out.println(objectMapper.writer().forType(Animal.class).writeValueAsString(animal));
    }
    
    @Data
    static abstract class Animal {
        protected String name;
    
        public String getAnimalType(){
            return this.getClass().getSimpleName();
        }
    }
    
    @JsonIgnoreProperties("animalType")
    @Data
    static class Cat extends Animal {
        protected int livesLeft;
    }
    

    生成的输出如下:

    {"name":"mycat","livesLeft":3}
    {"name":"mycat","animalType":"Cat"}
    

    【讨论】:

    • 我有个复杂的问题:Animal 和 Cat 是 3th 方类,我不能直接修改它们,只能为它们编写 Serializer/Deserializers。但是使用 mixins,这个解决方案可能会起作用,谢谢。
    猜你喜欢
    • 1970-01-01
    • 2013-12-07
    • 2013-06-12
    • 1970-01-01
    • 2014-05-01
    • 2015-01-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多