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();
我必须实例化一个 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();