杰克逊:继承和必需的属性
Jackson : Inheritance and required attributes
我目前正在尝试使用能够处理多态性的 jackson 实现反序列化器,也就是说,给定这两个 classes :
public abstract class Animal {
private String name;
private float weight;
@JsonCreator
protected Animal(@JsonProperty(value="name") String name, @JsonProperty(value="weight",required=true) int weight) {
this.name=name;
this.weight=weight;
}
}
public class Dog extends Animal {
private int barkVolume;
@JsonCreator
public Dog(String name,int weight, @JsonProperty(value="barkVolume",required=true) int barkVolume) {
super(name, weight);
this.barkVolume=barkVolume;
}
}
反序列化器应该能够从 json 字符串中推断并实例化正确的子 class。
我使用自定义反序列化器模块 UniquePropertyPolymorphicDeserializer(来自 https://gist.github.com/robinhowlett/ce45e575197060b8392d)。该模块配置如下:
UniquePropertyPolymorphicDeserializer<Animal> deserializer =
new UniquePropertyPolymorphicDeserializer<Animal>(Animal.class);
deserializer.register("barkVolume", Dog.class);
SimpleModule module = new SimpleModule("UniquePropertyPolymorphicDeserializer");
module.addDeserializer(Animal.class, deserializer);
mapper.registerModule(module);
此模块询问用户每个子class动物的独特属性。因此,当反序列化器找到一个 json 字符串和 barkVolume 属性 时,它知道应该实例化一个 Dog。
但是,我对 json 属性的规范有疑问,因为子 class 无法继承父 class 中给定的属性。在 class Dog 中,我必须再次指定 "name" 和 "weight" 是 json 属性,即使这些属性已经在 Animal class 中指定:
public Dog(@JsonProperty(value="name") String name, @JsonProperty(value="weight",required=true) int weight, @JsonProperty(value="barkVolume",required=true) int barkVolume) {
super(name, weight);
this.barkVolume=barkVolume;
}
否则,解串器会产生错误:
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Invalid type definition for type `Animals.Dog`: Argument #0 has no property name, is not Injectable: can not use as Creator [constructor for Animals.Dog, annotations: {interface com.fasterxml.jackson.annotation.JsonCreator=@com.fasterxml.jackson.annotation.JsonCreator(mode=DEFAULT)}]
at [Source: UNKNOWN; line: -1, column: -1]
这个解决方案对我来说并不令人满意:
每次我们想要创建 Animal 的新子class时,我们必须
在此 class 中指定名称和重量是 json 属性
这很棘手,例如,在动物 class 中,权重 属性 被标记为必需,而在子class 中,我们可以定义重量不是必需的 属性.
你知道从父class的属性中"inherit"的方法,以避免每次在子classes中指定相应的json 属性 ?
此致,
马修
我最终决定创建自己的反序列化器(而不是 UniquePropertyDeserializer),我在其中使用内省来获取父 class 的字段。它允许避免在子 classes 中再次指定所需的 json 属性。
我目前正在尝试使用能够处理多态性的 jackson 实现反序列化器,也就是说,给定这两个 classes :
public abstract class Animal {
private String name;
private float weight;
@JsonCreator
protected Animal(@JsonProperty(value="name") String name, @JsonProperty(value="weight",required=true) int weight) {
this.name=name;
this.weight=weight;
}
}
public class Dog extends Animal {
private int barkVolume;
@JsonCreator
public Dog(String name,int weight, @JsonProperty(value="barkVolume",required=true) int barkVolume) {
super(name, weight);
this.barkVolume=barkVolume;
}
}
反序列化器应该能够从 json 字符串中推断并实例化正确的子 class。
我使用自定义反序列化器模块 UniquePropertyPolymorphicDeserializer(来自 https://gist.github.com/robinhowlett/ce45e575197060b8392d)。该模块配置如下:
UniquePropertyPolymorphicDeserializer<Animal> deserializer =
new UniquePropertyPolymorphicDeserializer<Animal>(Animal.class);
deserializer.register("barkVolume", Dog.class);
SimpleModule module = new SimpleModule("UniquePropertyPolymorphicDeserializer");
module.addDeserializer(Animal.class, deserializer);
mapper.registerModule(module);
此模块询问用户每个子class动物的独特属性。因此,当反序列化器找到一个 json 字符串和 barkVolume 属性 时,它知道应该实例化一个 Dog。
但是,我对 json 属性的规范有疑问,因为子 class 无法继承父 class 中给定的属性。在 class Dog 中,我必须再次指定 "name" 和 "weight" 是 json 属性,即使这些属性已经在 Animal class 中指定:
public Dog(@JsonProperty(value="name") String name, @JsonProperty(value="weight",required=true) int weight, @JsonProperty(value="barkVolume",required=true) int barkVolume) {
super(name, weight);
this.barkVolume=barkVolume;
}
否则,解串器会产生错误:
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Invalid type definition for type `Animals.Dog`: Argument #0 has no property name, is not Injectable: can not use as Creator [constructor for Animals.Dog, annotations: {interface com.fasterxml.jackson.annotation.JsonCreator=@com.fasterxml.jackson.annotation.JsonCreator(mode=DEFAULT)}]
at [Source: UNKNOWN; line: -1, column: -1]
这个解决方案对我来说并不令人满意:
每次我们想要创建 Animal 的新子class时,我们必须 在此 class 中指定名称和重量是 json 属性
这很棘手,例如,在动物 class 中,权重 属性 被标记为必需,而在子class 中,我们可以定义重量不是必需的 属性.
你知道从父class的属性中"inherit"的方法,以避免每次在子classes中指定相应的json 属性 ?
此致,
马修
我最终决定创建自己的反序列化器(而不是 UniquePropertyDeserializer),我在其中使用内省来获取父 class 的字段。它允许避免在子 classes 中再次指定所需的 json 属性。