如何在@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之前,你有几个选择:
-
使它成为一个托管的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
,因此需要在视图中的任何地方手动定义转换器。 -
将其注入到常规的托管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
。 -
从JNDI手动获取EJB。
YourService yourService = (YourService) new InitialContext().lookup("java:global/appName/YourService");
缺点是有一定的风险,这不是完全可移植的。 另请参见以编程方式从JSF托管bean注入EJB bean 。
-
安装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 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(); } }
由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(); ................