如何在 Spring Boot 中使用明确指定的编组器

Posted

技术标签:

【中文标题】如何在 Spring Boot 中使用明确指定的编组器【英文标题】:How to use an explicitly specified marshaller in Spring Boot 【发布时间】:2020-01-22 02:55:57 【问题描述】:

我正在尝试创建一个能够生成 XML 输出的 REST 服务(我有一个包装在 HATEOAS 对象中的自定义类)。映射是这样的:

@GetMapping("/customclass")
Resource<CustomClass> custom() 
    return new Resource<CustomClass>(new CustomClass());


Resolved [org.springframework.http.converter.HttpMessageNotWritableException: Could not marshal [Resource  content: CustomClass(a=10, string=abc), links: [] ]: null; nested exception is javax.xml.bind.MarshalException
 - with linked exception:
[com.sun.istack.internal.SAXException2: class test.CustomClass nor any of its super class is known to this context.
javax.xml.bind.JAXBException: class test.CustomClass nor any of its super class is known to this context.]]

我很确定我的 CustomClass 没有任何问题。如果我改用以下映射

@GetMapping("/customclass")
CustomClass custom() 
    return (new CustomClass());

然后它就可以正常工作了。

如果我尝试手动编组(通过在 main 方法中设置内容然后运行它),它也可以正常工作。如果我将 CustomClass 的实例包装在 Resource 实例中也可以。

据我了解,问题在于 SpringApplication 中的编组器正在使用只知道 HATEOAS 资源的上下文,我需要一些如何让它知道 CustomClass。

我尝试使用这样的东西(来自https://***.com/a/40398632)

@Configuration
public class ResponseResolver  
    @Bean
    public Marshaller marshaller() 
        try 
            System.out.println("getting marshaller");
            JAXBContext context = JAXBContext.newInstance(CustomClass.class, Resource.class);
            return context.createMarshaller();
         catch (JAXBException e) 
            throw new RuntimeException(e);
        
    

但这没有用(我在这里有很多猜测,因为我不太了解 Spring Boot 的内部工作原理)。

https://***.com/a/14073899 中也有一个有希望的回复,但 ContextResolver 不在我的项目类路径中。

我还考虑将 Resource 包装在另一个类中,然后使用 XmlSeeAlso 注释,但这会弄乱我的 XML 并且会有点难看。

那么是否可以定义一个 SpringApplication 能够获取的自定义 JAXBContext?

【问题讨论】:

【参考方案1】:

来自 Spring Boot 文档 Spring Message message converters

Spring MVC 使用 HttpMessageConverter 接口来转换 HTTP 请求和响应。明智的默认设置是开箱即用的。 例如,对象可以自动转换为 JSON(通过使用 Jackson 库)或 XML(通过使用 Jackson XML 扩展,如果 可用,或者如果 Jackson XML 扩展不可用,则使用 JAXB 可用的)。默认情况下,Jaxb2RootElementHttpMessageConverter – 将 Java 对象转换为 XML 或从 XML 转换(仅当 JAXB2 存在于 类路径)

自定义转换器配置

@Configuration
public class WebConfig implements WebMvcConfigurer 

    @Override
    public void configureMessageConverters(
      List<HttpMessageConverter<?>> converters) 

        messageConverters.add(createXmlHttpMessageConverter());
        messageConverters.add(new MappingJackson2HttpMessageConverter());
    
    private HttpMessageConverter<Object> createXmlHttpMessageConverter() 
        MarshallingHttpMessageConverter xmlConverter = 
          new MarshallingHttpMessageConverter();

        XStreamMarshaller xstreamMarshaller = new XStreamMarshaller();
        xmlConverter.setMarshaller(xstreamMarshaller);
        xmlConverter.setUnmarshaller(xstreamMarshaller);

        return xmlConverter;
    

【讨论】:

这为我指明了正确的方向,我设法让它发挥作用。您提供的代码有几个问题。出于某种原因,new MappingJackson2HttpMessageConverter()Accept:application/xml 请求没有任何影响。但是,在制作 createXmlHttpMessageConverter public 并向其添加 @Bean 注释时,您的解决方案确实有效(Spring boot 会自动将其拾取)。谢谢!知道为什么添加转换器是通过将这两个添加到列表中来实现的(完全不明白为什么会这样)?

以上是关于如何在 Spring Boot 中使用明确指定的编组器的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Spring Boot 中明确检查请求内容类型是不是与实际内容匹配?

如何使用千分尺指定我想在spring-boot中使用的指标的白名单

如何使用 Spring Boot 2.0 指定 Hibernate 映射?

如何使用千分尺指定我想要在spring-boot中使用的度量标准的白名单

使用 Spring boot 时的两个版本的 Hibernate

Spring boot的Controller类是如何指定HTML页面的