使用Apache CXF通过REST解析String []请求参数

时间:2013-10-16 16:03:41

标签: java json cxf

我目前正在尝试使用CXF 2.6.4为REST应用程序开发一个简单的概念证明。我正采取非弹簧方式。我正在使用JBoss AS 7.1.1 Final作为我的网络服务器。

以下是我的网络服务类:

package restful.webservice;

import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import restful.entity.ControllerVersion;

@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class WebServiceRest implements WebServiceInterface
{

    @Override
    @POST
    @GET
    @Path("/getVersion")
    public ControllerVersion getVersion(String deviceID, String[] macAddresses)
    {

        return new ControllerVersion();
    }
}

ControllerVersion类:

package restful.entity;

@XmlRootElement(name = "ControllerVersion")
public class ControllerVersion {

    private String version="R1.1.0.0";

    public String getVersion() {
        return version;
    }

}

现在,当我尝试对我的Web服务进行REST调用时,我在服务器端遇到以下异常:

18:51:52,913 WARNING [org.apache.cxf.jaxrs.utils.JAXRSUtils] (http--0.0.0.0-8080-1) No message body reader has been found for request class String[], ContentType : application/json.
18:51:52,927 WARNING [org.apache.cxf.jaxrs.impl.WebApplicationExceptionMapper] (http--0.0.0.0-8080-1) javax.ws.rs.WebApplicationException
        at org.apache.cxf.jaxrs.utils.JAXRSUtils.readFromMessageBody(JAXRSUtils.java:1054)
        at org.apache.cxf.jaxrs.utils.JAXRSUtils.processParameter(JAXRSUtils.java:614)
        at org.apache.cxf.jaxrs.utils.JAXRSUtils.processParameters(JAXRSUtils.java:578)
        at org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.processRequest(JAXRSInInterceptor.java:238)
        at org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.handleMessage(JAXRSInInterceptor.java:89)
        at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:262)
        at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:121)
        at org.apache.cxf.transport.http.AbstractHTTPDestination.invoke(AbstractHTTPDestination.java:236)
        at org.apache.cxf.transport.servlet.ServletController.invokeDestination(ServletController.java:209)
        at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:154)
        at org.apache.cxf.transport.servlet.CXFNonSpringServlet.invoke(CXFNonSpringServlet.java:130)
        at org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java:225)
        at org.apache.cxf.transport.servlet.AbstractHTTPServlet.doPost(AbstractHTTPServlet.java:145)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:754)
        at org.apache.cxf.transport.servlet.AbstractHTTPServlet.service(AbstractHTTPServlet.java:201)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:329)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:275)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:161)
        at org.jboss.as.web.security.SecurityContextAssociationValve.invoke(SecurityContextAssociationValve.java:153)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:155)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:368)
        at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:877)
        at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:671)
        at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:930)
        at java.lang.Thread.run(Thread.java:662)

我在WEB-INF / lib下的库是:

cxf-api-2.6.4.jar
cxf-bundle-2.6.4.jar
cxf-rt-frontend-jaxrs-2.6.4.jar
cxf-rt-frontend-jaxrs.jar
cxf-rt-transports-http-2.6.4.jar
geronimo-servlet.jar
jaxb-api-2.2.5.jar
jaxb-impl-2.2.5.1.jar
jaxb-xjc-2.2.5.1.jar
jettison-1.3.4.jar
log4j-1.2.16.jar
neethi-3.0.2.jar
xmlschema-core-2.0.3.jar

有趣的是,我尝试做另一个项目,但这次在我的Web服务方法的签名中,我包含了一个自定义类。我在阅读自定义类实例的内容时没有问题,在将其返回给我的客户端时也没有问题。

我错过了什么吗?

更新 我尝试将以下内容添加到我的web.xml中:

<init-param>
  <param-name>jaxrs.providers</param-name>
  <param-value>
      org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider
      (writeXsiType=false)
  </param-value> 
</init-param>

并添加了以下依赖项:

jackson-jaxrs-1.9.2.jar
jackson-mapper-asl-1.9.2.jar
jackson-xc-1.9.2.jar

现在我遇到以下异常:

