Инъекция CDI в FacesConverter
Из нескольких поисков это кажется проблемой, которая существует уже давно. Я написал FacesConverter, который выглядит следующим образом. Объект Category - это объект JPA, а CategoryControl - это DAO, который его выбирает.
@FacesConverter(value = "categoryConverter")
public class CategoryConverter implements Converter {
@Inject private CategoryControl cc;
public CategoryConverter() { }
@Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if (cc != null) return cc.getByName(value);
System.out.println("CategoryConverter().getAsObject(): no injection!");
return null;
}
@Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (!(value instanceof Category)) return null;
return ((Category) value).getName();
}
}
Как вы, наверное, уже догадались, я никогда не получу укол. Я получил этот обходной путь с этой страницы, которая выглядит так:
Workaround for this problem: create this method in your localeController:
public Converter getConverter()
{
return FacesContext.getCurrentInstance().getApplication().createConverter("localeConverter");
}
and use converter="#{localeController.converter}" in your h:selectOneMenu.
Однако я тоже не могу сделать эту работу. Мой поддерживающий компонент хорошо создает и возвращает конвертер, но не вводит объект в него.
Я использую MyFaces CODI 1.0.1. С текущим контейнером GlassFish/Weld. Может кто-нибудь предложить решение, прежде чем я перекодировать, чтобы не использовать конвертер?
4 ответа
Замещать
@FacesConverter(value = "categoryConverter")
от
@Named
и использовать
<h:inputSomething converter="#{categoryConverter}" />
или же
<f:converter binding="#{categoryConverter}" />
вместо
<h:inputSomething converter="categoryConverter" />
или же
<f:converter converterId="categoryConverter" />
Кстати, похожая проблема существует для @EJB
внутри @FacesConverter
, Тем не менее, он предлагает способ захвата JNDI вручную. Смотрите также Связь в JSF 2.0 - Получение EJB в @FacesConverter и @FacesValidator. Таким образом, вы можете использовать @FacesConverter(forClass=Category.class)
без определения вручную каждый раз. К сожалению, я не могу сказать с самого начала, как реализовать это для компонентов CDI.
Обновление: если вы используете библиотеку утилит JSF OmniFaces, начиная с версии 1.6 добавлена прозрачная поддержка использования @Inject
а также @EJB
в @FacesConverter
Класс без каких-либо дополнительных настроек или аннотаций. Смотрите также CDI @FacesConverter
пример витрины.
@Inject
Аннотация работает только в управляемых экземплярах CDI. Если вы хотите использовать функции CDI внутри экземпляра, не управляемого CDI (например, JSF Validator или JSF Converter), вы можете просто программировать с использованием API CDI.
Это работает только по крайней мере на сервере Java EE 7 + CDI 1.1.
@FacesValidator("userNameValidator")
public class UserNameValidator implements Validator {
private UserService userService;
public UserNameValidator(){
this.userService = CDI.current().select(UserService.class).get();
}
@Override
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
....
}
}
https://docs.oracle.com/javaee/7/api/javax/enterprise/inject/spi/CDI.html
Со всем AnnotationHell в Java EE люди забывают, как писать код.
Просто используйте @Advanced из CODI для вашего @FacesConverter, смотрите Wiki.
Как только конвертер или валидатор аннотируются с помощью @Advanced, можно использовать @Inject.
Согласно ответу BalusC, я решил добавить управляемые bean-компоненты JSF (requestcoped), которые содержали только @FacesConverter и Converter, для решения этой проблемы в моем приложении, поскольку я перехожу с управляемых bean-компонентов JSF на управляемые bean-компоненты CDI.
Я пробовал CODI @Advanced против @FacesConverter, но он вообще не вводит бин.