如何在@FacesConverter 中注入@EJB、@PersistenceContext、@Inject、@Autowired 等?
Posted
技术标签:
【中文标题】如何在@FacesConverter 中注入@EJB、@PersistenceContext、@Inject、@Autowired 等?【英文标题】:How to inject @EJB, @PersistenceContext, @Inject, @Autowired, etc in @FacesConverter? 【发布时间】:2011-12-01 17:09:00 【问题描述】:如何在@FacesConverter
中注入@EJB
、@PersistenceContext
、@Inject
、@AutoWired
等依赖项?在我的具体情况下,我需要通过@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
也不起作用。
如何在转换器中注入服务依赖项以便访问数据库?
【问题讨论】:
【参考方案1】:我可以使用
@EJB
将我的服务注入@FacesConverter
吗?
不,直到 JSF 2.3 发布。 JSF/CDI 人员正在为 JSF 2.3 做这方面的工作。另请参阅 JSF spec issue 1349 和我的同事 Arjan Tijms 的这篇相关的 "What's new in JSF 2.3?" 文章。只有当您将managed=true
属性显式添加到注释时,@EJB
、@PersistenceContext
、@Inject
等依赖注入才能在@FacesConverter
中工作。
@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");
缺点是存在一定的风险,即不完全便携。另见Inject EJB bean from JSF managed bean programmatically。
安装OmniFaces。从 1.6 版开始,它在@FacesConverter
中透明地添加了对@EJB
(和@Inject
)的支持,无需进一步修改。另见the showcase。如果您碰巧需要<f:selectItem(s)>
的转换器,那么另一种选择是使用它的SelectItemsConverter
,它将根据所选项目自动执行转换工作,而无需任何数据库交互。
<h:selectOneMenu ... converter="omnifaces.SelectItemsConverter">
另见Conversion Error setting value for 'null Converter'。
另见:
How to inject in @FacesValidator with @EJB, @PersistenceContext, @Inject, @Autowired CDI Injection into a FacesConverter Getting an@EJB
in a @FacesValidator
and @FacesConverter
【讨论】:
ejb 查找应该是可移植的吧? @Kalpesh:取决于您如何打包 EJB 以及应用服务器的品牌/版本。 @BalusC 我知道这个问题已经过时了,但是从UIComponent
中检索UISelectItems
是否“不好”,然后遍历这个选择项列表并找到值?我的意思是你需要任何注入或向数据库发送请求(如果问题不清楚,我可以用一个例子开始一个新问题)
@OuerghiYassine:该转换器已经存在:showcase.omnifaces.org/converters/SelectItemsConverter
JSF 2.3 本周发布!耶! javaserverfaces.java.net/2.3/download.html【参考方案2】:
如果您可以在 Web 应用程序中容纳 Seam Faces 模块,答案是肯定的。请查看此帖子Injection of EntityManager or CDI Bean in FacesConverter。您可以以类似的方式使用@EJB。
【讨论】:
【参考方案3】:您可以通过 FacesContext 间接访问它,这是两个 Converter 方法中的参数。
转换器也可以注释 CDI Named with Application scope。当访问门面时,使用了同一个类的两个实例。一种是转换器实例本身,很笨,不知道 EJB 注释。另一个实例保留在应用程序范围内,可以通过 FacesContext 访问。该实例是一个命名对象,因此它知道 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));
...
【讨论】:
【参考方案4】:@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();
https://docs.oracle.com/javaee/7/api/javax/enterprise/inject/spi/CDI.html
https://***.com/a/33017416/5626568
【讨论】:
【参考方案5】: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;
定义具有应用程序bean范围的bean,用于获取EJB对象
@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();
................
【讨论】:
如何回答这个问题? 猜猜这可能是问题的答案,但没有解释很难说...以上是关于如何在@FacesConverter 中注入@EJB、@PersistenceContext、@Inject、@Autowired 等?的主要内容,如果未能解决你的问题,请参考以下文章
在较新版本的 JSF 中,@FacesValidator 和 @FacesConverter 中的 EJB 和 CDI 注入点无法通过 OmniFaces 工作
升级到 JSF 2.3 后,@Inject 在 @FacesConverter 中不起作用
使用 Express、Mongodb 和 EJ 显示下拉动态数据
php 在帖子中添加元变量(自定义字段,ej template-slug)#wordpress
如何在 c# (CA1307) 中使用 StringComparison?
java.lang.IllegalArgumentException:WFLYWELD0037:将持久性单元注入 CDI 托管 bean 时出错