Jsf 如何在@FacesConverter中注入@EJB、@PersistenceContext、@inject、@Autowired等?

Jsf 如何在@FacesConverter中注入@EJB、@PersistenceContext、@inject、@Autowired等?,jsf,dependency-injection,ejb,converter,Jsf,Dependency Injection,Ejb,Converter,如何在@FacesConverter中插入像@EJB、@PersistenceContext、@inject、@AutoWired等依赖项?在我的特定情况下,我需要通过@EJB: @FacesConverter public class MyConverter implements Converter { @EJB protected MyService myService; @Override public Object getAsObject(FacesConte

如何在
@FacesConverter
中插入像
@EJB
@PersistenceContext
@inject
@AutoWired
等依赖项?在我的特定情况下,我需要通过
@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

不,直到JSF2.3发布。JSF/CDI人员正在为JSF2.3进行这方面的工作。另请参阅我的同事Arjan Tijms的相关文章。只有在将
@EJB
@PersistenceContext
@Inject
等依赖项注入显式添加到注释时,才能在
@facescoverter
中工作

@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;
        // ...
    }
    
    将其引用为
    而不是
    ,或引用为
    而不是
    。别忘了删除
    @FacesConverter
    注释

    缺点是您不能为class指定
    ,因此需要在视图中的任何位置手动定义转换器

  • 将其注入常规托管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");
    
    缺点是存在一定的风险,即这不是完全可移植的。另见

  • 安装。自1.6版以来,它在
    @facescoverter
    中透明地添加了对
    @EJB
    (和
    @Inject
    )的支持,无需进一步修改。另见。如果您碰巧需要用于
    的转换器,则另一种选择是使用其
    SelectItemsConverter
    ,它将根据所选项目自动执行转换作业,而无需任何数据库交互

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

  • 另见:

    如果您可以在web应用程序中容纳Seam Faces模块,那么答案是肯定的。请检查这篇文章。您可以以类似的方式使用@EJB。

    您可以通过FacesContext间接访问它,这是两种转换器方法中的一个参数

    转换器也可以用应用范围命名为CDI。访问facade时,使用同一类的两个实例。一个是转换器实例本身,哑,不知道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));
        }
    
    ...
    
    路易斯·查孔,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;
        }
    }
    
    从转换器最终访问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(“CuentaPreconverter”)
    公共类CuentaPresConverter实现转换器{
    @EJB
    RubroEJB RubroEJB;
    公共对象getAsObject(FacesContext fc、uic组件uic、字符串值){
    if(value!=null&&value.trim().length()>0){
    试一试{
    CuentPressService=(CuentPressService)fc.getExternalContext().getApplicationMap().get(“CuentPressService”);
    List listCuentas=service.getCFGCOUNTAEJB().getAllCFGCOUNTAPRES();
    ................
    
    @Inject仅在CDI管理的实例中有效

    这只适用于至少JavaEE7CDI1.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();
      }
    
    }
    

    ejb查找应该是可移植的否?@Kalpesh:取决于您如何打包ejb和appserver make/version。@BalusC我知道这个问题很老,但它是“坏”的吗要从
    UIComponent
    检索
    UISelectItems
    ,然后迭代此选择项列表并找到值?我的意思是您需要任何注入或向数据库发送请求(如果问题不清楚,我可以用一个示例开始一个新问题)@OuerghiYassine:这个转换器已经存在了:JSF2.3本周发布了!耶!这是怎么回答这个问题的?我猜这可能是这个问题的答案,但是没有解释就很难说。。。
    @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();
      }
    
    }