Password Confirmation on a JSF Page – Part 1 A Simple Model

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 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 at https://gitlab.com/omniprof/JSFPasswordConfirmationPlainBean.git
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 a 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 occurs after the request values are assigned to UI temporary variables. Only if validation and conversion is 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.

My Personal Opinion on the Future of Jakarta EE

The following is just my personal opinion of where Jakarta EE may be going. I am far removed from the decision makers and this opinion is based on what I have read and my experience as a teacher. Feel free to label me a crackpot.

I began to teach J2EE in 2002. It was a mess. Most of my time was spent on explaining the purpose of the numerous xml files and the three strange beans, session, session stateless and EJB. Of course, this was in the days when it was thought that programs will be frequently reconfigured via their xml files and that pooling the strange beans was the state of the art. When I got a copy of Rod Johnson’s book J2EE Development without EJB I thought that the concept was intriguing. However, I was required to teach what was most commonly used in industry and at that time it was J2EE.

Fast forward to today and much of what Rod rallied against and that led to the creation of Spring has changed. While some may disagree, I find Java EE 7 easier to use and easier to teach than Spring.

All hell broke loose last year with the much-delayed release of Java EE 8. Components that we were looking forward to were dropped. The IDEs were slow to upgrade to Java EE 8. Then came the bombshell that Oracle was going to drop their stewardship of Java EE.

The Guardians came into being just before the release of Java EE 8 when Oracle announced that it was dropping certain popular new components. While I could speculate why Oracle did this and complain bitterly there is nothing to be gained. Oracle controls the destiny of Java and as a corporation they will make decisions that have a positive effect on their bottom line. I can only assume that the expense of maintaining and promoting Java EE was no longer cost effective. The money invested in Java EE could be spent in other areas that offered the company a higher rate of return.

Oracle then began to either donate and/or make fully open source different parts of their Java portfolio. NetBeans went to Apache and Java EE went to Eclipse. Fortunately, the word Java is not in NetBeans, so it kept its name. Java EE needed to be re branded for no discernible reason. There was much written on this but in the end it turned out to be nothing more than a distraction. It also ignored the real issue.

Java EE is a full stack development environment for enterprise level applications running on an application server. It was promoted as such and Oracle had evangelists travelling the word to get that message out. That ended abruptly when the evangelists were all let go. I was disappointed because I thought once I retired from teaching I could become an evangelist. That was also the point in time when Java EE began its slow death march inside Oracle.

Apache, Eclipse and other open source foundations do an amazing job at ensuring that the software that falls under their umbrella are engineered to the highest standards. What they don’t do effectively is to promote or evangelize their portfolio of software. Don’t get me wrong, I have seen Eclipse at conferences and I will be submitting proposals to an Apache Con coming up in Montreal soon. That is not the sufficient level of promotion that Java EE needs.

Java EE is not without its cheerleaders. Red Hat, IBM and Payara as well as some others are actively out there promoting Java EE but none have the gravitas that Oracle, the home of Java, had. In my myopic view of the world, Spring has managed to convince the enterprise development community that Java EE is nothing more that the necessary support libraries for some aspects (sorry about the AOP humour) of Spring.

What does this all mean to Jakarta EE? On the plus side, now that its fully open source many more interested developers will be able to contribute to its various components. On the minus side, I fear that a clear vision of what Jakarta EE is will be lost. Communities will coalesce around specific elements for their own self-interest. Self interest is a good thing. What I believe will be lost is a vision of Jakarta EE as a complete and integrated system to be considered along side of Spring or Vaadin. I worry that Jakarta EE will become another Commons style library.

That was a depressing conclusion. What can be done? I am way out of my league on this. I can only speculate that we need one of the existing corporations or the creation of a new one to put Jakarta EE on the same playing field as the frequently mentioned Spring. Spring is an excellent framework and I have taught Spring but it’s a different product from Jakarta EE. Spring is also backed by the deep pockets of Pivotal who are in turn backed by the enormous pockets of Dell. An obvious choice for a corporation to step up is Payara who promote their working version of Glassfish. Whomever it might be I wonder if there is the necessary investment available to return EE to its status as a true enterprise stack.

For the past three years I have attended parties at Bain Capital while at JavaOne. They have a wall with the names of all the companies they have invested in. A company that leads the commercialization of Jakarta EE should be on that wall alongside Twitter and others. To the investors out there I will happily provide you with my mailing address to send me the cheques.

Anyone want to start a business or hire a 64 year old evangelist?

One final word concerning the Java EE Guardians. It came into being because it was felt that Oracle was not listening to the developer community. With the donation to Eclipse I am uncertain what the raison d’être is of the group. Reza Rahman has done an amazing job in rallying the EE community to get their voices heard. Now I think we should all join the Eclipse foundation and directly influence Jakarta EE. We need to make noise inside Eclipse rather than outside.