gpt4 book ai didi

java - 如何配置 Jackson 以反序列化包含在基类上使用 @JsonTypeInfo 和 JsonSubTypes 注释的命名类型的列表?

转载 作者:行者123 更新时间:2023-11-30 10:22:29 27 4
gpt4 key购买 nike

我已经研究了实现对象类的最佳方式,继承并包含在一个对象中作为一个列表。

如果您知道处理该场景并提供正确答案的任何链接,我将很乐意将此视为重复并关闭此项目。我有以下类(class):

动物园

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import java.util.List;
import lombok.*;
@Getter
@Setter
@Builder(toBuilder = true)
@AllArgsConstructor
@NoArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
public class Zoo {
private String zooName;
private String zooLocation;
@JsonInclude(JsonInclude.Include.NON_EMPTY)
private @Singular List<Animal> animals;
}

动物

@Getter
@Setter
@Builder(builderMethodName = "parentBuilder")
@AllArgsConstructor
@NoArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonTypeInfo(
use = JsonTypeInfo.Id.NONE,
include = JsonTypeInfo.As.PROPERTY,
property = "type",
defaultImpl = Animal.class
)
@JsonSubTypes({
@JsonSubTypes.Type(value = Dog.class, name = "dog"),
@JsonSubTypes.Type(value = Elephant.class, name = "elephant")
})
public class Animal{
private String type;
private String nameTag;
}

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode(callSuper = false)
@JsonPropertyOrder({ "type", "nameTag"})
@JsonTypeName("dog")
public class Dog extends Animal{
private String barkingPower;
}

大象

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode(callSuper = false)
@JsonPropertyOrder({ "type", "nameTag"})
public class Elephant extends Animal{
private String weight;
}

模型助手

public final class ModelHelper {
private static final ObjectMapper MAPPER = new ObjectMapper();
.configure(SerializationFeature.WRITE_NULL_MAP_VALUES, false)
.setSerializationInclusion(JsonInclude.Include.NON_NULL)
.enableDefaultTypingAsProperty(
ObjectMapper.DefaultTyping.JAVA_LANG_OBJECT, "type");
public static <T> T fromJson(@NotNull final String json, final Class<T> objectClass) {
try {
return MAPPER.readValue(json, objectClass);
} catch (Exception e) {
final String message = String.format("Error de-serialising JSON '%s' to object of %s",
json, objectClass.getName());
log.warn(message, e);
return null;
}
}
}

我正在使用 ModelHelper 将 JSON 反序列化为一个对象:

String json = "{\"zooName\":\"Sydney Zoo\",\"zooLocation\":\"Sydney\",\"animals\":[{\"type\":\"dog\",\"nameTag\":\"Dog1\",\"barkingPower\":\"loud\"},{\"type\":\"elephant\",\"nameTag\":\"Elephant1\",\"weight\":\"heavy\"}]}";
mapper.readValue(json, Zoo.class);

当前反序列化Zoo只返回 Animal属性而不是 DogElephant属性。

我的问题是:

  1. 我可以收集到的是反序列化不起作用,因为 Zoo 中的 getter对于 List<Animal>是基类类型,反序列化无法计算出如何创建 DogElephant ,并根据签名生成 Animal .但我会认为通过输入 JsonTypeNameJsonSubTypes注释我已经标记了相关的子类。是这样吗?
  2. 是否Animal类必须定义为 abstract这行得通吗?
  3. 使它起作用的唯一方法是为类 Zoo 实现自定义反序列化吗?这是一个很好的例子吗:https://www.sghill.net/how-do-i-write-a-jackson-json-serializer-deserializer.html

如果代码不清楚,请告诉我,我会修复它。

最佳答案

您混合了大约 3 种方法来反序列化多态类型,考虑到 Jackson 经历了多少次迭代,这并不奇怪。

您将 Animal 标记为

@JsonTypeInfo(use = JsonTypeInfo.Id.NONE, include = JsonTypeInfo.As.PROPERTY, property = "type")

这告诉 Jackson 2 自相矛盾的事情:

  • includeproperty 字段声明您要使用名为 type 的属性
  • use 字段声明不应使用任何 ID 机制,从而有效地忽略您的类型信息。

最简单的“修复”是改用 JsonTypeInfo.Id.NAME,这将输出(我添加了 Lombok 的 @ToString):

Zoo(zooName=Sydney Zoo, zooLocation=Sydney, animals=[Dog(barkingPower=loud), Elephant(weight=heavy)])

现在你有了正确的类型识别。请注意,在这种情况下,不需要子类上的 @JsonTypeName 注释,因为您已经指定了一种解析类型的方法:@JsonTypeInfo 告诉反序列化器寻找一个type 属性和 @JsonSubTypes 告诉它将它的值(name 属性)映射到它的类(value属性(property))。您也不需要指定任何 ObjectMapper 配置。

@JsonTypeName 是干什么用的?它替换了 @JsonSubTypes 中的 name:

@JsonSubTypes({
@JsonSubTypes.Type(value = Dog.class, name = "dog"),
@JsonSubTypes.Type(value = Elephant.class) // no name
})
public class Animal { ... }

public class Dog extends Animal { ... }

@JsonTypeName("elephant") // name is here
public class Elephant extends Animal { ... }

这很有用,例如,如果您无权访问父类(super class)。

另一种无需注释即可完成所有这些操作的方法(同样,如果您无权访问类,这很有用)是配置映射器。您可以使用 @JsonSubTypes 而不是

MAPPER.registerSubtypes(new NamedType(Dog.class, "dog"), new NamedType(Elephant.class, "elephant"));

此处包括类型名称-类映射。

很可能有更多混合配置的方法,但这充分说明了这一点并回答了您的问题。

问题是我无法将父类(super class)属性与子类属性一起反序列化。它是一个或另一个。也许自定义反序列化器确实可以解决这个问题。

关于java - 如何配置 Jackson 以反序列化包含在基类上使用 @JsonTypeInfo 和 JsonSubTypes 注释的命名类型的列表?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47372486/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com