我该如何使用JAXB注释与Spring RestTemplate?

10
我正在尝试使用Spring的RestTemplate自动反序列化XML格式响应。我正在使用Jackson的jackson-dataformat-xml模块,Spring Boot已进行了自动配置。 我想在要反序列化的类中使用JAXB注释,但它似乎无法工作。以下是我希望该类的示例:
@XmlRootElement(name="Book")
public class Book {

    @XmlElement(name="Title")
    private String title;
    @XmlElement(name="Author")
    private String author;

}

这是基于以下XML示例:
<Book>
    <Title>My Book</Title>
    <Author>Me</Author>
</Book>

然而,使用上述注释的类时,字段总是设置为null。我进行了一些实验,发现如果我使用Jackson的@JsonProperty来注释子元素,则反序列化会起作用:
@XmlRootElement(name="Book")
public class Book {

    @JsonProperty("Title")
    private String title;
    @JsonProperty("Author")
    private String author;

}

它能正常工作,但我觉得有点笨拙。是否有一种方法可以使JAXB注释像我的第一个示例那样工作?
Jackson提供jackson-module-jaxb-annotations模块,用于XML数据绑定与JAXB注释一起使用。但是,我不确定如何设置由RestTemplate使用的ObjectMapper来使用此模块。

你解决了吗?我其实也在尝试做同样的事情。 - dalvarezmartinez1
1
@dalvarezmartinez1 是的。请看下面我的解决方案。 - Psycho Punch
4个回答

5
为了解决这个问题,我需要为Spring的RestTemplate添加的转换器中使用的每个ObjectMapper注册一个 JaxbAnnotationModule实例。该类包含在Jackson的jackson-module-jaxb-annotations模块中,我通过Gradle将其添加到我的项目中。
添加了这个依赖项后,我接下来配置了应用程序使用的 RestTemplate。由Spring自动配置的MappingJackson2XmlHttpMessageConverter使用了ObjectMapper 实例。我必须向每个转换器中使用的每个ObjectMapper 注册一个JaxbAnnotationModule实例,因此第一件事是使用以下代码查找所有的MappingJackson2XmlHttpMessageConverter
//create module
JaxbAnnotationModule jaxbAnnotationModule = new JaxbAnnotationModule();

restTemplate.getMessageConverters().stream().filter(converter -> {
    return converter instanceof MappingJackson2XmlHttpMessageConverter;
})

我先获取了所有相关的转换器,然后在每个ObjectMapper中注册了该模块:

forEach(converter -> {
    ((MappingJackson2XmlHttpMessageConverter) converter)
            .getObjectMapper()
            .register(jaxbAnnotationModule);
});

4
如果有人仍然需要处理这种问题,Springboot 提供了一种优雅的解决方案:
任何类型为 com.fasterxml.jackson.databind.Module 的 Bean 都会自动注册到自配置的 Jackson2ObjectMapperBuilder 中,并且应用于它创建的任何 ObjectMapper 实例。 这为在向应用程序添加新功能时贡献自定义模块提供了全局机制。
因此,在您的一个配置类中添加此代码应该就足够了:
@Bean
public Module jaxbModule() {
    return new JaxbAnnotationModule();
}

来源:https://docs.spring.io/spring-boot/docs/current/reference/html/howto.html#howto-customize-the-jackson-objectmapper


这个方法在很多其他调整都失败的情况下起作用了。在使用xjc时,当无法调整注释时,这尤其有用。 - undefined

2
如果@Psycho Punch的解决方案对您仍然无效,这是另一种选择:
  • 添加 com.fasterxml.jackson.dataformat:jackson-dataformat-xml 依赖。
  • MappingJackson2XmlHttpMessageConverter 中的 ObjectMapper 替换为 XmlMapper。例如:

    XmlMapper xmlMapper = new XmlMapper();
    xmlMapper.registerModule(new JaxbAnnotationModule());
    
    forEach(converter -> {
        ((MappingJackson2XmlHttpMessageConverter) converter).setObjectMapper(xmlMapper)
    });
    

HTH


0

我怀疑在第二种情况下,Spring只是忽略了根级别的JAXB注释,因为默认情况下Jackson会正确解析类的名称。

为了使用JAXB注释,您必须使用库jackson-xc

<dependency>
    <groupId>org.codehaus.jackson</groupId>
    <artifactId>jackson-xc</artifactId>
</dependency>

这些文章可能也会有用:
1) http://wiki.fasterxml.com/JacksonJAXBAnnotations 2) http://springinpractice.com/2011/12/06/jackson-json-jaxb2-xml-spring 3) 当使用RestTemplate时,我们如何配置内部的Jackson mapper?

我在我的问题中错过了一些细节。然而,jackson-xc现在实际上已经过时了,用于将JAXB支持添加到Jackson的XML databind的当前模块是jackson-module-jaxb-annotations。我的问题是我不确定如何设置被RestTemplate使用的ObjectMapper来使用这个模块。 - Psycho Punch
https://dev59.com/nWox5IYBdhLWcg3wLhUA - Andremoniy
我尝试通过ObjectMapperregisterModule()方法注册模块,但是对象字段仍然返回null值。 - Psycho Punch

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接