I created a new validator:
package com.example.jsf.validator;
import com.example.components.LoginFormValue;
import com.example.ejb.SecurityEjb;
import java.io.Serializable;
import javax.ejb.EJB;
import javax.enterprise.context.ApplicationScoped;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.validator.Validator;
import javax.faces.validator.ValidatorException;
import javax.inject.Named;
/**
* Validator for {@code login-form} component.
*
* @author steve
*/
@Named
@ApplicationScoped
public class LoginValidator implements Validator, Serializable
{
@Override
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException
{
if (value == null)
{
return;
}
LoginFormValue loginFormValue = (LoginFormValue) value;
if (securityEjb.checkCredentials(loginFormValue.getEmailAddress(), loginFormValue.getPassword())) {
return;
}
throw new ValidatorException(new FacesMessage("Incorrect email address/password"));
}
@EJB
private SecurityEjb securityEjb;
}
But when I try to use it:
<my:login-form emailAddress="#{loginBean.emailAddress}"
rememberMe="#{loginBean.rememberMe}"
actionListener="#{loginBean.submit()}"
recoverPasswordOutcome="recover-password"
registerOutcome="signup">
<f:validator validatorId="#{loginValidator}"/>
</my:login-form>
I get this exception displayed when I load the page:
javax.faces.FacesException: Expression Error: Named Object: com.example.jsf.validator.LoginValidator@31888ef8 not found.
The offending line of code is:
com.sun.faces.application.ApplicationImpl.createValidator(ApplicationImpl.java:1593)
Why can JSF actually resolve the validator bean class yet not be able to instantiate it? Every other validator in my app is a Named
ApplicationScoped
bean and they all work just fine. I reference them all using <f:validator validatorId="{myValidatorBean}"/>
.
I'm using GlassFish 3.1.2.
The <f:validator validatorId>
must refer the ID of the validator, not the concrete validator instance. The ID of the validator is exactly the one which you've specified as @FacesValidator
value or as <validator-id>
when using the faces-config.xml
approach. E.g.
@FacesValidator("myValidator")
which is then to be referenced as
<f:validator validatorId="myValidator" />
Any EL expression in validatorId
would during view build time be resolved to a String
identifying the validator ID. So when passing a concrete Validator
instance, it would only end up its toString()
value like com.example.MyValidator@hashcode
being passed as validator ID which does after all obviously not exist, as the exception message is trying to tell you:
javax.faces.FacesException: Expression Error: Named Object: com.example.jsf.validator.LoginValidator@31888ef8 not found.
You should be using <f:validator binding>
or <h:inputText validator>
instead. It can take a concrete instance.
<f:validator binding="#{myValidator}" />
That it doesn't work when been passed to a composite component is a different problem. You namely didn't specify the for
attribute at all, so it won't be applied on any of the UIInput
components inside the composite. I think the following question/answer will be fully applicable in order to solve that: How to specify a validator for an input component inside a composite component?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With