Reputation: 2114
I am completely flabbergasted by this behavior.
I've configured a RestTemplate with a Jackson ObjectMapper that has a JacksonAnnotationIntrospector.
objectMapper.setAnnotationIntrospector(new JacksonAnnotationIntrospector() {
@Override
public Object findDeserializer(Annotated a) {
I have a response entity I need to deserialize, and it needs my custom annotation on one of its fields to work.
When MyEntity is deserialized, findDeserializer is never called, and deserialization fails. If I remove my custom annotation from MyEntityOne, findDeserializer IS called, but since the annotation isn't present anymore, deserialization still fails. But this is only the case if the annotation is on a field that is present in the json being deserialized. If I put the annotation on some made-up field that is not in json, then findDeserializer is called.
Stranger still, if I instead ask the RestTemplate to give me back a String, and I manually pass that to my configured ObjectMapper, then it works as expected and can deserialize respecting my custom annotation.
So this fails
restTemplate.exchange(
new URI(requestUrl),
HttpMethod.GET,
new HttpEntity<>(getHeaders()),
MyEntity.class
);
But this works
var response = restTemplate.exchange(
new URI(requestUrl),
HttpMethod.GET,
new HttpEntity<>(getHeaders()),
String.class
).getBody();
objectMapper.readValue(response, MyEntity.class)
objectMapper is the same one given to the RestTemplate via RestTemplateBuilder
builder.additionalMessageConverters(new MappingJackson2HttpMessageConverter(objectMapper))
Here's my custom annotation that marks a field as needing to use my custom deserializer
@Target(
{ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface EscapedJsonArray {
Class<?> value();
}
Upvotes: 0
Views: 999
Reputation: 2114
The issue was that the RestTemplate had multiple ObjectMappers. I still have no explanation for why it would choose its own ObjectMapper instead of the one I supplied in some circumstances but not others, but I resolved the issue by registering my ObjectMapper like this instead:
var restTemplate = restTemplateBuilder.build();
restTemplate.getMessageConverters().removeIf(converter -> converter.getClass().equals(MappingJackson2HttpMessageConverter.class));
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter(objectMapper));
Upvotes: 0