I'm having some issues autowiring the default Jackson XmlMapper
in one of my Spring Boot projects. I've created a simple example project that illustrates this.
What I'm doing here is roughly based on this:
From pom.xml
<!-- ... -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.2.RELEASE</version>
</parent>
<!-- ... -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
</dependencies>
<!-- ... -->
The main class:
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
The Demo POJO, not specifying @XmlRootElement
, so it won't use JAXB:
@JsonInclude(Include.NON_NULL)
public class Demo {
private String stringProperty;
private int intProperty;
public String getStringProperty() {
return stringProperty;
}
public void setStringProperty(String stringProperty) {
this.stringProperty = stringProperty;
}
public int getIntProperty() {
return intProperty;
}
public void setIntProperty(int intProperty) {
this.intProperty = intProperty;
}
}
The Demo Controller:
@RestController
public class DemoController {
@Autowired
private ObjectMapper objectMapper;
// @Autowired
// private XmlMapper xmlMapper;
@RequestMapping(value = "/demo", method = RequestMethod.GET)
public Demo getDemo() {
Demo demo = new Demo();
demo.setStringProperty("Hello world!");
demo.setIntProperty(42);
return demo;
}
}
Everything works fine the way it is, depending on Accept
headers, either JSON or XML will be returned.
I can easily autowire the default ObjectMapper
configured by Spring Boot. So far so good.
If I comment in the autowiring of the XmlMapper
I get:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.fasterxml.jackson.dataformat.xml.XmlMapper] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1301)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1047)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:942)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:533)
... 18 more
Any idea why this is? I would have assumed it to work the same way as the ObjectMapper
. Just to clarify, I don't want to customise the mappers, I simply want a reference to the default ones created by Spring Boot.
Based on the answer by @Andy Wilkinson I did some more digging and found a way to get at what I wanted. Spring Boot does not expose the XmlMapper
as a Bean but it does expose the message converter it is used in, which is MappingJackson2XmlHttpMessageConverter
. So I could auto-wire that bean and get the ObjectMapper
(which is now an XmlMapper
) from it.
The Demo Controller from my question now looks like this:
@RestController
public class DemoController {
@Autowired
private ObjectMapper objectMapper;
@Autowired
private MappingJackson2XmlHttpMessageConverter xmlConverter;
@RequestMapping(value = "/demo", method = RequestMethod.GET)
public Demo getDemo() {
Demo demo = new Demo();
demo.setStringProperty("Hello world!");
demo.setIntProperty(42);
ObjectMapper xmlMapper = xmlConverter.getObjectMapper();
return demo;
}
}