Jackson 根据 Cat 实例的字段类型(多态)使用 2 个不同的序列化器序列化 Animal 和 Cat
Jackson serialize Animal and Cat with 2 different serializers depending on the field type of a Cat instance (polymorphistic)
我有一只 class 动物和一只 class 猫:
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的一个实例:
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)
来说 return Animal
,不是 Cat
.
既然你说不想注解字段,那你可以根据字段类型定义一个ContextualSerializer那个returns序列化器。然后,您可以为每个 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());
我希望这个解决方案对你有用,或者对此有任何适当的调整。造成您期望的行为的是 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"}
我有一只 class 动物和一只 class 猫:
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的一个实例:
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)
来说 return Animal
,不是 Cat
.
既然你说不想注解字段,那你可以根据字段类型定义一个ContextualSerializer那个returns序列化器。然后,您可以为每个 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());
我希望这个解决方案对你有用,或者对此有任何适当的调整。造成您期望的行为的是 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"}