如何在Spring Boot应用程序中自动装配默认的XmlMapper

时间:2015-03-02 14:21:02

标签: spring-boot xmlmapper

我在我的一个Spring Boot项目中遇到了一些自动装配默认Jackson XmlMapper的问题。我已经创建了一个简单的示例项目来说明这一点。

我在这里做的大致基于此:

http://docs.spring.io/spring-boot/docs/1.2.2.RELEASE/reference/htmlsingle/#howto-write-an-xml-rest-service

http://docs.spring.io/spring-boot/docs/1.2.2.RELEASE/reference/htmlsingle/#howto-customize-the-jackson-objectmapper

来自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>

<!-- ... -->

主要班级:

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

演示POJO,未指定@XmlRootElement,因此不会使用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;
    }
}

演示控制器:

@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;
    }
}

一切正常,取决于Accept标头,将返回JSON或XML。

我可以轻松自动装配Spring Boot配置的默认ObjectMapper。到目前为止一切都很好。

如果我在自动装配XmlMapper时发表评论:

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

知道为什么会这样吗?我会假设它的工作方式与ObjectMapper相同。只是为了澄清,我想要自定义映射器,我只想要引用Spring Boot创建的默认值。

3 个答案:

答案 0 :(得分:12)

根据@Andy Wilkinson的回答,我做了一些挖掘,找到了一种方法来达到我想要的目的。 Spring Boot不会将XmlMapper公开为Bean,但它会公开它所使用的消息转换器,即MappingJackson2XmlHttpMessageConverter。所以我可以自动连接那个bean并从中获取ObjectMapper(现在是XmlMapper)。

我的问题中的演示控制器现在看起来像这样:

@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;
    }
}

答案 1 :(得分:7)

Spring Boot不会将XmlMapper暴露为bean,因为它会与用于JSON映射的ObjectMapper bean冲突(Jackson的XmlMapper是Jackson的ObjectMapper的子类})。

答案 2 :(得分:0)

有两种方法:

@Bean
public XmlMapper xmlMapper(MappingJackson2XmlHttpMessageConverter converter) {
    return (XmlMapper) converter.getObjectMapper();
}

@Bean
@Primary
public ObjectMapper objectMapper(MappingJackson2XmlHttpMessageConverter converter) {
    return converter.getObjectMapper();
}

如果要支持JSON和XML,则应使用How to create multiple beans of same type according to configuration in Spring?

中所述的BeanFactoryPostProcessor方法自行注册这些bean。