本文介绍了如何在@FacesConverter 中注入@EJB、@PersistenceContext、@Inject、@Autowired 等?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何注入@EJB@PersistenceContext@Inject@AutoWired等依赖项,等在 @FacesConverter 中?在我的特定情况下,我需要通过 @EJB 注入 EJB:

@FacesConverter公共类 MyConverter 实现 Converter {@EJB受保护的 MyService myService;@覆盖公共对象 getAsObject(FacesContext 上下文,UIComponent 组件,字符串值){//myService.doSomething}}

然而,它没有被注入,它仍然是 null,从而导致 NPE.似乎 @PersistenceContext@Inject 也不起作用.

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

解决方案

不,直到 JSF 2.3 发布.JSF/CDI 人员正在为 JSF 2.3 进行这项工作.另请参阅 JSF 规范问题 1349 和相关的 JSF 2.3 中有哪些新功能?" 我的同事 Arjan Tijms 的文章.只有像 @EJB@PersistenceContext@Inject 等依赖注入才会在 @FacesConverter 中工作您明确地将 managed=true 属性添加到注释中.

@FacesConverter(value="yourConverter", managed=true)公共类 YourConverter 实现 Converter {@注入私人 YourService 服务;//...}

如果不是,那么正确"的方法是什么?

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

  1. 改为将其设为托管 bean.您可以通过 @ManagedBean@Named@Component 使其成为 JSF、CDI 或 Spring 托管 bean.下面的示例使其成为 JSF 托管 bean.

    @ManagedBean@RequestScoped公共类 YourConverter 实现 Converter {@EJB私人 YourService 服务;//...}

    下面的例子使它成为一个 CDI 管理的 bean.

    @Named@RequestScoped公共类 YourConverter 实现 Converter {@注入私人 YourService 服务;//...}

    将其引用为 <h:inputXxx converter="#{yourConverter}"> 而不是 <h:inputXxx converter="yourConverter">,或作为 <f:converter binding="#{yourConverter}"> 而不是 <f:converter converterId="yourConverter">.不要忘记删除 @FacesConverter 注释!

    缺点是不能指定forClass,因此需要在视图中的任何地方手动定义转换器.

  2. 改为将其注入到常规托管 bean 中.

    @ManagedBean@RequestScoped公共类你的豆{@EJB私人 YourService 服务;//...}

    在您的转换器中,通过 EL 获取或调用它.

    YourBean yourBean = context.getApplication().evaluateExpressionGet(context, "#{yourBean}", YourBean.class);//然后例如任何一个YourEntity yourEntity = yourBean.getService().findByStringId(value);//或者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,它将自动执行基于无需任何数据库交互即可选择项目.

    另见'null Converter'的转换错误设置值.

另见:

How can I inject a dependency like @EJB, @PersistenceContext, @Inject, @AutoWired, etc in a @FacesConverter? In my specific case I need to inject an EJB via @EJB:

@FacesConverter
public class MyConverter implements Converter {

  @EJB
  protected MyService myService;

  @Override
  public Object getAsObject(FacesContext context, UIComponent component, String value) {
    // myService.doSomething
  }

}

However, it didn't get injected and it remains null, resulting in NPEs. It seems that @PersistenceContext and @Inject also doesn't work.

How do I inject a service dependency in my converter so that I can access the DB?

解决方案

No, not until JSF 2.3 is released. The JSF/CDI guys are working on that for JSF 2.3. See also JSF spec issue 1349 and this related "What's new in JSF 2.3?" article of my fellow Arjan Tijms. Only then dependency injection like @EJB, @PersistenceContext, @Inject, etc will work in a @FacesConverter when you explicitly add managed=true attribute to the annotation.

@FacesConverter(value="yourConverter", managed=true)
public class YourConverter implements Converter {

    @Inject
    private YourService service;
    // ...
}


Before JSF 2.3, you have several options:

  1. Make it a managed bean instead. You can make it a JSF, CDI or Spring managed bean via @ManagedBean, @Named or @Component. The below example makes it a JSF managed bean.

    @ManagedBean
    @RequestScoped
    public class YourConverter implements Converter {
    
        @EJB
        private YourService service;
        // ...
    }
    

    And the below example makes it a CDI managed bean.

    @Named
    @RequestScoped
    public class YourConverter implements Converter {
    
        @Inject
        private YourService service;
        // ...
    }
    

    Reference it as <h:inputXxx converter="#{yourConverter}"> instead of <h:inputXxx converter="yourConverter">, or as <f:converter binding="#{yourConverter}"> instead of <f:converter converterId="yourConverter">. Don't forget to remove the @FacesConverter annotation!

    The disadvantage is that you cannot specify forClass and thus need to manually define the converter everywhere in the view where necessary.

  2. Inject it in a regular managed bean instead.

    @ManagedBean
    @RequestScoped
    public class YourBean {
    
        @EJB
        private YourService service;
        // ...
    }
    

    And in your converter, grab or call it via 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);
    

    This way you can keep using @FacesConverter.

  3. Manually grab the EJB from JNDI.

    YourService yourService = (YourService) new InitialContext().lookup("java:global/appName/YourService");
    

    The disadvantage is that there is a certain risk that this is not entirely portable. See also Inject EJB bean from JSF managed bean programmatically.

  4. Install OmniFaces. Since version 1.6, it transparently adds support for @EJB (and @Inject) in a @FacesConverter without any further modification. See also the showcase. If you happen to need the converter for <f:selectItem(s)>, then the alternative is to use its SelectItemsConverter which will automatically perform the conversion job based on select items without the need for any database interaction.

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

    See also Conversion Error setting value for 'null Converter'.

See also:

这篇关于如何在@FacesConverter 中注入@EJB、@PersistenceContext、@Inject、@Autowired 等?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-25 12:56