JSF and Bean Validation issue

To prevent injections and other attacks, input validation is a kind of must. JSF supports this by its own validator concept. Beside this, JSF takes advantage of Bean Validation (JSR 349): You may define constraints within your class, e.g. an entity. JSF will call this validation for every field or getter which is annotated with a constraint. Every field? No, there is a strange behavior.

This post is not part of my detailed tutorial [1]. Thus, I omit some explanation, just to demonstrate the function, and, what I call a strange behavior, which might be a bug.

In this showcase, I want to edit a person. For brevity, a person contains just a first and last name. In this example, a name is allowed to contain at least 2 characters, up to 50. A name may contain a single blank, dot or hyphen somewhere between letters. Thus, we just use two different constrains, Size and Pattern. This is the person “entity”:

public class Person {

    public Person() {
        this("", "");
    }

    public Person(String firstName, String lastName) {
        _firstName = firstName;
        _lastName = lastName;
    }

    @Size(min = 2, max = 50)
    @Pattern(regexp = "\\p{L}+([ \\.-]\\p{L}+)?", message = "FirstName: Wrong pattern.")
    String _firstName;

    public String getFirstName() {
        return _firstName;
    }

    public void setFirstName(String firstName) {
        _firstName = firstName;
    }

    String _lastName;

    @Size(min = 2, max = 50)
    @Pattern(regexp = "\\p{L}+([ \\.-]\\p{L}+)?", message = "LastName: Wrong pattern.")
    public String getLastName() {
        return _lastName;
    }

    public void setLastName(String lastName) {
        _lastName = lastName;
    }
}

You may notice the different positions of the constraints: At the first name attribute and at the last name getter. Both are valid annotations. For every constraint, a message may be provided. Otherwise a standard message would be used. There are messages for the Pattern constraint, just to show, to which part it belongs. I omitted the imports. Let NetBeans do it for you. Avoid the faces validation package!

The GUI contains a simple page with two input fields and some message fields, including output of a server created validation report.

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:f="http://xmlns.jcp.org/jsf/core">
    <h:head>
        <title>Bean validation demo</title>
    </h:head>
    <h:body>
        <h1>Bean validation demo</h1>
        <h:form>
            <div>
                First name:
                <h:inputText id="firstName" value="#{editPerson.person.firstName}">
                    <f:ajax render="@this msgFirstName validation"/>
                </h:inputText>
                <h:message id="msgFirstName" for="firstName"/>
            </div>
            <div>
                Last name:
                <h:inputText id="lastName" value="#{editPerson.person.lastName}">
                    <f:ajax render="@this msgLastName validation"/>
                </h:inputText>
                <h:message id="msgLastName" for="lastName"/>
            </div>
            <h:outputText id="validation" value="#{editPerson.violations}"/>
        </h:form>
    </h:body>
</html>

Its up to JSF to validate every input. Additional, within the backing bean, there is some logic to demonstrate how to validate the whole entity programmatically.

@Named
@SessionScoped
public class EditPerson implements Serializable {

    private Person _person = new Person("John", "Doe");
    private String _violations = "";

    public Person getPerson() {
        validate();
        return _person;
    }

    public void setPerson(Person person) {
        _person = person;
    }

    public String getViolations() {
        return _violations;
    }

    private void validate() {
        Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
        Set<ConstraintViolation<Person>> violations = validator.validate(_person);
        _violations = "";
        for (ConstraintViolation<Person> violation : violations) {
            _violations += violation.getMessage() + "; ";
        }
    }
}

Let’s start and try some invalid names:

BeanValidationDemoAt last name, you’ll see the faces message for this field. There is no such message for the first name. Below the input fields you’ll see the violation message generated by the validate method. What happened?

Both names are invalid. JSF handled the violation of the last name only. Due to this violation, the last name would not be transferred to the model. Thus, the violation method would not “see” the wrong last name. But, first name is not rejected by JSF’s validation. Thus, it is passed to the model (Person) and could be handled by the validate method.

Within Person, for first name the attribute (instance field) is annotated, whilst for last name, I placed the constraints to the getter. Believe me, Bean Validation handles both. You may check this by initialize Person as private Person _person = new Person(“John-“, “Doe-“);. In this case, the validation method alerts both names.

Its JSF which does not validate the first name. But shouldn’t it? I believe, it should.

Only a slightly change is needed to get it to work. Have you noticed the underscore I used for the attribute? I like to mark instance variables that way. Albeit NetBeans marks instance variables indifferent color, the underscore is useful within a simple text editor. And it avoids a “this.” in the value assignment. If you omit this underscore, JSF will do the validation job.

Bean validation is fine with this:

@Size(min = 2, max = 50)
@Pattern(regexp = "\\p{L}+([ \\.-]\\p{L}+)?", message = "FirstName: Wrong pattern.")
String christianName;

public String getFirstName() {
    return christianName;
}

public void setFirstName(String firstName) {
    christianName = firstName;
}

But for JSF, it works only if the attribute’s name is exactly the same as the getter without “get” and first letter lowercase:

@Size(min = 2, max = 50)
@Pattern(regexp = "\\p{L}+([ \\.-]\\p{L}+)?", message = "FirstName: Wrong pattern.")
String firstName;

public String getFirstName() {
    return firstName;
}

public void setFirstName(String firstName) {
    this.firstName = firstName;
}

(Using GlassFish 4 with JSF 2.2 Mojarra)

[1] http://blog.mueller-bruehl.de/tutorial-web-development/

This entry was posted in NetBeans, Programming. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>