如何在Spring 3(MVC)中为JAXB2支持添加自定义ContentHander?

时间:2013-04-19 08:14:20

标签: spring spring-mvc marshalling cdata jaxb2

场景:我有一个使用Spring 3 MVC的Web应用程序。使用Spring 3中强大的新注释(@ Controller,@ ResseseBody等),我编写了一些带有@XML注释的域对象,用于将ajax调用编组到Web客户端。一切都很好。我声明我的Controller类具有带有根XML对象的返回类型@ResponseBody - 有效负载被正确编组并发送给客户端。

问题是内容中的某些数据违反了XML合规性。我需要在必要时用CDATA包装它。我在这里看到一个POST How to generate CDATA block using JAXB?建议使用自定义内容处理程序。好的,太棒了!

public class CDataContentHandler extends (SAXHandler|XMLSerializer|Other...) {
 // see http://www.w3.org/TR/xml/#syntax
 private static final Pattern XML_CHARS = Pattern.compile("[<>&]");

 public void characters(char[] ch, int start, int length) throws SAXException {
     boolean useCData = XML_CHARS.matcher(new String(c,start,length)).find();
     if (useCData) super.startCDATA();
       super.characters(ch, start, length);
     if (useCData) super.endCDATA();
 }

}

使用Spring MVC 3,我该如何实现?一切都是&#34;自动神奇地&#34;关于设置的JAXB方面为我完成,Spring读取方法的返回类型,查看返回类型的注释并从类路径中拾取JAXB2以进行编组(Object to XML转换)。那么&#34;钩子&#34;允许用户在配置中注册自定义内容处理程序?

使用EclipseLink JAXB实现就像将@XmlCDATA添加到相关的Object属性一样简单。是否有一些聪明的方法Spring可以帮助/将这个问题抽象为一个小的配置细节?

我知道Spring并没有与任何特定的实现相关联,但为了这个问题,我们可以假设我使用的是默认实现。我在这里尝试过文档http://static.springsource.org/spring-ws/site/reference/html/oxm.html,但根据我能理解的问题,它几乎没有帮助。

感谢所有回复,非常感谢。

更新

感谢Akshay下面的建议答案。这足以让我走上正轨。进一步调查,我发现Spring版本3.05和3.2之间有一点历史。在Spring 3.05中,注册自定义MessageConverter过去非常困难(这真的是这里的目标)。

此对话几乎解释了所要求的开发变更背后的想法: https://jira.springsource.org/browse/SPR-7504

这是一个指向通常需要的类覆盖的链接,用于构建一个cusom解决方案: http://static.springsource.org/spring/docs/3.1.0.M1/javadoc-api/org/springframework/http/converter/AbstractHttpMessageConverter.html

关于堆栈溢出的以下问题与我的要求非常相似(除了@ResponseBody讨论涉及JSON和jackson) - 目标基本相同。

Spring 3.2 and Jackson 2: add custom object mapper

所以它看起来像是使用,并且需要覆盖MarshallingHttpMessageConverter,注册到AnnotationMethodHandlerAdapter。在上面的链接中有一个推荐的解决方案,也可以巧妙地使用这些东西并将整个事物包装在自定义的注释背后。

我还没有开发出一个有效的解决方案,但是因为我问了这些问题,想要至少发布一些可以帮助其他同类问题的东西,以便开始。尽管如此,虽然这在春季3.2中得到了改善,但仍然需要一些狗吃晚餐来进行一些定制工作......我真的期待一个单线配置改变等。

而不是扭曲和弯曲Spring,或许对我的特定问题最简单的答案就是改变JAXB2实现并使用类似Eclipse Link JAXB的东西来开箱即用。

1 个答案:

答案 0 :(得分:0)

基本上你需要创建一个自定义的HttpMessageConverter。而不是依赖Spring默认使用的Jaxb2RootElementHttpMessageConverter。

不幸的是,定制一个转换器意味着你告诉spring你将负责加载你需要的所有转换器!根据您是否使用注释,组件扫描,Spring 3.1或更早版本等,这是相当复杂的并且可能变得复杂。此处解决了如何添加自定义转换器的问题:Custom HttpMessageConverter with @ResponseBody to do Json things

在自定义消息转换器中,您可以自由使用任何自定义JAXB2内容处理程序。

解决原始问题的另一种更简单的方法是使用自定义XmlJavaTypeAdapter。创建javax.xml.bind.annotation.adapters.XmlAdapter的自定义实现来处理CDATA,在marshal方法中用cdata括号包装返回值。然后在映射的pojo中,使用XmlAdapter注释,将其传递给自定义适配器的类,然后就可以完成了。

我自己没有实现适配器方法,因此无法提供示例代码。但它应该有效,而且不会做很多工作。

希望这有帮助。