JavaServer Faces is a component-based MVC framework for Java web development. It is the “officially endorsed” web framework in Java EE 7.

JavaServer Faces applications have an unusual structure.

To explain, first consider the difference between using the iterator and visitor design patterns. Assume you want to sum the elements of a list. With an iterator, your code takes an active role. It would request (pull) each element of the list one-by-one. It would then update the total using each element it retrieves. In contrast, a visitor takes a more passive role. You would implement a visitor class that updates a total for every element it receives. The list is then responsible for passing (push) each element to the visitor.

What makes JavaServer Faces applications unique is that their controllers are typically very passive. The controllers in most other MVC frameworks are typically very active. They orchestrate most aspects of transforming inputs into a view. In contrast, in a JavaServer Faces application, the container does most of the orchestration. This inversion of control causes most JavaServer Faces applications to use a design pattern in which the application model is exposed as JavaBeans properties of the controller.

I teach a class on Java EE development. I try to relate design decisions to design patterns. However, I could not find any pattern catalog with a design pattern that resembles JavaServer Faces.

Preliminaries

JavaServer Faces is a MVC (Model-View-Controller) architecture. The model is implemented in Java classes that represent your domain logic. The view is an XHTML file that defines the user interface components. The controller is a class with annotations that define a name and scope.

As an example, consider this very simple controller for a JavaServer Faces application:

@Named
@SessionScoped
public class UserController {

  private String name = "guest"; // default user is "guest"

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public String login() {
    if ("admin".equals(name))
      return "admin_zone";
    else
      return "welcome";
  }
}

The @Named annotation tells Java that this class can be referenced by name in the user interface (its name is “userController”).

The pair of methods getName/setName follow a special naming convention. The naming convention is defined in the JavaBeans specification. The pair of get/set methods define a property called “name”. If you want to set the name property, you would invoke setName. If you want to retrieve the name property, you would invoke getName.

The @SessionScoped annotation tells the application server that the life-span of the controller is a single page request. This means that a separate instance of UserController will be created for each user.

Finally, the login() method defines an action. An action is a method that does some computation and then (optionally) returns the name of a new view.

Facelets and Expression Language

Views in JavaServer Faces are defined with XHTML files. These files are referred to as Facelets.

A view can use HTML as well as JavaServer Faces components. For example, a text box might be defined as follows:

<h:inputText value="#{userController.name}">

The hash and braces #{ } define an expression in Expression Language.

The expression is used for both reading and writing. The name is set with setName and retrieved using getName.

The view and controller work together. JavaServer Faces will create a text box with the default value from getName. When the user changes the name and submits the form, the setName method of the controller will be called.

A login button might also be defined on the same page as follows:

<h:commandButton value="Login" action="#{userController.login}">

This will generate a HTML button that, when clicked, will update the form value (i.e., call setName) and then call login.

Model-as-Property Design Pattern

In JavaServer Faces, the components of a view are bound to properties of the controller. This becomes interesting when the controller exposes the model as properties. This allows the view to create and manipulate the model.

For example, we might create the following model object:

public class User {
  private String name;
  private String password; // it isn't good practice to store passwords in plaintext

  public void setName(String name) {
    this.name = name;
  }

  public String getName() {
    return name;
  }

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

  public String getPassword() {
    return password;
  }
}

Then the model can be exposed as a property of the controller:

@Named
@SessionScoped
public class UserController {

  private User user = new User();

  public User getUser() {
    return user;
  }

  public String login() {
    if (Database.checkUser(user.getName(), user.getPassword()))
      return "welcome";
    else
      return "bad_password";
  }
}

The views reference the model:

Username: <h:inputText value="#{userController.user.name}">
Password: <h:inputText value="#{userController.user.password}">

These same expressions can be used to show the current user name as well as populate instances of the User class.

Note that the user property of UserController only needs a getUser method. It is read only. There is no need for a setUser method. Instead, the user is retrieved (get) and then the user properties are set. That is, setting the property #{userController.user.name} is equivalent to calling getUser().setName(...).

A more comprehensive controller could incorporate other actions:

@Named
@SessionScoped
public class UserController {

  private User user = new User();

  public User getUser() {
    return user;
  }

  public String login() {
    if (Database.checkUser(user.getName(), user.getPassword()))
      return "welcome";
    else
      return "bad_password";
  }

  public void create() {
    Database.createUser(user);
  }

  public void read() {
    // If the User object is partially completed, retrieve the full object
    user = Database.findUser(user.getName());
  }

  public void update() {
    Database.updateUserPassword(user.getName(), user.getPassword());
  }

  public void delete() {
    Database.deleteUser(user.getName());
  }
}

Summary

In summary, a typical JavaServer Faces application:

  1. Exposes a model as properties of the controller: both input and output are set directly on the model (or “view models”);
  2. Implements actions as methods in the controller that manipulate the model.

In addition, the model is typically exposed in a single property (e.g., getUser).

This is somewhat analogous to the visitor design pattern. That is, the controller does not directly do any input/output or orchestration. The input/output is handled by the container calling getter/setters. The actions are invoked as call-backs that are connected to command-buttons in the view.

Published 5 December 2014 by Benjamin Johnston.