Инъекция 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, но он вообще не вводит бин.

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