Dec 6, 2018 12:43 PM

What is JSF? Introducing JavaServer Faces

Find out what's new in JSF 2.3, the Java standard for developing component-based, event-oriented web UIs

fdecomite (CC BY 2.0)

JavaServer Faces (JSF) is the Java standard technology for building component-based, event-oriented web interfaces. Like JavaServer Pages (JSP), JSF allows access to server-side data and logic. Unlike JSP, which is essentially an HTML page imbued with server-side capabilities, JSF is an XML document that represents formal components in a logical tree. JSF components are backed by Java objects, which are independent of the HTML and have the full range of Java abilities, including accessing remote APIs and databases.

The key idea to a framework like JSF is to encapsulate (or wrap) client-side technologies like HTML, CSS, and JavaScript, allowing developers to build web interfaces without much interaction with these technologies.

This article presents a snapshot of JSF's approach to component-based UI development for Java web applications. Simple examples introduce JSF's MVC architecture, event model, and component library. Examples include new features in JSF 2.3, and we'll use PrimeFaces for our component library.

Evolving JSF

Long popular, JSF has recently faced competition from Java-compatible web frameworks, including client-side JavaScript frameworks. Still, JavaServer Faces remains the Java standard, especially for large-scale, Java enterprise development. The JSF specification has also spawned a wealth of frameworks and libraries, which have kept pace with recent client-side improvements. One of these is PrimeFaces, which we explore in this tutorial.

While the schedule for future development is unclear, JSF 2.3 gives developers plenty to work with while we wait. Released in March 2017, JSF 2.3 was intentionally designed to modernize JSF. Among several hundred small repairs and larger updates, JSF 2.3 deprecates managed bean annotations in favor of CDI, which I'll introduce later in this tutorial.

Building component-based web interfaces in JSF

JSF's core idea is to encapsulate functionality into reusable components. This is similar to the reusable tags used in JSP, but JSF components are more formal.

While you can use JSF pages within JavaServer Pages, it's more common to use Facelets to build standalone JSF pages. Facelets are XHTML pages designed for defining JSF interfaces. With Facelets, you use XML tags to create a component tree that becomes the scaffold for a JSF user interface.

Listing 1 presents the main parts of a simple JSF page written using Facelets. In this example we're accessing Java's server-side capabilities via a bean that's been placed in scope via CDI. You'll see more about CDI later on.

Listing 1. JSF sample page


<lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<lt;html xmlns=http://www.w3.org/1999/xhtml  xmlns:h="http://xmlns.jcp.org/jsf/html" >
   <lt;h:head>
      <lt;title>Hello JavaWorld!<lt;/title>
   <lt;/h:head>
   <lt;body>
      #{javaBean.content}
   <lt;/body>

In Listing 1 we see a standard XHTML page. A Facelets view is built on top of XHTML. In addition to the XHTML namespace, a secondary namespace is defined and referenced.

The h library contains standard components for use in JSF HTML pages. The http://xmlns.jcp.org/jsf/html library defines a collection of JSF components, in this case a collection of common HTML elements. One of these components is the <h:head> element.

HTML components in JSF

In terms of syntax, Listing 1's <h:head> element references the jsf/html library with the h prefix. It then references the specific component within the library, which is the head component.

The <h:head> component outputs the HTML head element. (All that syntax might seem like overkill for such a simple purpose, but there's good reason for it, as you'll see shortly.)

Nesting components

Inside the head is nested a standard HTML <title> element. This element is provided to the <h:head> component, along with the content child elements nested inside of it.

In the body of the doc, a JSF expression is contained by the #{} syntax. This is exactly analogous to a JSP expression with the ${} format: it allows the access of Java objects in scope, and simple functions.

The basic pattern for JSF is simple: Use Facelets to build an XML tree that references a component library or libraries, then use components within the library to render Java objects as HTML.

Using Java objects in JSF

