Как добавить в @FacesValidator с помощью @EJB, @PersistenceContext, @Inject, @Autowired
Как я могу ввести зависимость как @EJB
, @PersistenceContext
, @Inject
, @AutoWired
и т. д. в @FacesValidator
? В моем конкретном случае мне нужно внедрить управляемый компонент Spring через @AutoWired
:
@FacesValidator("emailExistValidator")
public class EmailExistValidator implements Validator {
@Autowired
private UserDao userDao;
// ...
}
Однако, это не было введено, и это остается null
, в результате чего java.lang.NullPointerException
, Кажется, что @EJB
, @PersistenceContext
а также @Inject
тоже не работает.
Как ввести сервисную зависимость в мой валидатор, чтобы я мог получить доступ к БД?
1 ответ
@FacesValidator
не управляется контейнером для инъекций. Вы должны сделать это управляемым бобом. Используйте Spring's @Component
CDI @Named
или JSF @ManagedBean
вместо @FacesValidator
для того, чтобы сделать его управляемым компонентом и таким образом иметь право на внедрение зависимостей.
Например, если вы хотите использовать JSF @ManagedBean
:
@ManagedBean
@RequestScoped
public class EmailExistValidator implements Validator {
// ...
}
Вы также должны ссылаться на него как на управляемый компонент #{name}
в EL вместо идентификатора валидатора в жестко закодированной строке. Таким образом, так
<h:inputText ... validator="#{emailExistValidator.validate}" />
или же
<f:validator binding="#{emailExistValidator}" />
вместо
<h:inputText ... validator="emailExistValidator" />
или же
<f:validator validatorId="emailExistValidator" />
Это действительно неловко. Ребята из JSF подтвердили эту неловкую оплошность, и они сделают @FacesValidator
(а также @FacesConverter
) приемлемая цель инъекции в предстоящем JSF 2,2 2.3, см. Также выпуск спецификации JSF 763. Для EJB есть обходной путь, вручную извлекая его из JNDI, см. Также Получение @EJB в @FacesConverter и @FacesValidator. Если вам случится использовать расширение CDI MyFaces CODI, то вы также можете решить его, поставив @Advanced
аннотация по классу.
Смотрите также:
Обновление: если вы используете библиотеку утилит JSF OmniFaces, начиная с версии 1.6 добавлена прозрачная поддержка использования @Inject
а также @EJB
в @FacesValidator
Класс без каких-либо дополнительных настроек или аннотаций. Смотрите также CDI @FacesValidator
пример витрины.
Теперь вы можете вставлять в валидаторы JSF, если используете Java EE 8 и / или JSF 2.3.
Протестировано с использованием Mojarra 2.3.9.payara-p2 на Payara Server 5.192 #badassfish.
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html">
<h:body>
Hello from Facelets
<h:form>
<h:messages/>
<h:inputText value="#{someBean.txtField}" validator="someValidator"/>
</h:form>
</h:body>
</html>
import javax.inject.Named;
import javax.enterprise.context.Dependent;
@Named(value = "someBean")
@Dependent
public class SomeBean {
private String txtField;
public String getTxtField() {
return txtField;
}
public void setTxtField(String txtField) {
this.txtField = txtField;
}
}
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.validator.FacesValidator;
import javax.faces.validator.Validator;
import javax.faces.validator.ValidatorException;
import javax.inject.Inject;
@FacesValidator(value = "someValidator", managed = true)
public class CustomValidator implements Validator<String> {
@Inject
NewClass newClass;
@Override
public void validate(FacesContext context, UIComponent component, String value)
throws ValidatorException {
System.out.println("validator running");
System.out.println("injected bean: " + newClass);
if (value != null && value.equals("badvalue")) {
throw new ValidatorException(new FacesMessage(newClass.getMessage()));
}
}
}
public class NewClass {
public String getMessage() {
return "secret message";
}
}
import javax.faces.annotation.FacesConfig;
// WITHOUT THIS INJECTION WILL NOT WORK!
@FacesConfig(version = FacesConfig.Version.JSF_2_3)
public class ConfigurationBean {
}
Должно отображаться что-то вроде:
Я бился головой о стену около часа, прежде чем осознал необходимость ConfigurationBean
. Из документации:
FacesConfig.Version.JSF_2_3
Это значение указывает, что CDI следует использовать для разрешения EL, а также для включения JSF CDI-инъекции, как указано в Разделе 5.6.3 "CDI для разрешения EL" и Разделе 5.9 "Интеграция CDI"
И из этой проблемы GitHub https://github.com/eclipse-ee4j/glassfish/issues/22094:
По умолчанию JSF 2.3 работает в режиме совместимости с предыдущими выпусками JSF, если управляемый компонент CDI не включен в приложение с аннотацией @javax.faces.annotation.FacesConfig. Чтобы переключиться в режим JSF 2.3, вам понадобится компонент конфигурации, как показано ниже: (показывает ConfigurationBean)
...
Тот факт, что JSF необходимо переключить на "текущую версию", был весьма спорным. Практически вся группа EG проголосовала против этого, но в конечном итоге мы не смогли обойти требования обратной совместимости, которые JCP устанавливает для Java EE и руководствуется спецификациями.