Как добавить @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 у вас есть несколько вариантов:
Вместо этого сделайте это управляемым бобом. Вы можете сделать это 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
и, следовательно, необходимо вручную определить конвертер везде, где это необходимо.Вместо этого введите его в обычный управляемый компонент.
@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");
Недостатком является то, что существует определенный риск, что он не является полностью переносимым. См. Также Программный компонент EJB Inject EJB из управляемого компонента JSF.
Установите OmniFaces. Начиная с версии 1.6, он прозрачно добавляет поддержку
@EJB
(а также@Inject
) в@FacesConverter
без каких-либо дальнейших изменений. Смотрите также витрину. Если вам понадобится конвертер для<f:selectItem(s)>
то альтернатива состоит в том, чтобы использовать егоSelectItemsConverter
которая автоматически выполнит задание преобразования на основе выбранных элементов без какого-либо взаимодействия с базой данных.<h:selectOneMenu ... converter="omnifaces.SelectItemsConverter">
См. Также значение параметра "Ошибка преобразования" для "нулевого преобразователя".
Смотрите также:
- Как добавить в @FacesValidator с помощью @EJB, @PersistenceContext, @Inject, @Autowired
- Инъекция CDI в FacesConverter
- Получение
@EJB
в@FacesValidator
а также@FacesConverter
Ответ Да, если вы можете разместить модуль 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();
................