使用 Spring 配置 CXF 以使用 MOXY 进行 XML 编组/解组 [英] Configuring CXF with Spring to use MOXY for XML marshalling/unmarshalling

查看:28
本文介绍了使用 Spring 配置 CXF 以使用 MOXY 进行 XML 编组/解组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 Java 服务器应用程序,它使用 CXF 来提供 SOAP 和 REST Web 服务.目前,它使用 JAX-B 的参考实现进行 XML 编组/解组,但我已将其配置为用 Jackson 替换 Jettison 进行 JSON 编组/解组.我使用 Spring 进行 DI 和应用程序上下文配置.

I have a Java server application that uses CXF to provide SOAP and REST web services. Currently it uses the reference implementation of JAX-B for XML marshalling/unmarshalling, but I have configured it to replace Jettison with Jackson for JSON marshalling/unmarshalling. I use Spring for DI and application context configuration.

REST Web 服务配置片段如下所示:

The REST web service configuration snippets looks as follows:

web.xml

<servlet>
    <display-name>Myapp REST Services</display-name>
    <servlet-name>MyappWebServices</servlet-name>
    <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>MyappWebServices</servlet-name>
    <url-pattern>/services/*</url-pattern>
</servlet-mapping>

applicationContext.xml

<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />

<bean id="jsonProvider" class="org.codehaus.jackson.jaxrs.JacksonJsonProvider" />

<jaxrs:server id="myappCoreSvcRest" address="/rest">
    <jaxrs:serviceBeans>
        <ref bean="fooService" />
        <ref bean="barService" />
    </jaxrs:serviceBeans>

    <jaxrs:providers>
        <ref bean="jsonProvider" />
    </jaxrs:providers>
</jaxrs:server>

此配置有效,将根据 HTTP 接受标头返回 XML 或 JSON.我喜欢这个配置的地方在于它基于 Spring,创建和使用备用 JSON 编码器非常容易.有关配置 CXF 的详细信息,请参见此处.

This configuration works and will return either XML or JSON depending on the HTTP Accept header. What I like about this configuration is that it is based in Spring and it is super easy to create and use an alternate JSON encoder. Details on configuring CXF can be found here.

我的问题是,现在我有一个新的(附加的)REST web 服务要提供,我想为这个新的 web 服务使用不同的 JAX-B XML 绑定.我知道 MOXy 可以做到这一点,但我无法弄清楚如何配置 CXF 端点,以便它使用 MOXy 进行编组/解组(以及如何将我的自定义 XML 映射文件告诉 Moxy).我还希望这个新的 Web 服务根据 Accept 标头返回 XML 或 JSON.我也读过 MOXy 2.4+ 也可以处理这个问题!

My problem is that now I have a new (additional) REST web service to provide and I would like to use a different JAX-B XML binding for this new web service. I understand that MOXy can do this, but I am unable to figure out how to configure a CXF end point so that it will use MOXy for marshalling/unmarshalling (and furthermore how to tell Moxy about my custom XML mapping file). I also would like this new web service to return either XML or JSON depending on the Accept header. I also have read that MOXy 2.4+ can handle that too!

理想情况下,我可以将 MOXy 用于这个新端点,而不会影响其他现有的 servlet.

Ideally I could use MOXy for this new endpoint without affecting the other existing servlets.

推荐答案

注意:我是EclipseLink JAXB (MOXy) 领导和成员 JAXB (JSR-222) 专家组.

Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.

我不知道 CXF 的确切配置,但在下面我提供了一些在 Spring 中使用 MOXy 的链接.请随时联系我,我可以帮助您实现这个:

Off hand I do not know the exact config for CXF, but below I have provided some links to using MOXy with Spring. Please feel free to contact me, and I can help you implement this:

我的问题是现在我有一个新的(附加的)REST Web 服务提供并且我想为此使用不同的 JAX-B XML 绑定新的网络服务.我知道 MOXy 可以做到这一点,但我做不到弄清楚如何配置 CXF 端点以便它使用MOXy 用于编组/解组(以及如何告诉 Moxy关于我的自定义 XML 映射文件).

My problem is that now I have a new (additional) REST web service to provide and I would like to use a different JAX-B XML binding for this new web service. I understand that MOXy can do this, but I am unable to figure out how to configure a CXF end point so that it will use MOXy for marshalling/unmarshalling (and furthermore how to tell Moxy about my custom XML mapping file).

在 JAX-RS 实现中使用 MOXy 时,您可以使用 ContextResolver 从 MOXy 的外部映射文件进行引导:

When using MOXy with a JAX-RS implementation you can use a ContextResolver to bootstrap from MOXy's external mapping file:

package blog.bindingfile.jaxrs;

import java.io.*;
import java.util.*;
import javax.ws.rs.Produces;
import javax.ws.rs.ext.*;
import javax.xml.bind.*;     
import org.eclipse.persistence.jaxb.JAXBContextFactory;

import blog.bindingfile.Customer;

@Provider
@Produces({"application/xml", "application/json"})
public class CustomerContextResolver implements ContextResolver<JAXBContext> {

    private JAXBContext jc;

    public CustomerContextResolver() {
        ClassLoader cl = Customer.class.getClassLoader();
        InputStream bindings =
            cl.getResourceAsStream("blog/bindingfile/binding.xml");
        try {
            Map<String, Object> props = new HashMap<String, Object>(1);
            props.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, bindings);
            jc = JAXBContext.newInstance(new Class[] {Customer.class} , props);
        } catch(JAXBException e) {
            throw new RuntimeException(e);
        } finally {
            try {
                bindings.close();
            } catch(IOException e) {
                throw new RuntimeException(e);
            }
        }
    }

    public JAXBContext getContext(Class<?> clazz) {
        if(Customer.class == clazz) {
            return jc;
        }
        return null;
    }

} 

对于一个复杂的例子

有关在 Spring 中使用 MOXy 的更多信息

我还希望这个新的 Web 服务返回 XML 或 JSON取决于 Accept 标头.我也读过 MOXy 2.4+ 可以也要处理!

I also would like this new web service to return either XML or JSON depending on the Accept header. I also have read that MOXy 2.4+ can handle that too!

是的,JSON 绑定正在添加到 EclipseLink 2.4.要在您的应用程序中利用它,只需创建一个 MessageBodyReader 和一个 MessageBodyWriter:

Yes, JSON binding is being added to EclipseLink 2.4. To leverage this in your application it should be a simple matter of creating a MessageBodyReader and a MessageBodyWriter:

package org.example;

import java.io.*;
import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import javax.xml.transform.stream.StreamSource;

import javax.ws.rs.*;
import javax.ws.rs.core.*;
import javax.ws.rs.ext.*;
import javax.xml.bind.*;

@Provider
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class MOXyJSONProvider implements 
    MessageBodyReader<Object>, MessageBodyWriter<Object>{

    @Context
    protected Providers providers;

    public boolean isReadable(Class<?> type, Type genericType,
        Annotation[] annotations, MediaType mediaType) {
        return true;
    }

    public Object readFrom(Class<Object> type, Type genericType,
            Annotation[] annotations, MediaType mediaType,
            MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
            throws IOException, WebApplicationException {
            try {
                Class<?> domainClass = getDomainClass(genericType);
                Unmarshaller u = getJAXBContext(domainClass, mediaType).createUnmarshaller();
                u.setProperty("eclipselink.media-type", mediaType.toString());
                u.setProperty("eclipselink.json.include-root", false);
                return u.unmarshal(new StreamSource(entityStream), domainClass).getValue();
            } catch(JAXBException jaxbException) {
                throw new WebApplicationException(jaxbException);
            }
    }

    public boolean isWriteable(Class<?> type, Type genericType,
        Annotation[] annotations, MediaType mediaType) {
        return true;
    }

    public void writeTo(Object object, Class<?> type, Type genericType,
        Annotation[] annotations, MediaType mediaType,
        MultivaluedMap<String, Object> httpHeaders,
        OutputStream entityStream) throws IOException,
        WebApplicationException {
        try {
            Class<?> domainClass = getDomainClass(genericType);
            Marshaller m = getJAXBContext(domainClass, mediaType).createMarshaller();
            m.setProperty("eclipselink.media-type", mediaType.toString());
            m.setProperty("eclipselink.json.include-root", false);
            m.marshal(object, entityStream);
        } catch(JAXBException jaxbException) {
            throw new WebApplicationException(jaxbException);
        }
    }

    public long getSize(Object t, Class<?> type, Type genericType,
        Annotation[] annotations, MediaType mediaType) {
        return -1;
    }

    private JAXBContext getJAXBContext(Class<?> type, MediaType mediaType) 
        throws JAXBException {
        ContextResolver<JAXBContext> resolver 
            = providers.getContextResolver(JAXBContext.class, mediaType);
        JAXBContext jaxbContext;
        if(null == resolver || null == (jaxbContext = resolver.getContext(type))) {
            return JAXBContext.newInstance(type);
        } else {
            return jaxbContext;
        }
    }

    private Class<?> getDomainClass(Type genericType) {
        if(genericType instanceof Class) {
            return (Class<?>) genericType;
        } else if(genericType instanceof ParameterizedType) {
            return (Class<?>) ((ParameterizedType) genericType).getActualTypeArguments()[0];
        } else {
            return null;
        }
    }

}

您也可以创建 JSONProvider 的扩展:

You may also be able to create an extension of JSONProvider:

了解更多信息

这篇关于使用 Spring 配置 CXF 以使用 MOXY 进行 XML 编组/解组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