4

リソースとフィルターに挿入したい POJO があります。

public final class MyObject { }

そのためのカスタム プロバイダーを実装しました。

@Provider
public final class MyProvider
extends AbstractHttpContextInjectable<MyObject>
implements InjectableProvider<Context, Type> {

    @Context private HttpServletRequest request;

    @Override
    public Injectable<MyObject> getInjectable(
            ComponentContext componentContext,
            Context annotation,
            Type type
    ) {
        if (type.equals(MyObject.class)) {
            return this;
        }
        return null;
    }

    @Override
    public ComponentScope getScope() {
        return ComponentScope.PerRequest;
    }

    @Override
    public MyObject getValue(HttpContext httpContext) {
        //in reality, use session info from injected request to create MyObject
        return new MyObject();
    }
}

オブジェクトがリソースに正常に挿入されました。

@Path("/test")
@ResourceFilters(MyFilter.class)
public final class MyResource {

    @Context private HttpServletRequest request;
    @Context private MyObject myObject;

    @GET
    public String execute() {

        System.out.println(request != null);  //true
        System.out.println(myObject != null); //true

        return "data";
    }
}

しかし、Jersey はそれをフィルターに挿入できません。

public final class MyFilter implements ResourceFilter {

    @Context private HttpServletRequest request;
    @Context private MyObject myObject;

    @Override
    public ContainerRequestFilter getRequestFilter() {
        return new ContainerRequestFilter() {
            @Override
            public ContainerRequest filter(ContainerRequest containerRequest) {

                System.out.println(request != null);  //true
                System.out.println(myObject != null); //false

                return containerRequest;
            }
        };
    }

    @Override
    public ContainerResponseFilter getResponseFilter() {
        return null;
    }
}

違いは、注入がスレッドローカルインスタンスに従うプロキシを使用して行われるという事実に関係していると推測していMyFilterます-これは、注釈が付けられたフィールド@Contextが外側のクラスで宣言されているためです。これは一度インスタンス化されますが、それらはリクエストごとにオブジェクトを注入するために使用されます。デバッグ中にステップスルーすると、 のインスタンスをラップするプロキシfilterを指していることがわかります。MyFilter.requestcom.sun.jersey.server.impl.container.servlet.ThreadLocalInvoker

フィルターにカスタム インジェクションを実行する必要があるカスタム プロバイダー (またはその他の実装) に欠けているものは何ですか?

私は現在、Jersey 1.1.4.1 で立ち往生していることに注意してください (申し訳ありません)。

編集: Jersey 1.17 を使用すると、代わりに起動時に例外が発生します:

SEVERE: フィールドの依存関係がありません: private mypackage.MyObject mypackage.MyFilter.myObject

4

2 に答える 2

1

JSR-311Providersの注入可能なインターフェースを使用して回避策を見つけました。まず、プロバイダーを実装する必要がありました。ContextResolver

@Provider
public final class MyProvider
extends AbstractHttpContextInjectable<MyObject>
implements InjectableProvider<Context, Type>, ContextResolver<MyObject> {

    ...

    @Override
    public MyObject getContext(Class<?> type) {
        //in reality, using the same logic as before
        return new MyObject();
    }
}

次にProviders、代わりにフィルターにインスタンスを注入しました。がfilter呼び出されると、それを使用してContextResolverforMyObjectを検索し、動的に取得します。

public final class MyFilter implements ResourceFilter {

    @Context private HttpServletRequest request;
    @Context private Providers providers;

    @Override
    public ContainerRequestFilter getRequestFilter() {
        return new ContainerRequestFilter() {
            @Override
            public ContainerRequest filter(ContainerRequest containerRequest) {

                final ContextResolver<MyObject> myObjectResolver =
                            providers.getContextResolver(MyObject.class, null);
                final MyObject myObject =
                            myObjectResolver.getContext(MyObject.class);

                System.out.println(request != null);  //true
                System.out.println(myObject != null); //true

                return containerRequest;
            }
        };
    }

    ...
}

クレジットは、について私に知らせてくれたこの回答Providersに送られます。解決策は機能しますが、きれいなものではありません。私はまだMyObjectどこにでも注入して、それを機能HttpServletRequestさせたいと思っています.

于 2013-03-26T05:45:39.920 に答える