How do I use JAXB annotations with Spring RestTemplate?

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.

Answer

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 MappingJackson2XmlHttpMessageConverters 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 MappingJackson2XmlHttpMessageConverters 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);
});

Leave a Reply

Your email address will not be published. Required fields are marked *