19:22:29,762 WARNING [org.apache.cxf.jaxrs.impl.WebApplicationExceptionMapper] (http--0.0.0.0-8080-1) javax.ws.rs.WebApplicationException: java.io.IOException: Stream closed
        at org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.processRequest(JAXRSInInterceptor.java:243)
        at org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.handleMessage(JAXRSInInterceptor.java:89)
        at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:262)
        at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:121)
        at org.apache.cxf.transport.http.AbstractHTTPDestination.invoke(AbstractHTTPDestination.java:236)
        at org.apache.cxf.transport.servlet.ServletController.invokeDestination(ServletController.java:209)
        at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:154)
        at org.apache.cxf.transport.servlet.CXFNonSpringServlet.invoke(CXFNonSpringServlet.java:130)
        at org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java:225)
        at org.apache.cxf.transport.servlet.AbstractHTTPServlet.doPost(AbstractHTTPServlet.java:145)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:754)
        at org.apache.cxf.transport.servlet.AbstractHTTPServlet.service(AbstractHTTPServlet.java:201)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:329)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:275)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:161)
        at org.jboss.as.web.security.SecurityContextAssociationValve.invoke(SecurityContextAssociationValve.java:153)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:155)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:368)
        at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:877)
        at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:671)
        at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:930)
        at java.lang.Thread.run(Thread.java:662)
Caused by: java.io.IOException: Stream closed
        at org.apache.catalina.connector.InputBuffer.read(InputBuffer.java:377)
        at org.apache.catalina.connector.CoyoteInputStream.read(CoyoteInputStream.java:193)
        at java.io.FilterInputStream.read(FilterInputStream.java:116)
        at org.codehaus.jackson.impl.ByteSourceBootstrapper.ensureLoaded(ByteSourceBootstrapper.java:507)
        at org.codehaus.jackson.impl.ByteSourceBootstrapper.detectEncoding(ByteSourceBootstrapper.java:129)
        at org.codehaus.jackson.impl.ByteSourceBootstrapper.constructParser(ByteSourceBootstrapper.java:224)
        at org.codehaus.jackson.JsonFactory._createJsonParser(JsonFactory.java:785)
        at org.codehaus.jackson.JsonFactory.createJsonParser(JsonFactory.java:561)
        at org.codehaus.jackson.jaxrs.JacksonJsonProvider.readFrom(JacksonJsonProvider.java:414)
        at org.apache.cxf.jaxrs.utils.JAXRSUtils.readFromMessageBody(JAXRSUtils.java:1038)
        at org.apache.cxf.jaxrs.utils.JAXRSUtils.processParameter(JAXRSUtils.java:614)
        at org.apache.cxf.jaxrs.utils.JAXRSUtils.processParameters(JAXRSUtils.java:578)

更新2: 我尝试使用不同的签名实现一个方法,这次,我省略了方法中的String数组:

public ControllerVersion getVersion(String deviceID)

没有String数组,一切都很完美。你觉得我应该怎么做?

3 个答案:

答案 0 :(得分:1)

我显然误解了REST是如何工作的。我最终解决问题的方法如下:

1-更改了我的网络服务签名:

@POST
@Path("/getVersion")
@Produces(MediaType.APPLICATION_JSON)
@Consumes({"application/xml", "application/json", "application/x-www-form-urlencoded"})
public ControllerVersion getVersion(@FormParam("deviceID") String deviceID,@FormParam("macAddresses") String macAddresses)

2-现在,确保客户端正在发送带有内容类型(application / x-www-form-urlencoded)的请求,并且客户端正确添加了与您在@FormParam注释中定义的表单参数相同的表单参数。

3-现在,您可以使用FlexJson等库来从JSon String反序列化您的参数。例如,我现在从客户端发送macAddresses作为JSon字符串:[“mac1”,“mac2”]。在服务器端,我使用以下方法将此JSon字符串转换为String []:

public static String[] parseStringArrayFromJSONArray(String jsonArray)
{
    String[] stringArray = null;
    try
    {
        JSONArray array = new JSONArray(jsonArray);
        if (array != null)
        {
            stringArray = new String[array.length()];

            for (int i = 0; i < array.length(); i++)
            {
                stringArray[i] = array.getString(i);
            }
        }
    } catch (Exception e)
    {
        stringArray = null;
    }

    return stringArray;
}

我希望这能帮助那些人。

答案 1 :(得分:0)

您正在使用@Consumes(MediaType.APPLICATION_JSON)。您需要添加jackson-core(可能还有一些jackson个依赖项)才能使转换生效。

答案 2 :(得分:0)

cxf默认使用jettison。为什么你有@GET和@POST注释? 但它说是

 java.io.IOException: Stream closed

因此很可能没有关闭输入流。