如何在@FacesConverter中注入@EJB,@PersistenceContext,@Inject,@Autowired等?

我怎么能注入一个依赖像@AutoWired@FacesConverter@AutoWired@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也不起作用。

如何在我的转换器中注入服务依赖项以便可以访问数据库?

我可以使用@EJB将我的服务注入@FacesConverter吗?

不,直到JSF 2.3发布。 JSF / CDI家伙正在为JSF 2.3做这个工作。 另请参阅JSF规范问题1349和与此相关的“JSF 2.3中的新增内容”? 我的同胞Arjan Tijms的文章。 只有像@FacesConverter等依赖注入才能在@FacesConverter工作,当你明确地向注解添加managed=true属性的时候。

 @FacesConverter(value="yourConverter", managed=true) public class YourConverter implements Converter { @Inject private YourService service; // ... } 

如果没有,那么做到这一点的“正确”方法是什么?

在JSF 2.3之前,你有几个选择:

  1. 使它成为一个托管的bean。 您可以通过@ @ManagedBean@Component @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 eg 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版以来,它在@FacesConverter透明地添加了对@EJB (和@Inject )的支持,而无需进一步修改。 另见展示 。 如果您碰巧需要<f:selectItem(s)>的转换器,那么另一种方法是使用它的SelectItemsConverter ,它将根据选择的项目自动执行转换作业,而不需要任何数据库交互。

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

    另请参阅“空转换器”的转换错误设置值 。

也可以看看:

  • 如何使用@EJB,@PersistenceContext,@Inject,@Autowired注入@FacesValidator
  • CDI注入到FacesConverter中
  • @FacesValidator@FacesConverter获取@EJB

如果您可以在Web应用程序中容纳Seam Faces模块,则答案为Yes。 请检查这个帖子在FacesConverter注入EntityManager或CDI Bean 。 你可以用类似的方式使用@EJB。

您可以通过FacesContext间接访问它,这是两个Converter方法中的一个参数。

该转换器也可以注释CDI命名与应用程序范围。 访问门面时,使用同一类的两个实例。 一个是转换器实例本身愚蠢,不知道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 7CDI 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(); } } 

由Luis Chacon,Sv

工作正常,测试

定义EJB:

 @Stateless @LocalBean public class RubroEJB { @PersistenceContext(unitName = "xxxxx") private EntityManager em; public List<CfgRubroPres> getAllCfgRubroPres(){ List<CfgRubroPres> rubros = null; Query q = em.createNamedQuery("xxxxxxx"); rubros = q.getResultList(); return rubros; } } 

用Aplication bean范围定义bean,获取EJB Object

 @ManagedBean(name="cuentaPresService", eager = true) @ApplicationScoped public class CuentaPresService { @EJB private RubroEJB cfgCuentaEJB; public RubroEJB getCfgCuentaEJB() { return cfgCuentaEJB; } public void setCfgCuentaEJB(RubroEJB cfgCuentaEJB) { this.cfgCuentaEJB = cfgCuentaEJB; } } 

最终从转换器访问Ejb对象:

 @FacesConverter("cuentaPresConverter") public class CuentaPresConverter implements Converter { @EJB RubroEJB rubroEJB; public Object getAsObject(FacesContext fc, UIComponent uic, String value) { if(value != null && value.trim().length() > 0) { try { CuentaPresService service = (CuentaPresService) fc.getExternalContext().getApplicationMap().get("cuentaPresService"); List<CfgCuentaPres> listCuentas=service.getCfgCuentaEJB().getAllCfgCuentaPres(); ................