Как вставить @EJB, @PersistenceContext, @Inject, @Autowired и т.д. В @FacesConverter?

Как я могу вложить зависимость, например @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 также не работают.

Как мне добавить зависимость в моем конвертере, чтобы я мог получить доступ к БД?

Ответ 1

Можно ли использовать @EJB для ввода моего сервиса в @FacesConverter?

Нет, только до тех пор, пока не будет выпущен JSF 2.3. Ребята JSF/CDI работают над этим для JSF 2.3. См. Также JSF spec issue 1349, и это связано с "Что нового в JSF 2.3?" моего коллеги Arjan Tijms. Только тогда инъекция зависимостей, такая как @EJB, @PersistenceContext, @Inject и т.д., Будет работать в @FacesConverter, когда вы явно добавляете атрибут managed=true к аннотации.

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

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

Если нет, то какой "правильный" способ сделать это?

Перед JSF 2.3 у вас есть несколько вариантов:

  • Сделайте это управляемым bean. Вы можете сделать его JSF, CDI или Spring bean через @ManagedBean, @Named или @Component. В приведенном ниже примере он управляется 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.

  • Вручную возьмите EJB от JNDI.

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

    Недостаток заключается в том, что существует определенный риск того, что это не совсем переносимо. См. Также Inject EJB bean из управляемого JSF bean программно.

  • Установите OmniFaces. Начиная с версии 1.6, она прозрачно добавляет поддержку @EJB@Inject) в @FacesConverter без каких-либо дополнительных изменений. См. Также витрина. Если вам нужен конвертер для <f:selectItem(s)>, то альтернативой является использование его SelectItemsConverter, который автоматически выполнит задание преобразования на основе элементов выбора без необходимости взаимодействия с базой данных.

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

    См. также Значение параметра ошибки преобразования для 'null Converter'.

См. также:

Ответ 2

Ответ: Да, если вы можете разместить модуль Seam Faces в своем веб-приложении. Пожалуйста, отметьте это сообщение Инъекция EntityManager или CDI Bean в FacesConverter. Вы можете использовать @EJB аналогичным образом.

Ответ 3

Вы можете получить доступ к нему косвенно через FacesContext, который является параметром в обоих методах конвертера.

Конвертер может быть также аннотирован 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));
    }

...

Ответ 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();
  }

}

Ответ 5

Луис Чакон, 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 с помощью области Aplication 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();


                ................