DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Related

  • Writing DTOs With Java8, Lombok, and Java14+
  • Java Bean Validation: Applying Constraints Programmatically
  • Java String: A Complete Guide With Examples
  • Generics in Java and Their Implementation

Trending

  • Start Coding With Google Cloud Workstations
  • Agentic AI for Automated Application Security and Vulnerability Management
  • MySQL to PostgreSQL Database Migration: A Practical Case Study
  • Unlocking Data with Language: Real-World Applications of Text-to-SQL Interfaces
  1. DZone
  2. Coding
  3. Languages
  4. Password Confirmation on a JSF Page (Part 1): A Simple Model

Password Confirmation on a JSF Page (Part 1): A Simple Model

This look at JSF pages considers how to properly use password confirmation fields without your IDE spouting NullPointerExceptions at you.

By 
Ken Fogel user avatar
Ken Fogel
·
Apr. 30, 18 · Tutorial
Likes (7)
Comment
Save
Tweet
Share
13.7K Views

Join the DZone community and get the full member experience.

Join For Free
Note: Kyle Stiemann from the Liferay Faces Team was kind enough to point out a flaw in the Java Server Faces libraries prior to versions JSF 2.3 and Mojarra 2.2.16 related to what I am presenting here. The solution requires two changes. The first is an addition to the web.xml file that you will see commented about in the file. The second change requires using newer versions of JSF. Payara 4/Glassfish 4 manifests the problem. Payara 5/Glassfish 5, with the newer library, does not exhibit the problem. You can read about the problem at: JSFSPEC-1433 issue

A student came to see me for help on a coding problem. Using JavaServer Faces, he created a form with password and password confirmation fields. The problem was that he kept getting a null pointer exception. He was confident in his code and the IDE didn’t declare any errors. Had he discovered a bug in JSF? Using StackOverflow, he found references to what he believed was the same problem and that the cause was likely a bug in Java or JSF. This student forgot rule number one in my course:

It’s your fault, always.

That’s not to say that there isn’t a possibility that there are bugs in a library or language. It means that at the level of usage in my courses, the probability that you have uncovered a bug in a commonly used framework or library is zero.

Let’s look at what the student presented to me. I have recreated the problem so that my student can remain anonymous.

You can download the project here.

First, let’s look at the UI.

Screen capture of password form

Here is the model for this form. For brevity, the comments have been removed. The repo version has all its comments.

import java.io.Serializable;
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;

@Named("user")
@RequestScoped
public class User implements Serializable {

    private static final long serialVersionUID = 1L;
    private String loginName;
    private String password;

    public User() {
    }

    public User(String loginName) {
        this.loginName = loginName;
    }

    public User(String loginName, String password) {
        this.loginName = loginName;
        this.password = password;
    }

    public String getLoginName() {
        return loginName;
    }

