31

JAX-RSを使用してJavaでRESTWebサービスを実装することに慣れたばかりで、次の問題が発生しました。私のリソースクラスの1つは、インターフェイスの背後に抽象化されたストレージバックエンドへのアクセスを必要としStorageEngineます。現在のインスタンスをRESTリクエストを提供するリソースクラスに注入したいStorageEngineと思います。これを行うための良い方法は、@Contextアノテーションと適切なContextResolverクラスを使用することだと思いました。これは私がこれまでに持っているものです:

MyResource.java

class MyResource {
    @Context StorageEngine storage;
    [...]
}

StorageEngineProvider.java

@Provider
class StorageEngineProvider implements ContextResolver<StorageEngine> {
    private StorageEngine storage = new InMemoryStorageEngine();

    public StorageEngine getContext(Class<?> type) {
        if (type.equals(StorageEngine.class))
            return storage;
        return null;
    }
}

私はcom.sun.jersey.api.core.PackagesResourceConfigプロバイダーとリソースクラスを自動的に検出するために使用しています。ログによると、StorageEngineProviderクラスを適切に取得します(タイムスタンプや不要なものは意図的に省略されています)。

INFO: Root resource classes found:
    class MyResource
INFO: Provider classes found:
    class StorageEngineProvider

ただし、storage私のリソースクラスのの値は常にですnull-のコンストラクタStorageEngineProviderもそのgetContextメソッドもJerseyによって呼び出されることはありません。私はここで何が間違っているのですか?

4

5 に答える 5

19

私はあなたが望むことをするためのJAX-RS特有の方法はないと思います。最も近いのは次のことです。

@Path("/something/")
class MyResource {
    @Context
    javax.ws.rs.ext.Providers providers;

    @GET
    public Response get() {
        ContextResolver<StorageEngine> resolver = providers.getContextResolver(StorageEngine.class, MediaType.WILDCARD_TYPE);
        StorageEngine engine = resolver.get(StorageEngine.class);
        ...
    }
}

ただし、@ javax.ws.rs.core.Contextアノテーションとjavax.ws.rs.ext.ContextResolverは、実際にはJAX-RSに関連し、JAX-RSプロバイダーをサポートするタイプ向けであると思います。

ここでは、Javaコンテキストと依存性注入(JSR-299)の実装(Java EE 6で利用可能である必要があります)またはGoogleGuiceなどの他の依存性注入フレームワークを探すことをお勧めします。

于 2010-07-20T01:39:12.533 に答える
15

InjectableProviderを実装します。ほとんどの場合、PerRequestTypeInjectableProviderまたはSingletonTypeInjectableProviderを拡張します。

@Provider
public class StorageEngineResolver extends SingletonTypeInjectableProvider<Context, StorageEngine>{
    public MyContextResolver() {
        super(StorageEngine.class, new InMemoryStorageEngine());
    }
}

あなたに持ってもらいます:

@Context StorageEngine storage;
于 2013-03-19T07:04:34.653 に答える
2

私は別の方法を見つけました。私の場合、パーシテンスレイヤーからユーザーエンティティとして現在ログインしているユーザーを提供したいと思います。これはクラスです:

@RequestScoped
@Provider
public class CurrentUserProducer implements Serializable, ContextResolver<User> {

    /**
     * Default
     */
    private static final long serialVersionUID = 1L;


    @Context
    private SecurityContext secContext;

    @Inject
    private UserUtil userUtil;

    /**
     * Tries to find logged in user in user db (by name) and returns it. If not
     * found a new user with role {@link UserRole#USER} is created.
     * 
     * @return found user or a new user with role user
     */
    @Produces
    @CurrentUser
    public User getCurrentUser() {
        if (secContext == null) {
            throw new IllegalStateException("Can't inject security context - security context is null.");
        }
        return userUtil.getCreateUser(secContext.getUserPrincipal().getName(),
                                      secContext.isUserInRole(UserRole.ADMIN.name()));
    }

    @Override
    public User getContext(Class<?> type) {
        if (type.equals(User.class)) {
            return getCurrentUser();
        }
        return null;
    }

}

私はこのクラスをJax-Rsによって発見され、注入されるためにのみ使用implements ContextResolver<User>しました。現在のユーザーを取得するには、修飾子でCDIを使用します。したがって、現在のユーザーが必要なすべての場所で、次のように入力します。@ProviderSecurityContext@CurrentUser

@Inject
@CurrentUser
private User user;

本当に

@Context
private User user;

動作しません(ユーザーがnullです)。

于 2016-02-05T09:13:17.467 に答える
1

誰かがResteasyを使用している場合、これは私のために働いたものです。

このようなものを追加する場合:

ResteasyContext.pushContext(StorageEngine.class, new StorageEngine());

jaxrsフィルターのようなものにすると、次のようなことができます。

@GET
@Path("/some/path")
public Response someMethod(@Context StorageEngine myStorageEngine) {
 ...
}

これはResteasyに固有であり、のようなものはありませんSingletonTypeInjectableProvider

于 2019-06-15T03:50:12.803 に答える
0

私に適したパターン:注入する必要のあるオブジェクトを提供するフィールドをApplicationサブクラスに追加します。次に、抽象基本クラスを使用して「インジェクション」を実行します。

public abstract class ServiceBase {

    protected Database database;

    @Context
    public void setApplication(Application app) {
        YourApplication application = (YourApplication) app;
        database = application.getDatabase();
    }
}

データベースにアクセスする必要のあるすべてのサービスは、ServiceBaseを拡張し、保護されたフィールド(または必要に応じてゲッター)を介してデータベースを自動的に使用できるようになります。

これは、UndertowとResteasyで機能します。アプリケーションのインジェクションは標準のAFAICSでサポートされているため、理論的にはこれすべてのJAX-RS実装で機能するはずですが、他の設定ではテストしていません。

私にとって、Bryantのソリューションに対する利点は、データベースのようなアプリケーションスコープのシングルトンを取得できるようにするために、リゾルバークラスを作成する必要がないことでした。

于 2016-11-25T20:23:21.980 に答える