杰克逊的@JsonSubTypes仍然是多态反序列化所必需的吗?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了杰克逊的@JsonSubTypes仍然是多态反序列化所必需的吗?相关的知识,希望对你有一定的参考价值。
我能够序列化和反序列化抽象基类注释的类层次结构
@JsonTypeInfo(
use = JsonTypeInfo.Id.MINIMAL_CLASS,
include = JsonTypeInfo.As.PROPERTY,
property = "@class")
但没有列出子类的@JsonSubTypes
,并且子类本身相对未注释,在构造函数上只有一个@JsonCreator
。 ObjectMapper是vanilla,我没有使用mixin。
关于PolymorphicDeserialization and "type ids"的杰克逊文档建议(强烈地)我需要在抽象基类上使用@JsonSubTypes
注释,或者在mixin上使用它,或者我需要使用register the subtypes with the ObjectMapper。并且有很多SO问题和/或博客帖子都同意。但它确实有效。 (这是Jackson 2.6.0。)
那么......我是一个尚未记录的功能的受益者,还是我依赖于无证件行为(可能会改变)或是其他事情继续发生? (我问,因为我真的不希望它成为后两者中的任何一个。但是I gots to know。)
编辑:添加代码 - 和一个评论。评论是:我应该提到我反序列化的所有子类都与基本抽象类在同一个包和同一个jar中。
抽象基类:
package so;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
@JsonTypeInfo(
use = JsonTypeInfo.Id.MINIMAL_CLASS,
include = JsonTypeInfo.As.PROPERTY,
property = "@class")
public abstract class PolyBase
{
public PolyBase() { }
@Override
public abstract boolean equals(Object obj);
}
它的一个子类:
package so;
import org.apache.commons.lang3.builder.EqualsBuilder;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
public final class SubA extends PolyBase
{
private final int a;
@JsonCreator
public SubA(@JsonProperty("a") int a) { this.a = a; }
public int getA() { return a; }
@Override
public boolean equals(Object obj) {
if (null == obj) return false;
if (this == obj) return true;
if (this.getClass() != obj.getClass()) return false;
SubA rhs = (SubA) obj;
return new EqualsBuilder().append(this.a, rhs.a).isEquals();
}
}
子类SubB
和SubC
是相同的,除了在a
中String
和int
(而不是SubB
)在boolean
中声明int
(不是SubC
)(并且相应地修改getA
方法)。
测试类:
package so;
import java.io.IOException;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.testng.annotations.Test;
import static org.assertj.core.api.Assertions.*;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
public class TestPoly
{
public static class TestClass
{
public PolyBase pb1, pb2, pb3;
@JsonCreator
public TestClass(@JsonProperty("pb1") PolyBase pb1,
@JsonProperty("pb2") PolyBase pb2,
@JsonProperty("pb3") PolyBase pb3)
{
this.pb1 = pb1;
this.pb2 = pb2;
this.pb3 = pb3;
}
@Override
public boolean equals(Object obj) {
if (null == obj) return false;
if (this == obj) return true;
if (this.getClass() != obj.getClass()) return false;
TestClass rhs = (TestClass) obj;
return new EqualsBuilder().append(pb1, rhs.pb1)
.append(pb2, rhs.pb2)
.append(pb3, rhs.pb3)
.isEquals();
}
}
@Test
public void jackson_should_or_should_not_deserialize_without_JsonSubTypes() {
// Arrange
PolyBase pb1 = new SubA(5), pb2 = new SubB("foobar"), pb3 = new SubC(true);
TestClass sut = new TestClass(pb1, pb2, pb3);
ObjectMapper mapper = new ObjectMapper();
// Act
String actual1 = null;
TestClass actual2 = null;
try {
actual1 = mapper.writeValueAsString(sut);
} catch (IOException e) {
fail("didn't serialize", e);
}
try {
actual2 = mapper.readValue(actual1, TestClass.class);
} catch (IOException e) {
fail("didn't deserialize", e);
}
// Assert
assertThat(actual2).isEqualTo(sut);
}
}
这个测试通过,如果你在第二个try {
线突破你可以检查actual1
并看到:
{"pb1":{"@class":".SubA","a":5},
"pb2":{"@class":".SubB","a":"foobar"},
"pb3":{"@class":".SubC","a":true}}
因此,三个子类被正确序列化(每个子类的类名称为id),然后反序列化,结果比较相等(每个子类都有一个“值类型”equals()
)。
有两种方法可以在Jackson中实现序列化和反序列化的多态性。它们在第1节中定义。在您发布的link中使用。
你的代码
@JsonTypeInfo(
use = JsonTypeInfo.Id.MINIMAL_CLASS,
include = JsonTypeInfo.As.PROPERTY,
property = "@class")
是第二种方法的一个例子。首先要注意的是
注释类型及其子类型的所有实例都使用这些设置(除非被另一个注释覆盖)
因此,此配置值传播到所有子类型。然后,我们需要一个类型标识符,它将Java类型映射到JSON字符串中的文本值,反之亦然。在您的示例中,这是由JsonTypeInfo.Id#MINIMAL_CLASS
给出的
表示具有最小路径的Java类名称用作类型标识符。
因此,从目标实例生成最小类名,并在序列化时写入JSON内容。或者使用最小类名来确定反序列化的目标类型。
你也可以使用JsonTypeInfo.Id#NAME
表示逻辑类型名称用作类型信息;然后需要将名称单独解析为实际的具体类型(
Class
)。
要提供这样的逻辑类型名称,请使用@JsonSubTypes
与
JsonTypeInfo
一起使用的注释,用于指示可序列化多态类型的子类型,以及关联JSON内容中使用的逻辑名称(比使用物理Java类名称更具可移植性)。
这只是实现相同结果的另一种方式。您询问有关州的文件
基于Java类名称的类型ID非常简单:它只是类名,可能是一些简单的前缀删除(对于“最小”变体)。但是类型名称是不同的:一个必须在逻辑名称和实际类之间进行映射。
因此,处理类名的各种JsonTypeInfo.Id
值是直截了当的,因为它们可以自动生成。但是,对于类型名称,您需要显式提供映射值。
以上是关于杰克逊的@JsonSubTypes仍然是多态反序列化所必需的吗?的主要内容,如果未能解决你的问题,请参考以下文章