    public void setLoginName(String loginName) {
        this.loginName = loginName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (loginName != null ? loginName.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        if (!(object instanceof User)) {
            return false;
        }
        User other = (User) object;
        if ((this.loginName == null && other.loginName != null) || (this.loginName != null && !this.loginName.equals(other.loginName))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "com.jsfpasswordconfirmplainbean.bean[ loginName=" + loginName + " ]";
    }

}

User model class

This model class is managed by the CDI framework, as you can see from the annotations. In this model, we have the loginName and the password. The third input field on the form, the password confirmation input, is not part of the model. It will exist only to verify that the password can be entered twice correctly. It does not need to be preserved in the model. This model is fine. In part two of this two-part blog, we will look at how to handle a model that is an entity bean.

Now let’s look at the JSF page.

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<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>#{msgs.pageTitle}</title>
        <h:outputStylesheet library="css" name="styles.css" />
    </h:head>
    <h:body>
        <h1>#{msgs.pageHeader1}</h1>
        <h:form>
            <h:panelGrid columns="3" cellpadding="1" border="0" cellspacing="10"
                         title="#{msgs.signup}" columnClasses="firstColumn,secondColumn,thirdColumn"
                         rowClasses="rowHeight, rowHeight">
                <f:facet name="header">
                    <h:outputText value="#{msgs.signup}" />
                </f:facet>

                <h:outputLabel for="login_name" value="#{msgs.login_name}"/>
                <h:inputText id="login_name" 
                             value="#{passwordBacking.user.loginName}"
                             required="true"
                             requiredMessage="#{msgs.required}" >
                    <f:validateLength maximum="45" />
                </h:inputText>
                <h:messages for="login_name" styleClass="message" />

                <h:outputLabel for="password" value="#{msgs.password}"/>
                <h:inputText id="password" label="#{msgs.age}"
                             value="#{passwordBacking.user.password}"
                             required="true"
                             requiredMessage="#{msgs.required}">
                    <f:validateLength maximum="12" />
                </h:inputText>
                <h:messages for="password" styleClass="message" />

                <h:outputLabel for="password_confirm" value="#{msgs.confirm}"/>
                <h:inputText id="password_confirm"
                             value="#{passwordBacking.passwordConfirm}"
                             required="true"
                             requiredMessage="#{msgs.required}"
                             validator="#{passwordBacking.validatePasswordError}">
                    <f:validateLength maximum="12" />
                </h:inputText>
                <h:messages for="password_confirm" styleClass="message" />

            </h:panelGrid>
            <h:commandButton id="saveButton" value="#{msgs.save}"
                             action="#{passwordBacking.doSomething()}"
                             styleClass="myButton"/>
        </h:form>
    </h:body>
</html>

index01.xhtml

The password and confirm password inputs should be inputSecret, but to better understand what is happening, I have left them as simple inputText. Many samples of JSF pages are coded so that the page can access the model directly such as:

value="#{user.password}"


My preference is to adopt the approach required if the model was an entity bean. To me, this clearly delineates the view, the model, and the controller. This means that access is through the controller backing bean such as:

value="#{passwordBacking.user.password}"


Let’s look at the backing bean.

import com.jsfpasswordconfirmplainbean.model.User;
import java.io.Serializable;
import javax.enterprise.context.RequestScoped;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.component.UIInput;
import javax.faces.context.FacesContext;
import javax.faces.validator.ValidatorException;
import javax.inject.Inject;
import javax.inject.Named;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Named("passwordBacking")
@RequestScoped
public class PasswordBackingBean implements Serializable {

    private final static Logger LOG = LoggerFactory.getLogger(PasswordBackingBean.class);

    @Inject
    private User user;

    // The value for the confirmPassword field that does not exist in the entity
    private String passwordConfirm;

    public User getUser() {
        return user;
    }

    public String doSomething() throws Exception {
        return "doSomething";
    }

    public String getPasswordConfirm() {
        return passwordConfirm;
    }

    public void setPasswordConfirm(String passwordConfirm) {
        this.passwordConfirm = passwordConfirm;
    }

    public void validatePasswordError(FacesContext context, UIComponent component,
            Object value) {

        if (!user.getPassword().equals(passwordConfirm)) {
            String message = context.getApplication().evaluateExpressionGet(context, "#{msgs['nomatch']}", String.class);
            FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, message, message);
            throw new ValidatorException(msg);
        }
    }

}

PasswordBackingBean.java

This backing bean is also the home of the passwordConfirm String that needs to be compared to the password field. Technically, this makes this backing bean a part-time model. The passwordConfirm field is disposable, so I can justify placing it in the backing bean and not the user model.

Here is where my student made his error. When you run the project, it will throw a NullPointerException when it runs the custom validator. Can you see the reason?

The student is comparing the password field in the User object with the passwordConfirm field in the PasswordBackingBean object. The validator is executed before the parameters are applied to the objects User and PasswordBackingBean. The exception happens in:

if (!user.getPassword().equals(passwordConfirm))


The Strings we are testing are not set yet, so they are null. If they were set, then a logic error will occur because you will be comparing the Strings already in the objects and not what the user entered in the form.

What the student has forgotten is the following diagram from the JSF documentation:

JSF Phase diagram

Validation and conversion occur after the request values are assigned to UI temporary variables. Only if validation and conversion are successful will the values be used to update the model. Therefore, to successfully compare the two fields, we need to use the UI variables. Here is the corrected method.

public void validatePasswordCorrect(FacesContext context, UIComponent component,
        Object value) {

    // Retrieve the value passed to this method
    String confirmPassword = (String) value;

    // Retrieve the temporary value from the password field
    UIInput passwordInput = (UIInput) component.findComponent("password");
    String password = (String) passwordInput.getLocalValue();

    if (password == null || confirmPassword == null || !password.equals(confirmPassword)) {
        String message = context.getApplication().evaluateExpressionGet(context, "#{msgs['nomatch']}", String.class);
        FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, message, message);
        throw new ValidatorException(msg);
    }
}

Corrected Validation Method

The temporary value for the confirmed password field is in the Object value parameter for the validation method. The value in the first password field is retrieved from the UI component named “password” that is the id from the JSF page.

Another potential problem can occur if a user fills in only one of the password fields. This will result in null values. Therefore, a test for null-ness has been added to the if statement:

if (password == null || confirmPassword == null || !password.equals(confirmPassword)) {


Do not forget to test for null-ness first. If you wrote the if statement as:

if (!password.equals(confirmPassword) || password == null || confirmPassword == null) {


You will get a NullPointerException if either field is left blank.

To run it, please change:

validator="#{passwordBacking.validatePasswordError}


to:

validator="#{passwordBacking.validatePasswordCorrect}


There you have it, a working confirmation input field pair.

In my next blog, I will look at how to do the same thing but with a model that is a JPA entity.

Bean (software) Spring Framework Object (computer science) Form (document) Library code style Strings entity Java (programming language) Blog

Published at DZone with permission of Ken Fogel, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Writing DTOs With Java8, Lombok, and Java14+
  • Java Bean Validation: Applying Constraints Programmatically
  • Java String: A Complete Guide With Examples
  • Generics in Java and Their Implementation

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends: