How to inject in @FacesValidator with @EJB, @PersistenceContext, @Inject, @Autowired How to inject in @FacesValidator with @EJB, @PersistenceContext, @Inject, @Autowired spring spring

How to inject in @FacesValidator with @EJB, @PersistenceContext, @Inject, @Autowired


JSF 2.3+

If you're already on JSF 2.3 or newer, and want to inject CDI-supported artifacts via e.g. @EJB, @PersistenceContext or @Inject, then simply add managed=true to the @FacesValidator annotation to make it CDI-managed.

@FacesValidator(value="emailExistValidator", managed=true)

JSF 2.2-

If you're not on JSF 2.3 or newer yet, then you basically need to make it a managed bean. Use Spring's @Component, CDI's @Named or JSF's @ManagedBean instead of @FacesValidator in order to make it a managed bean and thus eligible for dependency injection.

E.g., assuming that you want to use CDI's @Named:

@Named@ApplicationScopedpublic class EmailExistValidator implements Validator {    // ...}

You also need to reference it as a managed bean by #{name} in EL instead of as a validator ID in hardcoded string. Thus, so

<h:inputText ... validator="#{emailExistValidator.validate}" />

instead of

<h:inputText ... validator="emailExistValidator" />

or

<f:validator binding="#{emailExistValidator}" />

instead of

<f:validator validatorId="emailExistValidator" />

For EJBs there's a workaround by manually grabbing it from JNDI, see also Getting an @EJB in @FacesConverter and @FacesValidator.

If you happen to use JSF utility library OmniFaces, since version 1.6 it adds transparent support for using @Inject and @EJB in a @FacesValidator class without any additional configuration or annotations. See also the CDI @FacesValidator showcase example.

See also:



You can now inject into JSF validators if you're using Java EE 8 and/or JSF 2.3.

Tested using Mojarra 2.3.9.payara-p2 on 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")@Dependentpublic 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 {}

Should render something like:

enter image description here

I banged my head on the wall for about an hour before realizing the need for ConfigurationBean. From the documentation:

FacesConfig.Version.JSF_2_3 This value indicates CDI should be used for EL resolution as well as enabling JSF CDI injection, as specified in Section 5.6.3 "CDI for EL Resolution" and Section 5.9 "CDI Integration"

And from this GitHub issue, https://github.com/eclipse-ee4j/glassfish/issues/22094:

By default, JSF 2.3 runs in a compatibility mode with previous releases of JSF, unless a CDI managed bean is included in the application with the annotation @javax.faces.annotation.FacesConfig. To switch into a JSF 2.3 mode you will need a configuration bean like below: (shows ConfigurationBean)

...

The fact that JSF needs to be switched into the "current version" was highly controversial. Pretty much the entire EG voted against that, but eventually we could not get around the backwards compatibility requirements that the JCP sets for Java EE and the spec lead enforces.