-
Available since OmniFaces 1.6
The @FacesValidator
is by default not eligible for dependency injection by @Inject
nor @EJB
. It that only when the managed=true
attribute is set. But this doesn't support setting custom attributes. OmniFaces solves this by implicitly making all FacesValidator
instances eligible for dependency injection without any further modification. In order to utilize OmniFaces managed validator, simply remove the Faces native managed=true
attribute.
The ValidatorManager
provides access to all FacesValidator
annotated Validator
instances which are made eligible for CDI.
bean-discovery-mode
Since CDI 1.1, when having a CDI 1.1 compatible beans.xml
, by default only classes with an explicit CDI managed bean scope annotation will be registered for dependency injection support. In order to cover FacesValidator
annotated classes as well, you need to explicitly set bean-discovery-mode="all"
attribute in beans.xml
. This was not necessary in Mojarra versions older than 2.2.9 due to an oversight. If you want to keep the default of bean-discovery-mode="annotated"
, then you need to add Dependent
annotation to the validator class.
AmbiguousResolutionException
In case you have a FacesValidator
annotated class extending another FacesValidator
annotated class which in turn extends a standard validator, then you may with bean-discovery-mode="all"
face an AmbiguousResolutionException
. This can be solved by placing Specializes
annotation on the subclass.
JSF 2.3 compatibility
JSF 2.3 introduced two new features for validators: parameterized validators and managed validators. When the validator is parameterized as in implements Validator<T>
, then you need to use at least OmniFaces 3.1 wherein the incompatibility was fixed. When the validator is managed with the managed=true
attribute set on the FacesValidator
annotation, then the validator won't be managed by OmniFaces and will continue to work fine for Faces. But the <o:validator> tag won't be able to set attributes on it.
Submit the form
Validator will print itself and both the injected EJB and CDI bean in a faces message. Note: EJB is stateless and CDI bean is request scoped.
<h3>Submit the form</h3>
<p>
Validator will print itself and both the injected EJB and CDI bean in a faces message.
Note: EJB is stateless and CDI bean is request scoped.
</p>
<h:form>
<h:inputText validator="someValidator" />
<h:commandButton value="Submit">
<f:ajax execute="@form" render="@form" />
</h:commandButton>
<h:messages />
</h:form>
package org.omnifaces.showcase.cdi;
import jakarta.ejb.EJB;
import jakarta.faces.component.UIComponent;
import jakarta.faces.context.FacesContext;
import jakarta.faces.validator.FacesValidator;
import jakarta.faces.validator.Validator;
import jakarta.faces.validator.ValidatorException;
import jakarta.inject.Inject;
import org.omnifaces.util.Messages;
@FacesValidator("someValidator")
public class SomeValidator implements Validator {
@EJB
private SomeEJB ejb;
@Inject
private SomeCDI cdi;
@Override
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
Messages.addInfo(component.getClientId(context), "Validator currently used: {0}", this);
Messages.addInfo(component.getClientId(context), "EJB injected in validator: {0}", ejb);
Messages.addInfo(component.getClientId(context), "CDI injected in validator: {0}", cdi);
}
}
package org.omnifaces.showcase.cdi;
import jakarta.enterprise.context.RequestScoped;
import jakarta.inject.Named;
@Named
@RequestScoped
public class SomeCDI {
//
}
package org.omnifaces.showcase.cdi;
import jakarta.ejb.Stateless;
@Stateless
public class SomeEJB {
//
}