我想序列化一个“持有人”类,其中有一个值,其类型是从泛型派生。即“类HasValue”里面有一个“私人A值”。@JsonTypeInfo不包含“@class”ID到json时,包装类也有@JsonTypeInfo
此外,我已经和接口“Inf”和一个实现该接口的具体类“InfCls”。界面用@JsonTypeInfo标记,并被告知创建一个“@class”字段。
如果持有者类没有@JsonTypeInfo就可以了。但是当我补充说它打破了。
注意:虽然在此实例中我不需要@JsonTypeInfo(因为持有者始终是一个具体类),所以在需要时会出现同样的问题,所以我选择这个作为更简单的示例。下面
SCWE:
import static org.junit.Assert.assertEquals;
import java.util.Objects;
import org.junit.Test;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonTypeInfo.As;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
public class SerializationIssues {
// No @JsonTypeInfo on HasValue
@Test
public void json_HasValue_Inf_javaType() throws Exception {
HasValue<Inf> object = new HasValue<>(new InfCls(1));
ObjectMapper objectMapper = new ObjectMapper();
JavaType javaType = objectMapper.getDeserializationConfig().getTypeFactory().constructParametricType(HasValue.class, Inf.class);
String serialized = objectMapper.writerFor(javaType).writeValueAsString(object);
HasValue<?> deserialized = objectMapper.readValue(serialized, javaType);
assertEquals(object, deserialized);
}
// @JsonTypeInfo on HasValueId
@Test
public void json_HasValueId_Inf_javaType() throws Exception {
HasValueId<Inf> object = new HasValueId<>(new InfCls(1));
ObjectMapper objectMapper = new ObjectMapper();
JavaType javaType = objectMapper.getDeserializationConfig().getTypeFactory().constructParametricType(HasValueId.class, Inf.class);
String serialized = objectMapper.writerFor(javaType).writeValueAsString(object);
HasValueId<?> deserialized = objectMapper.readValue(serialized, javaType);
assertEquals(object, deserialized);
}
// ===== An interface and impl to test @JsonTypeInfo =====
@JsonTypeInfo(use = JsonTypeInfo.Id.MINIMAL_CLASS, include = As.PROPERTY, property = "@class")
public static interface Inf {
}
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, isGetterVisibility = JsonAutoDetect.Visibility.NONE, getterVisibility = JsonAutoDetect.Visibility.NONE, setterVisibility = JsonAutoDetect.Visibility.NONE)
public static class InfCls implements Inf {
private int val;
@JsonCreator
public InfCls(@JsonProperty("val") int val) {
this.val = val;
}
@Override
public String toString() {
return "InfCls [val=" + val + "]";
}
@Override
public int hashCode() {
return 31 * 1 + val;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
InfCls other = (InfCls) obj;
if (val != other.val)
return false;
return true;
}
}
// ===== A class that has a value =====
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, isGetterVisibility = JsonAutoDetect.Visibility.NONE, getterVisibility = JsonAutoDetect.Visibility.NONE, setterVisibility = JsonAutoDetect.Visibility.NONE)
public static class HasValue<A> {
private final A val;
@JsonCreator
public HasValue(@JsonProperty("val") A val) {
this.val = Objects.requireNonNull(val);
}
public A get() {
return val;
}
@Override
public String toString() {
return "HasValue [val=" + val + "]";
}
@Override
public int hashCode() {
return 31 * 1 + ((val == null) ? 0 : val.hashCode());
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
HasValue<?> other = (HasValue<?>) obj;
if (val == null) {
if (other.val != null)
return false;
} else if (!val.equals(other.val))
return false;
return true;
}
}
@JsonTypeInfo(use = JsonTypeInfo.Id.MINIMAL_CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class")
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, isGetterVisibility = JsonAutoDetect.Visibility.NONE, getterVisibility = JsonAutoDetect.Visibility.NONE, setterVisibility = JsonAutoDetect.Visibility.NONE)
public static class HasValueId<A> {
private final A val;
@JsonCreator
public HasValueId(@JsonProperty("val") A val) {
this.val = Objects.requireNonNull(val);
}
public A get() {
return val;
}
@Override
public String toString() {
return "HasValue [val=" + val + "]";
}
@Override
public int hashCode() {
return 31 * 1 + ((val == null) ? 0 : val.hashCode());
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
HasValueId<?> other = (HasValueId<?>) obj;
if (val == null) {
if (other.val != null)
return false;
} else if (!val.equals(other.val))
return false;
return true;
}
}
}
这确实解决了我的问题。感谢您的快速回复。 关于何时序列化器被“推出”有什么一般规则? –
对不起,模糊的术语,但我不知道官方语言是什么。如果你看看'ObjectWriter.Prefetch.forRootType',你会发现有问题的代码。一旦找到一个多态类型,它就会“解开”序列化程序,大概是为了让动态类型优先于静态。 – teppic