Reputation: 6892
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.
Upvotes: 10
Views: 10204
Reputation: 321
If someone still have to deal with this kind of issue, Springboot provide an elegant solution :
Any beans of type com.fasterxml.jackson.databind.Module are automatically registered with the auto-configured Jackson2ObjectMapperBuilder and are applied to any ObjectMapper instances that it creates. This provides a global mechanism for contributing custom modules when you add new features to your application.
So adding this in one of your configuration class should be enough:
@Bean
public Module jaxbModule() {
return new JaxbAnnotationModule();
}
Upvotes: 5
Reputation: 640
If solution by @Psycho Punch still not working for you, This is another alternative:
com.fasterxml.jackson.dataformat:jackson-dataformat-xml
dependency.use XmlMapper instead of ObjectMapper to your MappingJackson2XmlHttpMessageConverter
. For example:
XmlMapper xmlMapper = new XmlMapper();
xmlMapper.registerModule(new JaxbAnnotationModule());
forEach(converter -> {
((MappingJackson2XmlHttpMessageConverter) converter).setObjectMapper(xmlMapper)
});
HTH
Upvotes: 2
Reputation: 6892
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);
});
Upvotes: 5
Reputation: 34900
I suspect that in second case Spring simply ignores root level JAXB annotation, because by default Jackson will resolve name of the class properly.
In order to use JAXB annotations you have to use library jackson-xc
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-xc</artifactId>
</dependency>
These artilces may be also useful:
1) http://wiki.fasterxml.com/JacksonJAXBAnnotations
2) http://springinpractice.com/2011/12/06/jackson-json-jaxb2-xml-spring
3) How can we configure the internal Jackson mapper when using RestTemplate?
Upvotes: 0