我有一个现有的Jersey webservice方法,它通过Http POST方法接受许多参数,该方法用于处理标准表单数据,application / x-www-form-urlencoded的内容类型;其中一个参数是字符串列表。下面是我所拥有的方法签名的一个例子。
@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正确生成并传递给方法时。
我现在需要制作一个可接受多部分请求的此方法的替代版本,以便也可以将文件与现有参数一起上传。所以我创建了一个非常相似的方法签名来使用多部分请求,如下所示。
@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测试中调用此方法来进行调用(与原始方法相同)但是我收到以下错误。
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被省略。
为了支持在处理多部分数据时接受List作为输入,是否需要做一些不同的事情? 鉴于这是一个可选参数,我预计无论如何都应该可以省略它,这是原始方法的情况。
用于调用方法的测试中的RESTAssured代码如下。
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,但得到相同的结果。
在此先感谢,任何帮助将不胜感激。
答案 0 :(得分:3)
在介绍了更多的球衣代码后,我得出的结论是,在使用多部分时,我的方法上不能有List类型的参数。 在进程中的某一点,Jersey循环遍历方法的每个参数,找到一个Injectable来读取每个参数的值(抱歉可能不是一个很好的解释,但我已经调试了尽可能多的内容),在类com.sun中.jersey.multipart.impl.FormDataMultiPartDispatchProvider 在getInjectables方法中有以下代码:
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。
为了解决这个问题,我刚刚改变了我的方法,接受p3的逗号分隔字符串代替List。
答案 1 :(得分:0)
我遇到了另一种解决方案,它可能比手动处理列表的逗号分隔版本等更好(更简单)。过时发布以帮助其他人找到该帖子。
从以下位置更改multipart参数:
@FormDataParam("p3") List<String> p3,
到
@FormDataParam("p3") List<FormDataBodyPart> p3,
然后在P3中有您的列表,您可以在其中使用FormDataBodyPart
获得每个getValue()
元素的参数值。