杰克逊注解中的多态性:@JsonTypeInfo用法

58

我想知道是否可以使用@JsonTypeInfo注解来处理接口。我有一组需要序列化和反序列化的类。

这是我的实现方法:我有两个实现类Sub1Sub2实现了MyInt接口。一些模型类具有实现类型的接口引用。我希望可以基于多态性进行对象的反序列化。

@JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=As.WRAPPER_OBJECT)
@JsonSubTypes({
    @Type(name="sub1", value=Sub1.class), 
    @Type(name="sub2", value=Sub2.class)})
public interface MyInt{
}

@JsonTypeName("sub1")
public Sub1 implements MyInt{
}

@JsonTypeName("sub2")
public Sub2 implements MyInt{
}

我遇到了以下JsonMappingException:

意外的令牌 (END_OBJECT),预期的是 FIELD_NAME: 需要包含类型标识符的 JSON 字符串


你看到这个了吗?http://jackson-users.ning.com/forum/topics/mapper-not-include-type-information-when-serializing-object-why?xg_source=activity 你有没有像其他帖子中讨论的那样没有提到类型的列表? - Senthil Kumar
2
我认为你需要展示更多的代码(如何进行序列化、反序列化),以及所生成/消耗的JSON。 - StaxMan
3个回答

53

@JsonSubTypes.Type 必须像这样拥有一个值和名称,

@JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=As.WRAPPER_OBJECT, property="type")
@JsonSubTypes({       
    @JsonSubTypes.Type(value=Dog.class, name="dog"),
    @JsonSubTypes.Type(value=Cat.class, name="cat")       
}) 
在子类中,使用@JsonTypeName("dog")来指定名称。属性名为type,值可以是dog或者cat

3
有人知道JsonTypeInfo是否可以应用于接口吗? - Chris
1
更新了答案,在@JSONTypeInfo中添加属性,看看是否有效。抱歉之前没有注意到。 - Senthil Kumar
2
是的,如果有帮助的话,@JsonTypeInfo可以用于接口(Jackson的注释处理支持继承)。 - StaxMan
5
但是如果有其他人试图实现你的接口呢?在不将注释添加到你的接口文件中,你无法将一个名为“sub3”的新具体类型反序列化为MyInt。 - derrdji
1
这里有很好的解释和更新的示例:http://www.davismol.net/2015/03/05/jackson-json-deserialize-a-list-of-objects-of-subclasses-of-an-abstract-class/ - ruhong
显示剩余8条评论

3

是的,它可以用于抽象类和接口。

考虑以下代码示例

假设我们有一个枚举,接口和类

enum VehicleType {
    CAR,
    PLANE
}

interface Vehicle {
    VehicleType getVehicleType();
    String getName();
}


@NoArgsConstructor
@Getter
@Setter
class Car implements Vehicle {
    private boolean sunRoof;
    private String name;

    @Override
    public VehicleType getVehicleType() {
        return VehicleType.Car;
    }
}

@NoArgsConstructor
@Getter
@Setter
class Plane implements Vehicle {
    private double wingspan;
    private String name;

    @Override
    public VehicleType getVehicleType() {
        return VehicleType.Plane;
    }
}

如果我们尝试将这个json反序列化为 List<Vehicle>
[
  {"sunRoof":false,"name":"Ferrari","vehicleType":"CAR"}, 
  {"wingspan":19.25,"name":"Boeing 750","vehicleType":"PLANE"}
]

然后我们会遇到错误。

abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information

为了解决这个问题,只需按照下面的示例,在接口中添加以下JsonSubTypesJsonTypeInfo注释即可。
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME,
        property = "vehicleType")
@JsonSubTypes({
        @JsonSubTypes.Type(value = Car.class, name = "CAR"),
        @JsonSubTypes.Type(value = Plane.class, name = "PLANE")
})
interface Vehicle {
    VehicleType getVehicleType();
    String getName();
}

使用此方法,反序列化将与接口一起工作,并返回一个List<Vehicle>

您可以在此处查看代码 - https://github.com/chatterjeesunit/java-playground/blob/master/src/main/java/com/play/util/jackson/PolymorphicDeserialization.java


0
对于 Kotlin,它也可以在不手动声明子类型的情况下工作。像这样:
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "kind")
sealed class Something {
    val kind = this::class.java.simpleName
}

注意你需要封装这个类。


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