73

注釈を介してステートレス EJBを JAX-RS Web サービスに挿入しようとしています。残念ながら、EJB は単なるものnullであり、NullPointerException使用しようとするとエラーが発生します。

@Path("book")
public class BookResource {

    @EJB
    private BookEJB bookEJB;

    public BookResource() {
    }

    @GET
    @Produces("application/xml")
    @Path("/{bookId}")
    public Book getBookById(@PathParam("bookId") Integer id)
    {
        return bookEJB.findById(id);
    }
}

私は何を間違っていますか?

ここに私のマシンに関するいくつかの情報があります:

  • グラスフィッシュ 3.1
  • Netbeans 6.9 RC 2
  • JavaEE6

いくつかの実用的な例を示してもらえますか?

4

7 に答える 7

113

これが機能するかどうかはわかりません。したがって、次のいずれかです。

オプション 1: インジェクション プロバイダー SPI を使用する

ルックアップを実行して EJB を注入するプロバイダーを実装します。見る:

com.sun.jersey:jersey-server:1.17 の例:

import com.sun.jersey.core.spi.component.ComponentContext;
import com.sun.jersey.core.spi.component.ComponentScope;
import com.sun.jersey.spi.inject.Injectable;
import com.sun.jersey.spi.inject.InjectableProvider;

import javax.ejb.EJB;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.ws.rs.ext.Provider;
import java.lang.reflect.Type;

/**
 * JAX-RS EJB Injection provider.
 */
@Provider
public class EJBProvider implements InjectableProvider<EJB, Type> {

    public ComponentScope getScope() {
        return ComponentScope.Singleton;
    }

    public Injectable getInjectable(ComponentContext cc, EJB ejb, Type t) {
        if (!(t instanceof Class)) return null;

        try {
            Class c = (Class)t;
            Context ic = new InitialContext();

            final Object o = ic.lookup(c.getName());

            return new Injectable<Object>() {
                public Object getValue() {
                    return o;
                }
            };
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}

オプション 2: BookResource を EJB にする

@Stateless
@Path("book")
public class BookResource {

    @EJB
    private BookEJB bookEJB;

    //...
}

見る:

オプション 3: CDI を使用する

@Path("book")
@RequestScoped
public class BookResource {

    @Inject
    private BookEJB bookEJB;

    //...
}

見る:

于 2010-06-12T15:36:43.843 に答える
15

このスレッドはかなり古いですが、昨日同じ問題と戦ったばかりです。これが私の解決策です:

クラス レベルで@javax.annotation.ManagedBeanを介して BookResource をマネージド Bean にするだけです。

これを機能させるには、beans.xml で CDI を有効にする必要があります。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
</beans>

BookResource が war ファイルの一部である場合、このファイルは WEB-INF にある必要があります。BookResource が ejbs と一緒にパッケージ化されている場合は、META-INF に配置します。

@EJB を使用する場合は、これで完了です。@Inject を介して EJB を注入する場合は、beans.xml を ejbs jar ファイルの META-INF にも配置する必要があります。

あなたがしていること: リソースがコンテナー管理されるべきであることをコンテナーに伝えているだけです。そのため、インジェクションとライフサイクル イベントをサポートします。したがって、ビジネス ファサードを EJB にプロモートすることなく作成できます。

これが機能するために javax.ws.rs.core.Application を拡張する必要はありません。BookResource は、ルート リソースとして自動的にスコープ指定されたリクエストです。

Glassfish 3.1.2 と Maven プロジェクトでテスト済み。

ハッピーコーディング。

于 2012-10-12T08:06:32.173 に答える
10

EJBまたはCDIコンポーネントにすることなく、JAX-RSリソースにインジェクションを行うことができます。ただし、JAX-RS リソースはシングルトンであってはならないことに注意してください。

したがって、このコードを使用してアプリケーションをセットアップします。これにより、BookResourceクラスがリクエストごとのJAX-RS リソースになります。

@javax.ws.rs.ApplicationPath("application")
public class InjectionApplication extends javax.ws.rs.core.Application {
  private Set<Object> singletons = new HashSet<Object>();
  private Set<Class<?>> classes = new HashSet<Class<?>>();

  public InjectionApplication() {
    // no instance is created, just class is listed
    classes.add(BookResource.class);
  }

  @Override
  public Set<Class<?>> getClasses() {
    return classes;
  }

  @Override
  public Set<Object> getSingletons() {
    return singletons;
  }
}

このセットアップでは、JAX-RS がリクエストごとにBookResourceをインスタンス化し、必要なすべての依存関係を注入できるようにします。BookResourceクラスをシングルトンの JAX-RS リソースにするなら、これはgetSingletonsに入れます

public Set<Object> getSingletons() {
  singletons.add(new BookResource());
  return singletons;
}

次に、JAX-RS ランタイムによって管理されないインスタンスを作成し、コンテナー内の誰も何も注入しようとしません。

于 2012-03-07T17:36:21.783 に答える
5

残念ながら、私の答えはコメントするには長すぎるので、ここに行きます。:)

Zeck さん、Pascal が提案したように、Bean を EJB にプロモートすることで正確に何をしているのかを認識していただければ幸いです。残念ながら、Java EE を使用して「クラスを EJB にする」ことは今日では簡単ですが、そうすることの意味を認識しておく必要があります。各 EJB は、それが提供する追加機能とともにオーバーヘッドを作成します。これらは、トランザクションを認識し、独自のコンテキストを持ち、完全な EJB ライフ サイクルに参加するなどです。

クリーンで再利用可能なアプローチのためにあなたがしなければならないと思うことはこれです:サーバーサービスへのアクセスを抽出します(これは、SessionFacadeを介してアクセスされることを願っています:) BusinessDelegateに。このデリゲートは、バックエンドにアクセスするために、ある種の JNDI ルックアップ (おそらくServiceLocator - はい、Java EE でも有効です!) を使用する必要があります。

オーケー、オフレコ: JNDI アクセスを手動で記述したくないために本当に、本当に、本当にインジェクションが必要な場合でも、デリゲートを EJB にすることができますが、それは...まあ、それは間違っているように感じます。:) そうすれば、JNDIルックアップアプローチに切り替えることにした場合、少なくとも後で別のものに簡単に置き換えることができます...

于 2011-09-01T07:11:29.543 に答える
1

アルジャンは正しいです。RS 用の Bean を作成する代わりに、EJB を初期化する別のクラスを作成しました

@Singleton
@LocalBean
public class Mediator {
    @EJB
    DatabaseInterface databaseFacade;

次の方法でヌルポインターを回避するには:

@Path("stock")
public class StockResource {
    @EJB
    DatabaseInterface databaseFacade;
...

それは実際にGFで動作します

于 2015-08-21T08:47:05.320 に答える
0

私は同じ問題を抱えており、コンテキストルックアップによって te EJB を呼び出して解決しました (インジェクションは不可能で、同じエラー NullPointerException が発生しました)。

于 2012-07-13T23:18:27.703 に答える