Java:在 json -SpringBoot 中使用“@class”将 json 反序列化为 rest 模板中的对象

Java: Deserialize a json to object in rest template using "@class" in json -SpringBoot

我必须实例化一个 class,它使用 @class 中的信息从 JSON 扩展抽象 class,如下所示。

"name": {
  "health": "xxx",
  "animal": {
    "_class": "com.example.Dog",
    "height" : "20"
    "color" : "white"
  }
},

这里的抽象 class 是动物,狗扩展了动物 class。那么利用@class中的信息,我们是不是可以直接实例化dog呢。这也是我在 restTemplate

中得到的回应
ResponseEntity<List<SomeListName>> response = restTemplate.exchange("http://10.150.15.172:8080/agencies", HttpMethod.GET, request, responseType);

执行该行时出现以下错误。 由于 POJO classes 是自动生成的,我不能使用像 @JsonTypeInfo

这样的注释

我正在使用 Spring 启动和 maven。 此错误出现在控制台中。

Could not read JSON: Can not construct instance of "MyPOJO", problem: abstract types either need to be mapped to concrete types, have custom deserializer, or be instantiated with additional type information

您可以使用 @JsonTypeInfo 注释,而不管生成 classes 的事实,只要遵守 MixIn's

"mix-in annotations are": a way to associate annotations with classes, without modifying (target) classes themselves.

That is, you can:

Define that annotations of a mix-in class (or interface) will be used with a target class (or interface) such that it appears as if the target class had all annotations that the mix-in class has (for purposes of configuring serialization / deserialization)

所以你可以写下你的 AnimalMixIn class,比如

@JsonTypeInfo(  
    use = JsonTypeInfo.Id.NAME,  
    include = JsonTypeInfo.As.PROPERTY,  
    property = "_class")  
@JsonSubTypes({  
    @Type(value = Cat.class, name = "com.example.Cat"),  
    @Type(value = Dog.class, name = "com.example.Dog") })  
abstract class AnimalMixIn  
{  

}  

并配置解串器

    ObjectMapper mapper = new ObjectMapper();  
    mapper.getDeserializationConfig().addMixInAnnotations(  
    Animal.class, AnimalMixIn.class);

由于您使用的是 Spring Boot,您可以查看以下博客 post 了解如何自定义 ObjectMapper 以使用 [=] 的 MixIns、Customizing the Jackson Object Mapper, note especially the mixIn 方法15=]

RestTemplate中使用自定义的ObjectMapper应该通过转换器来设置,比如

    RestTemplate restTemplate = new RestTemplate();
    List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
    MappingJackson2HttpMessageConverter jsonMessageConverter = new MappingJackson2HttpMessageConverter();
    jsonMessageConverter.setObjectMapper(objectMapper);
    messageConverters.add(jsonMessageConverter);
    restTemplate.setMessageConverters(messageConverters);
    return restTemplate;

作为对@Master Slave 回答的补充。他说

you can customize the ObjectMapper for using the MixIns, Customizing the Jackson Object Mapper, note especially the mixIn method of Jackson2ObjectMapperBuilder

但他没有为 RestTemplate 定义 ObjectMapper。以下是他的回答如何帮助我找出完整的答案。

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.addMixIn(Target.class, MixinClass.class)
    .setVisibility(VisibilityChecker.Std.defaultInstance()
        .withFieldVisibility(JsonAutoDetect.Visibility.ANY)
        .withGetterVisibility(JsonAutoDetect.Visibility.ANY)
        .withSetterVisibility(JsonAutoDetect.Visibility.ANY)
        .withCreatorVisibility(JsonAutoDetect.Visibility.ANY)
    );
List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
MappingJackson2HttpMessageConverter jsonMessageConverter = new MappingJackson2HttpMessageConverter();
jsonMessageConverter.setObjectMapper(objectMapper);
messageConverters.add(jsonMessageConverter);
restTemplate.setMessageConverters(messageConverters);
MyResponse response =
    restTemplate.exchange(request, new ParameterizedTypeReference<MyResponse>() {
    }).getBody();