Как добавить @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 тоже не работает.

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

5 ответов

Решение

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

Нет, пока JSF 2.3 не будет выпущен. Над этим работают ребята из JSF/CDI для JSF 2.3. См. Также выпуск 1349 спецификации JSF и связанный с ним вопрос "Что нового в 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. Вместо этого сделайте это управляемым бобом. Вы можете сделать это JSF, CDI или Spring bean через @ManagedBean, @Named или же @Component, Приведенный ниже пример делает его управляемым компонентом JSF.

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

    А приведенный ниже пример делает его управляемым компонентом CDI.

    @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. Вместо этого введите его в обычный управляемый компонент.

    @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. Вручную возьмите EJB из JNDI.

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

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

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

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

    См. Также значение параметра "Ошибка преобразования" для "нулевого преобразователя".

Смотрите также:

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

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

}

Вы можете получить к нему косвенный доступ через 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));
    }

...

Луис Чакон, Св

Работает нормально, проверено

определение 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();


                ................
Другие вопросы по тегам