Going back to Listing 1, notice that inside the JSF expression (${javaBean.content) The javaBean object is in scope when this markup is executed. The XHTML of Facelets accesses the .content property on the javaBean object. The final output is a web interface that merges the Facelets view structure with Java's server-side data and logic capabilities.

Using a JSF expression is just one way to access Java application data from a JSF user interface. Eventually, you'll want to explore other ways a JSF component can interact with the Java backend--things like data lists and grids and a variety of input controls. For now, it's enough to absorb how JSF uses XML tags (or annotations) to create a tree of components that outputs HTML based on the data contained in Java objects.

Structure of a JSF application

Like JavaServer Pages and the Servlet API, JavaServer Faces requires a standard directory structure and metadata. These are deployed as .war files.

The structure of a .war file is similar to a Servlet or JSP application. It contains a /web-app directory, which holds the application's markup files (in this case HTML, JSP, and Facelets), as well as a /WEB-INF directory, which presents the metadata to describe the application.

JSF 2.3: Spec and implementations

One of Java's strengths is that it is standards based, and those standards are governed by an open source community process. Since its inception, the Java Community Process (JCP) has overseen the development of Java technology. Once a specification or specification improvement has been developed and approved by JCP, it is available to be implemented by multiple parties. Until recently, Servlets, JSP, and JSF were all developed using JCP's open source specification process.

The most recent JSF specification as of this writing is JSF 2.3, released as part of Java EE 8 in 2017. Oracle's (now Eclipse's) Mojarra is the JSF reference implementation, and MyFaces and PrimeFaces are popular third-party implementations.

Each of these frameworks implements the JSF core, which includes some standard components. Vendors may also offer additional component libraries on top of the standard. When evaluating JSF frameworks, it's a good idea to consider the needs of your application and what component libraries are available to help you build it. Ideally, your JSF framework should get you as close as possible to what you need, right out of the box.

MVC in JSF 2.3

JSF is an MVC framework, implementing the model-view-controller pattern. In the MVC pattern, the idea is to separate the three concerns of a UI into discreet parts, so they're easier to manage. In general, the view is responsible for displaying data in the model, and the controller is responsible for setting up the model and routing the user to the correct view.

In a JSF implementation, the view is the Facelets page with its set of XML tags. These define the layout of the user interface. The other half of using JSF is the server-side, where Java classes back those UI components.

Controller beans

In JSF 2.3, controller beans provide the controller part of the MVC equation. Normal Java objects (often called POJOs, or plain old Java objects) provide the model.

In terms of process flow, controller beans:

  1. Decide where to direct user requests
  2. Set up POJOs for the model
  3. Use the model to render the Facelets view

JSF then folds together the component tree and model to render the output HTML.

Listing 2 shows how you would define the javaBean object from Listing 1 using CDI. This listing assumes the application has the cdi-api-1.2.jar in its dependencies.

Listing 2. A JavaBean defined using CDI


import javax.inject.Named;
import javax.enterprise.context.SessionScoped;

@Named
@ViewScoped

public class JavaBean  implements Serializable {
  private String content = ìWelcome to JSF!î
  // getters/setters

}

JSF 2.3 with PrimeFaces

In the next sections I'll use PrimeFaces to show you how JSF implements the MVC pattern, event-driven messaging, and reusable components. To start, open up the PrimeFaces Showcase, click the Data link in the left-side column, and select DataList. This will pull up the DataList demo code for PrimeFaces.

Figure 1 shows you where to find these samples.

Matthew Tyson

Figure 1. PrimeFaces showcase

Figure 2 shows the output of a simple data table, which is taken from the PrimeFaces DataList demo.

Matthew Tyson

Figure 2. Basic DataList component output

PrimeFaces DataList: Accessing the data model

Listing 3 presents the markup for this dataList display. If you scroll to the bottom of the PrimeFaces showcase, you can see the markup in the dataList.xhtml tab.

