4

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.

Steve
  • 8,066
  • 11
  • 70
  • 112
  • Already did. In that case, validation was completely ignored and the dodgy credentials were available in the action listener which, by then, assumes the user with the specified email address has supplied valid credentials. – Steve Jun 09 '12 at 20:14
  • Although I'm still interested in the possibility of validating a composite component as a whole (after all, we can generate a single, converted value from it), I did solve the problem of composite component validation in [this answer](http://stackoverflow.com/a/10966594/584670). – Steve Jun 10 '12 at 06:05

2 Answers2

10

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?

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • `validatorId="#{myBean}"` has always worked for other, non-composite components. Try it yourself! I think the problem here is that I'm trying to validate the entire form. I have a backing component class that converts the form to a `LoginFormValue` instance and I had expected the validator to be called after that. – Steve Jun 10 '12 at 03:24
  • It has never worked that way. I just tried on Mojarra 2.1.9, no cigar. I get exactly your exception. Perhaps you're confusing with `` – BalusC Jun 10 '12 at 12:59
  • Buggered if I know how or why it works, but it does - at least up to and including Mojarra 2.1.6. It's been working for me for a long time in multiple places throughout my app. I forget where I got the idea from - probably somewhere on SO. – Steve Jun 10 '12 at 13:32
  • It'll be something like http://stackoverflow.com/questions/7572335/dependency-injection-in-facesvalidator-jsf-validation/7572413#7572413 But still, this answer (and all answers on similar questions) tell to use `binding`. – BalusC Jun 10 '12 at 13:34
  • My validators for which it works *don't* use the `@FacesValidator` annotation. They are just `@Named` and `@ApplicationScoped` and implement `Validator` and `Serializable`. It's probably a CDI thing. Who knows. I don't. – Steve Jun 10 '12 at 13:37
  • Yes, the answer also tells to use `@ManagedBean` or `@Named` instead and then reference it in EL by `` or `` instead of ``. – BalusC Jun 10 '12 at 13:43
0

I had same problem today and solve it by adding "implement Validator". That was my mistake.

<ui:composition>
    <h:inputText id="#{id}" value="#{value}" size="20">
        <f:validator validatorId="com.example.shop.validator.PhoneNumber"/>
    </h:inputText>
</ui:composition>

@FacesValidator("com.example.shop.validator.PhoneNumber")
public class PhoneNumber implements Validator {

@Override
public void validate(FacesContext facesContext, UIComponent uiComponent,     Object o) throws ValidatorException {

}
Mircea Stanciu
  • 3,675
  • 3
  • 34
  • 37