3

標準フォームデータ、application/x-www-form-urlencoded; のコンテンツタイプを処理するように設計されたHttp POSTメソッドを介して多くのパラメーターを受け入れる既存のJersey Webサービスメソッドがありました。これらのパラメーターの 1 つは文字列のリストでした。以下は、私が持っているメソッド署名の例です。

@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 {

これは正しく機能しており、リストに複数の 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)

いくつかのブレーク ポイントをジャージー コードに配置すると、スタック トレースで特定されたポイントのいくつかで、呼び出す正しいメソッドを特定したように見えますが、渡そうとするパラメーターのリストでは、p3 が省略されています。 .

マルチパート データを処理するときに入力としてリストを受け入れることをサポートするために行う必要がある別のことはありますか? これがオプションのパラメーターであることを考えると、とにかく省略できるはずだと思っていましたが、これは元のメソッドの場合です。

メソッドを呼び出すために使用されているテストの 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 の代わりに使用した場合も試しましたが、同じ結果が得られました。

事前に感謝します。

4

2 に答える 2

3

ジャージー コードをさらに詳しく調べた結果、マルチパートを使用する場合、メソッドで List 型のパラメーターを使用できないという結論に達しました。プロセスのある時点で、Jersey はメソッドの各パラメーターをループして、各パラメーターの値を読み取るための Injectable を見つけます (申し訳ありませんが、おそらく素晴らしい説明ではありませんが、必要なだけデバッグしました)、クラス com.sun 内でgetInjectables メソッドの .jersey.multipart.impl.FormDataMultiPartDispatchProvider は次のコードです。

 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 のカンマ区切りの文字列を受け入れるようにしました。

于 2012-06-18T15:32:28.467 に答える