springvalidationjsf-2dependency-injectionservice-layer

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


How can I inject a dependency like @EJB, @PersistenceContext, @Inject, @AutoWired, etc in a @FacesValidator? In my specific case I need to inject a Spring managed bean via @AutoWired:

@FacesValidator("emailExistValidator")
public class EmailExistValidator implements Validator {

    @Autowired
    private UserDao userDao;

    // ...
}

However, it didn't get injected and it remains null, resulting in java.lang.NullPointerException. It seems that @EJB, @PersistenceContext and @Inject also doesn't work.

How do I inject a service dependency in my validator so that I can access the DB?


Solution

  • 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
    @ApplicationScoped
    public 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: