@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にアクセスできるように、コンバーターにサービスの依存関係を注入するにはどうすればよいですか?
_
@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より前は、いくつかのオプションがあります。
代わりにマネージド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
を指定できないため、必要に応じてビュー内のあらゆる場所でコンバーターを手動で定義する必要があることです。
代わりに、通常のマネージド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
_を使い続けることができます。
JNDIからEJBを手動で取得します。
_YourService yourService = (YourService) new InitialContext().lookup("Java:global/appName/YourService");
_
欠点は、これが完全に移植可能ではないという特定のリスクがあることです。 JSFマネージドBeanからプログラムでEJB Beanを注入する も参照してください。
インストール OmniFaces 。バージョン1.6以降、それ以上の変更を加えることなく、_@EJB
_に_@Inject
_(および_@FacesConverter
_)のサポートを透過的に追加します。 ショーケース も参照してください。 <f:selectItem(s)>
のコンバーターが必要な場合は、そのSelectItemsConverter
を使用して、データベースとの対話を必要とせずに、選択したアイテムに基づいて変換ジョブを自動的に実行します。
_<h:selectOneMenu ... converter="omnifaces.SelectItemsConverter">
_
'null Converter'の変換エラー設定値 も参照してください。
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));
}
...
@ 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();
}
}