接受List作为Jersey Web服务的参数,该Web服务使用多部分的内容类型 [英] Accepting a List as a parameter to a Jersey webservice that consumes a content type of multi-part

查看:128
本文介绍了接受List作为Jersey Web服务的参数,该Web服务使用多部分的内容类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个现有的Jersey webservice方法,它通过Http POST方法接受许多参数,该方法用于处理标准表单数据,application / x-www-form-urlencoded的内容类型;其中一个参数是字符串列表。下面是我拥有的方法签名的示例。

I had an existing Jersey webservice method that accepts a number of parameters via Http POST method which is designed to handle a standard form data, content type of application/x-www-form-urlencoded; one of these parameters was a list of Strings. Below is an example of the method signature I have.

@POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response createItem(
        @FormParam("p1") long p1,
        @FormParam("p2") String p2,
        @FormParam("p3") List<String> p3,
        @FormParam("p4") String p4,
        @Context UriInfo uriInfo
) throws SQLException {

这是正常工作的,当List中传递的多个p3参数由Jersey正确生成并传递给方法时。

This was working correctly and when multiple p3 parameters are passed in the List is correctly generated by Jersey and passed into the method.

我现在需要制作一个可以接受多部分请求的方法的替代版本,以便也可以将文件与现有参数一起上传。所以我创建了一个非常相似的方法签名来使用多部分请求,如下所示。

I now needed to make an alternative version of this method that would accept a multi-part request so that a file could also be uploaded along with the existing parameters. So I created a very similar method signature to consume the multi-part requests, example shown below.

@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
public Response createItemWithFile(
        @FormDataParam("p1") long p1,
        @FormDataParam("p2") String p2,
        @FormDataParam("p3") List<String> p3,
        @FormDataParam("p4") String p4,
        @FormDataParam("file") InputStream inputStream,
        @Context UriInfo uriInfo
) throws SQLException {

我将FormParam注释更改为FormDataParam,因为我认为在使用多个时需要这样做零件数据。我一直试图通过使用RESTAssured进行调用的JUnit测试调用此方法(与原始方法相同)但是我收到以下错误。

I changed the FormParam annotations to FormDataParam as I believe this is needed when consuming multi-part data. I have been trying to call this method from a JUnit test using RESTAssured to make the call (the same as had been done for the original method) but I get the following error.

java.lang.IllegalArgumentException: wrong number of arguments
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.sun.jersey.spi.container.JavaMethodInvokerFactory$1.invoke(JavaMethodInvokerFactory.java:60)
at com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$ResponseOutInvoker._dispatch(AbstractResourceMethodDispatchProvider.java:205)
at com.sun.jersey.server.impl.model.method.dispatch.ResourceJavaMethodDispatcher.dispatch(ResourceJavaMethodDispatcher.java:75)
at com.sun.jersey.server.impl.uri.rules.HttpMethodRule.accept(HttpMethodRule.java:288)

拥有在Jersey代码中加入一些断点,在堆栈跟踪中识别的一些点上,似乎已经识别出正确的调用方法,但是在尝试传递给它的参数列表中,省略了p3。

Having put some break points into the Jersey code, at some of the points indentified in the stack trace, it seems that it has identified the correct method to invoke, but in the list of parameters it is trying to pass to it, p3 is omitted.

为了支持在处理多部分数据时接受List作为输入,是否需要做一些不同的事情?
鉴于这是一个可选参数,我预计无论如何都应该可以省略它,这是原始方法的情况。

Is there something different that needs to be done in order to support accepting a List as an input when dealing with multi-part data? Given this is an optional parameter I expected it should be possible to omit it anyway, this is the case with the original method.

RESTAssured中的代码用于调用该方法的测试如下。

The RESTAssured code in the test being used to call the method is as follows.

Response response = given()                    
                .header("my_header", "xyz")
                .param("p1", "8000040")
                .param("p2", "sample string") 
                .param("p3", "first_value")
                .param("p4", "abcde")
                .multiPart("file", myFile1, inputStream)
                .expect()

我还尝试在RESTAssured测试代码中使用formParam代替param,但得到相同的结果。

I have also tried when using formParam in the RESTAssured test code in place of param, but get the same result.

在此先感谢,任何帮助将不胜感激。

Thanks in advance, any help would be appreciated.

推荐答案

已经穿过了更多的球衣代码,我的结论是我不能有一个段落使用多部分时我的方法上的类型列表。
在过程中的某一点,泽西循环遍历方法上的每个参数,找到一个Injectable来读取每个参数的值(抱歉可能不是一个很好的解释,但我调试了尽可能多的内容),在getInjectables方法中的类com.sun.jersey.multipart.impl.FormDataMultiPartDispatchProvider
是以下代码:

Having stepped through some more of the jersey code, my conclusion is that I can not have a parameter of type List on my method when using multi-part. At one point in the process Jersey loops through each paramter on the method finding an Injectable to read the value for each parameter (sorry probably not a great explaination, but I have debugged as much as I needed to), within the class com.sun.jersey.multipart.impl.FormDataMultiPartDispatchProvider in the getInjectables method is the following code:

 private List<Injectable> getInjectables(AbstractResourceMethod method) {
    List<Injectable> list = new ArrayList<Injectable>(method.getParameters().size());
    for (int i = 0; i < method.getParameters().size(); i++) {
        Parameter p = method.getParameters().get(i);
        if (Parameter.Source.ENTITY == p.getSource()) {
            if (FormDataMultiPart.class.isAssignableFrom(p.getParameterClass())) {
                list.add(new FormDataMultiPartInjectable());
            } else {
                list.add(null);
            }
        } else if (p.getAnnotation().annotationType() == FormDataParam.class) {
            if (Collection.class == p.getParameterClass() || List.class == p.getParameterClass()) {
                Class c = ReflectionHelper.getGenericClass(p.getParameterType());
                if (FormDataBodyPart.class == c) {
                    list.add(new ListFormDataBodyPartMultiPartInjectable(p.getSourceName()));
                } else if (FormDataContentDisposition.class == c) {
                    list.add(new ListFormDataContentDispositionMultiPartInjectable(p.getSourceName()));
                }
            } else if (FormDataBodyPart.class == p.getParameterClass()) {
                list.add(new FormDataBodyPartMultiPartInjectable(p.getSourceName()));
            } else if (FormDataContentDisposition.class == p.getParameterClass()) {
                list.add(new FormDataContentDispositionMultiPartInjectable(p.getSourceName()));
            } else {
                list.add(new FormDataMultiPartParamInjectable(p));
            }
        } else {
            Injectable injectable = getInjectableProviderContext().getInjectable(p, ComponentScope.PerRequest);
            list.add(injectable);
        }
    }
    return list;
}

因此,当它看到参数类型是List或Collection时,它会忽略它其中泛型类型不是FormDataBodyPart或FormDataContentDisposition。

So where it sees the parameter type is a List or Collection it will ignore it where the generic type is anything other than FormDataBodyPart or FormDataContentDisposition.

为了解决这个问题,我刚刚改变了我的方法,接受逗号分隔的字符串代替p3代替a清单。

To get round the issue I have just changed my method to accept a comma delimited String for p3 in place of a List.

这篇关于接受List作为Jersey Web服务的参数,该Web服务使用多部分的内容类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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