当JSON包含类型属性时,Jackson能确定反序列化的根对象类型吗?

13

假设将对象序列化为JSON时,包括实际对象的类名,在该类上使用以下注释:

@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@type")
class MyClass {
    String foo;
}

因此,JSON的一个示例:

{"@type": "com.example.MyClass", "foo": "bar"}

这个可以在不指定类型的情况下反序列化吗?我指的是甚至不指定其超类型。就像这样:

objectMapper.readValue(value, Object.class);

这个实际上并不起作用,它会返回一个 Map。


请参见 https://dev59.com/Wl0a5IYBdhLWcg3waYCM - koppor
4个回答

11

当然可以这样做,尽管我个人从未以那种方式使用过Jackson。你可以将其反序列化为JsonNode对象,然后将其转换为适当的类型。

final ObjectMapper objectMapper = new ObjectMapper();
final MyClass myClass = new MyClass();
myClass.foo = "bar";

// Serialize
final String json = objectMapper.writeValueAsString(myClass);

// Deserialize
final JsonNode jsonNode = objectMapper.readTree(json);

// Get the @type
final String type = jsonNode.get("@type").asText();

// Create a Class-object
final Class<?> cls = Class.forName(type);

// And convert it
final Object o = objectMapper.convertValue(jsonNode, cls);

System.out.println(o.getClass());

输出为:

MyClass


2
哦,是的,我想那样可以。我在想是否有更内置的方法,但我想这没有任何意义,因为Jackson不可能知道我如何配置JsonTypeInfo,而不知道类。非常感谢。 - Nazaret K.

3
    ObjectMapper mapper = new ObjectMapper();
    mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);

    MyClass original = new MyClass();
    original.foo = "hello";

    String json = mapper.writeValueAsString(original);
    MyClass foo = (MyClass) mapper.readValue(json, MyClass.class);

这应该可以正常运行,而且非常方便。


如果您在反序列化时知道JSON表示MyClass,那么它可以工作。我认为问题是指在您不知道对象类型的情况下的场景。这就是我目前正在尝试处理的情况。 - Rob Fletcher
如果您不知道类型,可以将其分配给一个对象。 object.getClass()将告诉您它是什么类型。 - sydraz

2
是的,但有一个注意事项:您提供的类型必须包括您指定的 @JsonTypeInfo。除非您使用“混合注释”将其关联,否则 Object.class 将不具备此功能。
然而,如果您需要为(声明类型为)java.lang.Object 的属性添加类型信息,则可能需要启用默认类型:有关更多信息,请参见 ObjectMapper.enableDefaultTyping(...)。 这实际上会启用对更大类别的类的类型信息的包含(和使用),无需添加注释。

1

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