@JsonTypeInfo和@JsonSubTypes在jackson中有何作用?

63

@JsonTypeInfo@JsonSubTypes注解在Jackson中用于什么?

public class Lion extends Animal {

private String name;

@JsonCreator
public Lion(@JsonProperty("name") String name) {
    this.name = name;
}

public String getName() {
    return name;
}

public String getSound() {
    return "Roar";
}

public String getType() {
    return "carnivorous";
}

public boolean isEndangered() {
    return true;
}

@Override
public String toString() {
    return "Lion [name=" + name + ", getName()=" + getName() + ", getSound()=" + getSound() + ", getType()=" + getType() + ", isEndangered()="
            + isEndangered() + "]";
}

}

========================================

public class Elephant extends Animal {

@JsonProperty
private String name;

@JsonCreator
public Elephant(@JsonProperty("name") String name) {
    this.name = name;
}

public String getName() {
    return name;
}

public String getSound() {
    return "trumpet";
}

public String getType() {
    return "herbivorous";
}

public boolean isEndangered() {
    return false;
}

@Override
public String toString() {
    return "Elephant [name=" + name + ", getName()=" + getName() + ", getSound()=" + getSound() + ", getType()=" + getType()
            + ", isEndangered()=" + isEndangered() + "]";
}
}

==============================================

@JsonTypeInfo (use = JsonTypeInfo.Id.CLASS, include = As.PROPERTY, property = "classNameExtenral")
@JsonSubTypes ({@Type (value = Lion.class, name = "lion"), @Type (value = Elephant.class, name = "elephant")})

public abstract class Animal {

@JsonProperty ("name")
String name;
@JsonProperty ("sound")
String sound;
@JsonProperty ("type")
String type;
@JsonProperty ("endangered")
boolean endangered;
}

public static void main(String[] args){
    Lion lion = new Lion("Simba");
    Elephant elephant = new Elephant("Manny");
    List<Animal> animals = new ArrayList<>();
    animals.add(lion);
    animals.add(elephant);
}

我的理解是,它除了保存实际数据之外,还保留了被序列化对象的具体类型。

对我来说不清楚的是,反序列化过程中的实际优势/收益是什么。

除了Java文档之外,没有获得任何重要的文档。有人可以帮忙或提供相关文档吗?


也许这个答案会有所帮助:https://dev59.com/M1wZ5IYBdhLWcg3wQ-bk#31666888 - davidbak
它有助于...谢谢。 - Harshit
1个回答

76
这些注释的目的是支持反序列化中的多态性。在反序列化时,实际执行的代码将知道它所期望的内容的类,例如反序列化为某个字段的类型。但是,如果该类有子类(即子类型),通用的Jackson反序列化程序如何知道要反序列化的字符串属于哪个实际类?它必须创建某个具体类型(该类或其子类之一)的实例并填充它。唯一能知道要创建哪个实例的方法是首先在序列化中写入这些信息。正如此答案所述,有三种方法可以实现 - 您可以选择适合您用例的方法。 @JsonTypeInfo + @JsonSubtypes是其中之一 - 当您在编译时知道可能存在的所有子类型时,它非常有效。

1
在各个具体类上使用@JsonTypeInfo不是更合理吗?在接口上使用它似乎违反了开闭原则(因为我们需要在每次添加具体实现时修改接口)。如果我错了,请纠正我。 - Harshit
再次强调,这取决于使用情况。例如,我有一个使用情况,在那里实际上可以在一个地方使用@JsonSubtypes,而这比标记每个子类型更可取。但老实说,现在我忘记了那个使用情况是什么;我记得它有点与实际部署/发布问题有关,而不是纯粹的面向对象理论。 (请记住:像开放-关闭原则这样的任何“原则”都只是一个强烈的指导方针……在某些情况下,您可能会发现违反这样的原则是正确的设计 - 只需确保您真正知道为什么。) - davidbak
4
假设你有一个类叫 Cage,包含一个类型为 Animal 的字段。当 Cage 对象从 JSON 反序列化时,Jackson 发现它应该创建一个 Animal,所以如果 Animal 没有用 @JsonTypeInfo 注释,Jackson 就不会支持多态性,并且只会创建 Animal(如果可能),而不是它的子类型。 - Konstantin Pelepelin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接