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

How to autowire default XmlMapper in Spring Boot application

我在我的 Spring 引导项目之一中自动装配默认 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>

<!-- ... -->

主要class:

@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 headers,将返回 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.

创建的默认映射器

Spring Boot 不会将 XmlMapper 作为 bean 公开,因为它会与用于 JSON 映射的 ObjectMapper bean 冲突(Jackson 的 XmlMapper 是杰克逊 ObjectMapper).

的子类

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

有两种方法:

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

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

如果你想支持 JSON 和 XML 那么你应该使用

中描述的 BeanFactoryPostProcessor 方法自己注册这些 beans