user4279433
user4279433

Reputation:

/Registration.xhtml @19,81 validator="#{UsernameValidator}": Identity 'UsernameValidator' was null and was unable to invoke

This is my project structure:

enter image description here

This is in my XHTML file:

<h:inputText id="username" value="#{user.username}" required="true"
 validator="#{UsernameValidator}" />
 <h:message for="username"/>

And here is UsernameValidator class:

@FacesValidator("UsernameValidator")
public class UsernameValidator implements Validator {

    @Override
    public void validate(FacesContext fc, UIComponent uic, Object value) throws ValidatorException {
        JOptionPane.showMessageDialog(null, "in validator class");
        if (String.valueOf(value).length() == 0 || String.valueOf(value).length() < 3) {
            FacesMessage message = new FacesMessage("Username Validation Failed", "Invalid Username");
            message.setSeverity(FacesMessage.SEVERITY_ERROR);
            throw new ValidatorException(message);
        }
    }
}

But when I write something in username field, This error happens:

/Registration.xhtml @19,81 validator="#{UsernameValidator}": Identity 'UsernameValidator' was null and was unable to invoke

Upvotes: 0

Views: 864

Answers (3)

Tarik
Tarik

Reputation: 5021

As your question was a little modified, I added a strikeout to the content related to your original question:

First, The application level validation include points 3 and 4 (Custom validation using Validator interface and Validation methods in backing beans) in addition to using Custom Component.

It seems that you are mixing up Validation using bean methods and implementing custom validator classes (the two last ones), a quick refresh about this two approaches taking your code as an example :

Validation with bean methods:

This is the most simple one, as hou will just need to add validation method to your class and invoke it through a method expression using the validator attribute, like your example :

<h:inputText id="username" value="#{user.username}" required="true" validator="#{usernameValidator}" /> 
// I changed to usernameValidator to respect naming conventions

But, in that case, usernameValidator is a method in the user @ManagedBean, something like this:

@ManagedBean("user")
@SessionScoped
public class User implements Serializable{

    // Please notice that this method should have the same signature as the validate method of the interface Validator 
    public void usernameValidator(FacesContext fc, UIComponent uic, Object value) throws ValidatorException {
        JOptionPane.showMessageDialog(null, "in validator class");
        if (String.valueOf(value).length() == 0 || String.valueOf(value).length() < 3) {
            FacesMessage message = new FacesMessage("Username Validation Failed", "Invalid Username");
            message.setSeverity(FacesMessage.SEVERITY_ERROR);
            throw new ValidatorException(message);
        }
    }
}

Custom Validator Classes:

The implementation for the Class is the same as what you did, which is implementing the Validator Interface, and registring the Validator by giving it and ID , I will copy your exact code to make the answer clean:

// I just changed the ID from UsernameValidator to usernameValidator
@FacesValidator("usernameValidator") 
public class UsernameValidator implements Validator {

    @Override
    public void validate(FacesContext fc, UIComponent uic, Object value) throws ValidatorException {
        JOptionPane.showMessageDialog(null, "in validator class");
        if (String.valueOf(value).length() == 0 || String.valueOf(value).length() < 3) {
            FacesMessage message = new FacesMessage("Username Validation Failed", "Invalid Username");
            message.setSeverity(FacesMessage.SEVERITY_ERROR);
            throw new ValidatorException(message);
        }
    }
}

You can give and ID to your Validator by using annotation @FacesValidator("usernameValidator") (which you already did), Or in the faces-config.xml by adding the following:

<validator>
    <validator-id>usernameValidator</validator-id>
    <validator-class>yourpackage.UsernameValidator</validator-class>
</validator>

Then, you will use the same ID in the f:validator Tag, like this:

<h:inputText id="username" value="#{user.username}" required="true">
    <f:validator validatorId="usernameValidator" />
</h:inputText>

NB: This is not all validation appraoches in JSF, but I think that these two are the simplest ones for Custom validation which you can use in your example (It's the 4 and 3 respectively in the list of JSF validation ways you provided).

As additional information, I will also give a brief review about the Built-in validation components which doesn't fit to your Code example:

Built-in validation components:

JSF (I am talking about 2.0 as I am not sure if there is some new ones in JSF 2.2) has standard validators that you can use to validate:

  • The length of String using f:validateLength
  • A double / long value within an optional range using f:validateDoubleRange / f:validateLongRange respectivly.
  • A String against a regular expression using f:validateRegex
  • Required values using f:validateRequired or the attribute required

There is another alternative for using those Tags by using the f:validator, you can find a good example here.

See also:

Upvotes: 2

BalusC
BalusC

Reputation: 1108802

Your mistake is here:

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

You're trying to reference a @FacesValidator as a managed bean. This won't work. The value in the @FacesValidator annotation represents the application-wide validator ID which is to be specified as a string, not a managed bean name.

So, below should do:

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

True, you'll probably have seen code snippets wherein a validator (or converter) is referenced as a managed bean via #{...}. But in those cases they are actually also registered as a managed bean via @ManagedBean or @Named instead of @FacesValidator (or @FacesConverter).

@ManagedBean
@RequestScoped
public class UsernameValidator implements Validator {}

This is often done so in order to be able to inject an EJB into it so that any necessary business/DB logic could be performed.

See also:


Unrelated to the concrete problem: the below

JOptionPane.showMessageDialog(null, "in validator class");

Is a very, very bad way to perform "logging" in a web application. Please stop doing that.

Upvotes: 2

Tim Biegeleisen
Tim Biegeleisen

Reputation: 521457

There appears to be a problem in your Registration.xhtml file. The validator requires a separate tag inside the <h:inputText> tag:

<h:inputText id="username" value="#{user.username}" required="true">
<f:validator validatorId="UsernameValidator" />
</h:inputText>

<h:message for="username" />

The error you have seems to be caused by JSF not being able to find the validation bean. Your project directory looks OK but check to make sure the class file for UsernameValidator is there and can be read by your app server.

Upvotes: 0

Related Questions