web-dev-qa-db-ja.com

@ FacesConverterに@ EJB、@ PersistenceContext、@ Inject、@ Autowiredなどを挿入する方法は?

@EJB@PersistenceContext@Inject@AutoWiredなどの依存関係を@FacesConverterに挿入するにはどうすればよいですか?私の特定のケースでは、@EJBを介してEJBを挿入する必要があります。

@FacesConverter
public class MyConverter implements Converter {

  @EJB
  protected MyService myService;    

  @Override
  public Object getAsObject(FacesContext context, UIComponent component, String value) {
    // myService.doSomething
  }

}

ただし、注入されず、nullのままであるため、NPEが発生します。 @PersistenceContext@Injectも機能していないようです。

DBにアクセスできるように、コンバーターにサービスの依存関係を注入するにはどうすればよいですか?

28
user550738

_@EJB_を使用してサービスを_@FacesConverter_に注入できますか?

いいえ、JSF2.3がリリースされるまではありません。 JSF/CDIの担当者は、JSF2.3用に取り組んでいます。 JSF仕様の問題1349 およびこれに関連する "JSF 2.3の新機能" 私の仲間のArjanTijmsの記事も参照してください。アノテーションに_@EJB_属性を明示的に追加すると、_@PersistenceContext_、_@Inject_、_@FacesConverter_などの依存性注入が_managed=true_で機能します。

_@FacesConverter(value="yourConverter", managed=true)
public class YourConverter implements Converter {

    @Inject
    private YourService service;
    // ...
}
_

そうでない場合、これを行うための「正しい」方法は何ですか?

JSF 2.3より前は、いくつかのオプションがあります。

  1. 代わりにマネージドBeanにします。 _@ManagedBean_、_@Named_、または_@Component_を介して、JSF、CDI、またはSpringマネージドBeanにすることができます。以下の例では、JSFマネージドBeanになります。

    _@ManagedBean
    @RequestScoped
    public class YourConverter implements Converter {
    
        @EJB
        private YourService service;
        // ...
    }
    _

    そして、以下の例はそれをCDI管理のBeanにします。

    _@Named
    @RequestScoped
    public class YourConverter implements Converter {
    
        @Inject
        private YourService service;
        // ...
    }
    _

    _<h:inputXxx converter="#{yourConverter}">_ではなく_<h:inputXxx converter="yourConverter">_として、または_<f:converter binding="#{yourConverter}">_ではなく_<f:converter converterId="yourConverter">_として参照してください。 _@FacesConverter_アノテーションを削除することを忘れないでください!

    欠点は、forClassを指定できないため、必要に応じてビュー内のあらゆる場所でコンバーターを手動で定義する必要があることです。

  2. 代わりに、通常のマネージドBeanに注入してください。

    _@ManagedBean
    @RequestScoped
    public class YourBean {
    
        @EJB
        private YourService service;
        // ...
    }
    _

    そして、コンバーターで、ELを介してそれを取得または呼び出します。

    _YourBean yourBean = context.getApplication().evaluateExpressionGet(context, "#{yourBean}", YourBean.class);
    
    // Then e.g. either
    YourEntity yourEntity = yourBean.getService().findByStringId(value);
    // Or
    YourEntity yourEntity = yourBean.findEntityByStringId(value);
    _

    このようにして、_@FacesConverter_を使い続けることができます。

  3. JNDIからEJBを手動で取得します。

    _YourService yourService = (YourService) new InitialContext().lookup("Java:global/appName/YourService");
    _

    欠点は、これが完全に移植可能ではないという特定のリスクがあることです。 JSFマネージドBeanからプログラムでEJB Beanを注入する も参照してください。

  4. インストール OmniFaces 。バージョン1.6以降、それ以上の変更を加えることなく、_@EJB_に_@Inject_(および_@FacesConverter_)のサポートを透過的に追加します。 ショーケース も参照してください。 <f:selectItem(s)>のコンバーターが必要な場合は、そのSelectItemsConverterを使用して、データベースとの対話を必要とせずに、選択したアイテムに基づいて変換ジョブを自動的に実行します。

    _<h:selectOneMenu ... converter="omnifaces.SelectItemsConverter">
    _

    'null Converter'の変換エラー設定値 も参照してください。

参照:

53
BalusC

WebアプリケーションにSeamFacesモジュールを収容できる場合、答えは「はい」です。この投稿を確認してください FacesConverterへのEntityManagerまたはCDI Beanの挿入 。 @EJBも同様に使用できます。

両方のConverterメソッドのパラメーターであるFacesContextを介して間接的にアクセスできます。

コンバーターには、アプリケーションスコープで名前が付けられたCDIという注釈を付けることもできます。ファサードにアクセスするとき、同じクラスの2つのインスタンスが使用されます。 1つは、EJBアノテーションを知らない、コンバーターインスタンス自体です。別のインスタンスはアプリケーションスコープに保持され、FacesContextを介してアクセスできます。そのインスタンスはNamedオブジェクトであるため、EJBアノテーションを認識しています。すべてが単一のクラスで行われるため、アクセスを保護しておくことができます。

次の例を参照してください。

@FacesConverter(forClass=Product.class)
@Named
@ApplicationScoped
public class ProductConverter implements Converter{
    @EJB protected ProductFacade facade;

    protected ProductFacade getFacadeFromConverter(FacesContext ctx){
        if(facade==null){
            facade = ((ProductConverter) ctx.getApplication()
                .evaluateExpressionGet(ctx,"#{productConverter}",ProductConverter.class))
                .facade;
        }
        return facade;
    }

    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String value) {
        return getFacadeFromConverter(context).find(Long.parseLong(value));
    }

...
0
Pavel Sedek

@ InjectはCDIマネージドインスタンスでのみ機能します

これは、少なくともJava EE 7およびCDI 1.1サーバーでのみ機能します。

@FacesConverter
public class MyConverter implements Converter {

  protected MyService myService;    

  @Override
  public Object getAsObject(FacesContext context, UIComponent component, String value) {
      myService = CDI.current().select(MyService .class).get();
      myService.doSomething();
  }

}
0
ℛɑƒæĿ