Как вставить @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();
................