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

问题描述 投票:0回答:6

如何在

@EJB
中注入
@PersistenceContext
@Inject
@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
也不起作用。

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

jsf dependency-injection ejb converters
6个回答
54
投票

我可以使用

@EJB
将我的服务注入到
@FacesConverter
中吗?

不,直到 JSF 2.3 发布为止。 JSF/CDI 人员正在为 JSF 2.3 做这方面的工作。另请参阅 JSF 规范问题 1349 以及我的同事 Arjan Tijms 的相关 “JSF 2.3 中有哪些新功能?” 文章。只有这样,当您显式地将

@EJB
属性添加到注释时,像
@PersistenceContext
@Inject
@FacesConverter
等依赖注入才会在
managed=true
中工作。

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

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

如果不是,“正确”的方法是什么?

在 JSF 2.3 之前,您有多种选择:

  1. 改为将其设为托管 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
    ,因此需要在视图中的任意位置手动定义转换器。

  2. 将其注入常规托管 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

  3. 手动从 JNDI 获取 EJB。

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

    缺点是存在一定的风险,即不完全便携。另请参阅 以编程方式从 JSF 托管 bean 注入 EJB bean

  4. 安装OmniFaces。从 1.6 版本开始,它在

    @EJB
    中透明地添加了对
    @Inject
    (和
    @FacesConverter
    )的支持,无需任何进一步修改。另请参阅展示柜。如果您碰巧需要
    <f:selectItem(s)>
    的转换器,那么另一种方法是使用其
    SelectItemsConverter
    ,它将根据选择的项目自动执行转换作业,而不需要任何数据库交互。

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

    另请参阅 “null Converter”的转换错误设置值

另请参阅:


2
投票

如果您可以在 Web 应用程序中容纳 Seam Faces 模块,那么答案是肯定的。请查看这篇文章Injection of EntityManager or CDI Bean in FacesConverter。您可以以类似的方式使用@EJB。


0
投票

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

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

...

0
投票

@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();
  }

}

0
投票

更新 Jakarta Faces 4(尤其是 Mojarra 4.0.0.payara-p2)

这个周末我遇到了这个@EJB 注入不起作用问题并找到了这个线程,但今天的 Faces 版本没有答案。我想添加此更新只是为了记录。

不起作用...

@RequestScoped
@Named("miniController")
public class MiniController {
   ...
   MiniValue val;
   ...
}


@FacesConverter(managed = true, forClass = MiniValue.class, value ="miniConverter")
public class MiniConverter implements Serializable, Converter<MiniValue> {
  ...
  @EJB
  DemoBeanRemote bean;
  ...
}


...
<h:inputText value="#{miniController.val}" converter="miniConverter" />
...

什么对我有用:

@RequestScoped
@Named("miniController")
public class MiniController {
   ...
   MiniValue val;
   ...
}


@FacesConverter(managed = true, forClass = MiniValue.class)
public class MiniConverter implements Serializable, Converter<MiniValue> {
  ...
  @EJB
  DemoBeanRemote bean;
  ...
}


...
<h:inputText value="#{miniController.val}" />
...

也适用:

@RequestScoped
@Named("miniController")
public class MiniController {
   ...
   MiniValue val;
   ...
}


@FacesConverter(managed = true, value="miniConverter")
public class MiniConverter implements Serializable, Converter<MiniValue> {
  ...
  @EJB
  DemoBeanRemote bean;
  ...
}


...
<h:inputText value="#{miniController.val}" converter="miniConverter" />
...

The JavaDoc 说: “...应用程序用户应该理解的一个重要的微妙之处。不可能使用单个 @FacesConverter 注释在按类和按转换器中注册单个转换器实现 - id 数据结构...”


-4
投票

作者:路易斯·查孔,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 对象

@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();


                ................
© www.soinside.com 2019 - 2024. All rights reserved.