Listing 3. Facelet for PrimeFaces DataList


<p:dataList value="#{dataListView.cars1}" var="car" type="ordered">
  <f:facet name="header">
    Basic
  </f:facet>
  #{car.brand}, #{car.year}
</p:dataList>

In Listing 3, notice the value property of the dataList component. You can see that this references a dataListView object, and accesses the .cars1 property on it. The component is going to use the model object returned by that field. JSF tokens use conventional accessors to reference object properties, so .cars1 will refer to the getCars() getter on the object.

Next, notice the var="car" property. This tells the dataList component what variable to use when it iterates over the list of cars returned by the value field. These properties are specific to the dataList component, but the value property is very common. The var attribute is also conventional for components that iterate over lists.

In the body of the component in Listing 3, you can see the car variable is accessed via JSF expressions like #{car.brand}. Each iteration of the dataListView.cars1 instance will output the car.brand field.

Notice that the <f:facet...> tag demonstrates the ability to customize components for how they will display. In this case, the header is defined as Basic.

You can see how the Facelets XML will drive this output by combining the data with the markup. Now let's look at the Java code behind it.

DataList's server-side components

Listing 4 shows DataListView, the Java class that is used by the markup in Listing 3. You'll see shortly how the dataListView instance is associated with the DataListView class.

Listing 4. DataListView class


package org.primefaces.showcase.view.data;

import java.io.Serializable;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.inject.Named;  // Pre JSF 2.3, this was: 
				     // import javax.faces.bean.ManagedBean;
import javax.inject.Inject;
import javax.faces.bean.ViewScoped;
import org.primefaces.showcase.domain.Car;
import org.primefaces.showcase.service.CarService;

@Named
@ViewScoped

public class DataListView implements Serializable {
    private List<Car> cars1; 
    private Car selectedCar;

    @Inject("#{carService}")
    private CarService service;

    @PostConstruct
    public void init() {

        cars1 = service.createCars(10);
    }
    public List getCars1() {
        return cars1;
    }
    public void setService(CarService service) {
        this.service = service;

    }
}

Listing 4 has a few other important elements, which we'll consider piece by piece.

Dependency injection and annotations

First, notice that the DataListView class is annotated with @Named, which you can see from the import import javax.inject.Named; is part of JSF. The @Named annotation tells JSF this bean is part of the app. The @ViewScoped annotation informs JSF that the bean will live for just the life of the view.

Next, observe that the CarService property has the @Inject annotation (called the @ManagedProperty prior to JSF 2.3). This is another JSF feature that allows beans to be "wired together," a technique popularized by the Spring framework and other dependency injection tools. In essence, JSF will find the carService object in scope and associate it automatically to the service field on the DataListView object.

Remembering that the Facelet in Listing 3 accesses the getCars1() method, you'll notice that the method simply returns the cars1 field, which is defined as a list with the line private List cars1;. How is this list populated?

Lifecycle hooks

Take a look at the method init() in Listing 4, which is annotated with the @PostConstruct annotation. The @PostConstruct annotation is a lifecycle hook, meaning that it allows the developer to tap into the JSF component lifecycle. The PostConstruct informs JSF to run this code once the component has been constructed, but before it has been rendered. In the body of the init() method, the CarService object (previously injected into the service field) is used to populate the cars1 list with this line: cars1 = service.createCars(10); .

Service classes

Now let's shoot over to the CarService class. A service class is a class that provides services to other classes, usually by providing services to one more more controllers. Like the MVC pattern, the service class idea is common, and not unique to JSF.

Listing 5. DataListView class


package org.primefaces.showcase.service;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import javax.faces.bean.ApplicationScoped;
import javax.inject.Named;
import org.primefaces.showcase.domain.Car;

@Named(name = "carService")
@ApplicationScoped

