Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 484
Psycho Punch Avatar asked Dec 22 '16 16:12

Psycho Punch


People also ask

Can Jackson use JaxB annotations?

Jackson by default does not recognize JaxB annotations. To recognize them Jackson requires jackson-module-jaxb-annotations module.

Which method of RestTemplate is used for sending post request?

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.

What does RestTemplate getForEntity do?

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.


1 Answers

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);
});
like image 81
Psycho Punch Avatar answered Sep 19 '22 13:09

Psycho Punch