I'm trying to automatically deserialize XML formatted response using Spring's RestTemplate. I'm using Jackson's jackson-dataformat-xml
module, for which Spring Boot is set to auto-configure. I want to use JAXB annotations in the class I want to deserialize to, but it won't seem to work. Here's a sample of what I want the class to look like:
@XmlRootElement(name="Book")
public class Book {
@XmlElement(name="Title")
private String title;
@XmlElement(name="Author")
private String author;
}
This is based on the following XML sample:
<Book>
<Title>My Book</Title>
<Author>Me</Author>
</Book>
However, with class annotated like that above, the fields are always set null
. I did some experiments and found out that the deserialization works if I use Jackson's @JsonProperty
to annotate the child elements:
@XmlRootElement(name="Book")
public class Book {
@JsonProperty("Title")
private String title;
@JsonProperty("Author")
private String author;
}
It works, but somehow I feel like it's kind of awkward. Is there a way to get the JAXB annotations work like in my first example?
Jackson provides jackson-module-jaxb-annotations
module for the XML databinding to work with JAXB annotations. However, I'm not sure how to setup the ObjectMapper
being used by RestTemplate
to use this module.
Jackson by default does not recognize JaxB annotations. To recognize them Jackson requires jackson-module-jaxb-annotations module.
Here, we'll try to send POST requests to the Person API by using the POST methods provided by the RestTemplate: postForObject, postForEntity, and postForLocation.
getForEntity. Retrieve an entity by doing a GET on the specified URL. The response is converted and stored in an ResponseEntity . URI Template variables are expanded using the given URI variables, if any.
To address this issue, I needed to register an instance of JaxbAnnotationModule
to every ObjectMapper
used by converters added to Spring's RestTemplate
. The class is included in Jackson's jackson-module-jaxb-annotations
module, which I added to my build through Gradle.
With the dependency added to my project, what I did next was to configure the RestTemplate
used by my application. The ObjectMapper
instances are being used by MappingJackson2XmlHttpMessageConverter
s configured automatically by Spring. I had to register JaxbAnnotationModule
instance to each ObjectMapper
used in every converter, so the first task was to find all MappingJackson2XmlHttpMessageConverter
s using:
//create module
JaxbAnnotationModule jaxbAnnotationModule = new JaxbAnnotationModule();
restTemplate.getMessageConverters().stream().filter(converter -> {
return converter instanceof MappingJackson2XmlHttpMessageConverter;
})
Once I had all the relevant converters, I then registered the module to each of their ObjectMappers
:
forEach(converter -> {
((MappingJackson2XmlHttpMessageConverter) converter)
.getObjectMapper()
.register(jaxbAnnotationModule);
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With