public class CarService {
    private final static String[] colors;
    private final static String[] brands;
    static {
        colors = new String[10];
        colors[0] = "Black";
        colors[1] = "White";
        // ...other colors...
    }

    public List createCars(int size) {
        List list = new ArrayList();
        for(int i = 0 ; i < size ; i++) {
            list.add(new Car(getRandomId(), getRandomBrand(), getRandomYear(), getRandomColor(), getRandomPrice(), getRandomSoldState()));

        }
        return list;
    }
    // Utility methods like getRandomId() have been removed
}

To begin, notice how the code informs JSF this is a managed class: @Named(name = "carService"). In this case, the bean is given a name, "carService", which we've seen in Listing 4 is used as a handle to reference the bean in the DataListView controller. In addition, the class is specified as @ApplicationScoped. In essence, that means that the object instance will live for the duration of the application.

The actual Java code for preparing the cars list should be fairly self-documenting. But how will JSF finds these beans?

Bean metadata

JSF uses the application's metadata to locate the beans it needs; in the past, that meta-data lived primarily in separate XML files, the /WEB-INF/beans.xml. CDI is enabled in Java 7 by default, so that file is not required unless you need something not supported by annotation. (You no longer have to even tell JSF to use bean-discovery-mode="all).

Events in JSF

Along with being an MVC, component-based framework, JSF is an eventing framework. That means it uses events to handle interactions with users and components. We'll conclude with a quick look at JSF's event-oriented architecture.

Ideally, events provide a clean separation of concerns by isolating event generation code from event handling code. JSF events can be divided into two types: server-side events and client-side events.

To set up a server-side event, you would create an event handler in Java code. You would then create an event emitter (on the component markup), or an event listener, whose role is to listen for lifecycle events.

Client-side events--things like a user clicking a button in the browser--are transparently mapped to event-handlers on the server. Component events are handled in this way. For the most part, the JSF framework abstracts the actual wiring of the events. This is true even of AJAX or Websocket-style eventing.

Component-managed events

JSF hides the details of how an event works by encapsulating those details inside one or more components. To understand how this works, go back to the DataList example and find Paginator, a dataList that employs events.

Figure 3 presents the output of a Paginator dataList.

Matthew Tyson

Figure 3. Paginator dataList with events

This list uses the same kind of structure as the DataListView in Listing 4 to output the grid, but it has a new feature: if you click on the magnifying glass icon, you will see a popup window displaying a list of links. Listing 6 shows the component that creates those links

Listing 6. Magnifying glass links


<p:commandLink update=":form:carDetail" oncomplete="PF('carDialog').show()" title="View Detail" styleClass="ui-icon ui-icon-search" style="float:left;margin-right:10px">
  <f:setPropertyActionListener value="#{car}" target="#{dataListView.selectedCar}" />
  <h:outputText value="#{car.brand}, #{car.year}" />
</p:commandLink>

Listing 7 has the component that supplies the actual popup.

Listing 7. Popup component



<p:dialog header="Car Info" widgetVar="carDialog" modal="true" showEffect="blind" hideEffect="explode" resizable="false">
 <!-- Dialog Content -->
</p:dialog>

By carefully studying Listings 6 and 7, it becomes clear that in JSF, JavaScript eventing is handled by components. In Listing 6, the JavaScript oncomplete event is used to fire JavaScript code: oncomplete="PF('carDialog').show()".

Note that you don't define the function to be called; instead, it's pre-defined by the component internals.

The p:dialog component in Listing 7 has given itself a name with widgetVar="carDialog. The work to unite these two into a functioning JavaScript dialog is handled by the PrimeFaces framework and the components themselves.

Conclusion

JavaServer Faces is the Java standard for creating web-based UIs. As of this writing, JSF 2.3 is the current version, and the reference implementation is Eclipse Mojarra. JSF has been selected for inclusion and further development in Jakarta EE, which is good news for Java developers who want a standard way to develop modern, Java-based web UIs.

Learn more about JSF