【问题标题】:How to autowire default XmlMapper in Spring Boot application如何在 Spring Boot 应用程序中自动装配默认 XmlMapper
【发布时间】:2015-05-02 22:32:19
【问题描述】:

我在我的一个 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);
    }
}

Demo 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 创建的默认映射器。

【问题讨论】:

  • 可能Spring Boot在IoC容器中不包含XmlMapper,先尝试注入bean。
  • 我知道我可以创建自己的 XmlMapper,但我想要默认的,即实际用于将类映射到响应正文中的 Xml 的那个,它现在可以正常工作,所以某处必须有一个 XmlMapper 吗? @kris14an

标签: spring-boot xmlmapper


【解决方案1】:

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

【讨论】:

  • 我正在尝试用最新的 Spring-Boot 做同样的事情,但发现我无法自动装配 ObjectMapper 或 MappingJackson2XmlHttpMessageConverter。两者都会导致“No qualifying bean of type”错误。
  • @robross0606 检查问题中的 pom.xml 中是否有依赖项。
  • 已经检查过了。我正在使用 Gradle 进行依赖项管理,但已确认我在您的 Maven POM 中拥有与上面列出的所有相同的依赖项。
  • @robross0606 不确定,我专门为这个问题创建了那个最小的项目,没有更多的了。我不熟悉gradle。也许是一个新问题?
【解决方案2】:

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

【讨论】:

  • 这当然回答了这个问题。一个隐含的下一个问题是,“我可以通过其他方式获取 XmlMapper 吗?”,我发现您可以改为自动装配 MappingJackson2XmlHttpMessageConverter 并通过 .getObjectMapper() 获取 XmlMapper
  • 我正在尝试用最新的 Spring-Boot 做同样的事情,但发现我无法自动装配 ObjectMapper 或 MappingJackson2XmlHttpMessageConverter。两者都会导致“No qualifying bean of type”错误。
【解决方案3】:

有两种方法:

@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

【讨论】:

    猜你喜欢
    • 2018-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-06
    • 2019-10-27
    相关资源
    最近更新 更多