Immediate attribute example in JSF

Introduction

This tutorial will show you what is the purpose of using immeditae attribute in JSF. Although the request processing lifecycle processes the different phases in a consistent manner, the execution order of the phases can be altered for special cases.

For example, you may want to add a Cancel button to a form. When clicked, it will skip all validation and simply navigate to another page without processing the values in a form. To alter the processing order of the request processing lifecycle, simply set the immediate attribute on a component.

Prerequisites

Java at least 8, Maven 3.6.3, Gradle 6.5.1, Tomcat 9.0.24, JSF 2.2.20, cdi-api 2.0.SP1 (for JDK 9 or above)

Project Setup

Create a maven or gradle based web project in Eclipse.

If you are creating maven based project then follow the below steps.

Go to File -> New -> Other. On popup window under Maven select Maven Project. Then click on Next. Select the workspace location – either default or browse the location. Click on Next. Now in next window select the row as highlighted from the below list of archtypes and click on Next button.

Select maven-arctype-webapp.

Now enter the required fields (Group Id, Artifact Id) as shown below:

Group Id : com.roytuts
Artifact Id : jsf2-immediate-attribute

Modify the pom.xml file as shown below to include the required dependencies.

<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.roytuts</groupId>
	<artifactId>jsf2-immediate-attribute</artifactId>
	<packaging>war</packaging>
	<version>0.0.1-SNAPSHOT</version>
	<dependencies>
		<dependency>
			<groupId>com.sun.faces</groupId>
			<artifactId>jsf-api</artifactId>
			<version>2.2.20</version>
		</dependency>
		<dependency>
			<groupId>com.sun.faces</groupId>
			<artifactId>jsf-impl</artifactId>
			<version>2.2.20</version>
		</dependency>
                <!-- for jdk 9 or above -->
		<dependency>
			<groupId>javax.enterprise</groupId>
			<artifactId>cdi-api</artifactId>
			<version>2.0.SP1</version>
		</dependency>
	</dependencies>
	<build>
		<finalName>jsf2-immediate-attribute</finalName>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.8.1</version>
				<configuration>
					<source>12</source>
					<target>12</target>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

If you creating gradle based project then you can use the following build.gradle script:

plugins {
	id 'war'
    id 'java-library'
}

repositories {
    jcenter()
}

dependencies {
    implementation 'com.sun.faces:jsf-api:2.2.20'
    implementation 'com.sun.faces:jsf-impl:2.2.20'
    implementation 'javax.enterprise:cdi-api:2.0.SP1'    
}

Deployment Descriptor

Modify generated web.xml file with below the below content to define JSF 2 related configurations.

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_1.xsd"
	id="WebApp_ID" version="3.1">
	<display-name>JSF 2 Immediate Attribute Example</display-name>
	<context-param>
		<param-name>javax.faces.PROJECT_STAGE</param-name>
		<param-value>Development</param-value>
	</context-param>
	<servlet>
		<servlet-name>Faces Servlet</servlet-name>
		<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>Faces Servlet</servlet-name>
		<url-pattern>*.jsf</url-pattern>
	</servlet-mapping>
	<servlet-mapping>
		<servlet-name>Faces Servlet</servlet-name>
		<url-pattern>*.faces</url-pattern>
	</servlet-mapping>
	<servlet-mapping>
		<servlet-name>Faces Servlet</servlet-name>
		<url-pattern>*.xhtml</url-pattern>
	</servlet-mapping>
	<welcome-file-list>
		<welcome-file>index.jsf</welcome-file>
	</welcome-file-list>
</web-app>

JSF Managed Bean

I will create a JSF 2 managed bean to bind the view with this managed bean.

package com.roytuts.jsf2.immediate.mbean;
import java.io.Serializable;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
@ViewScoped
@ManagedBean
public class RegistrationBean implements Serializable {
	private static final long serialVersionUID = 1L;
	private String name;
	private String gender;
	private String dateOfBirth;
	private String emailAddress;
	public String register() {
		FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("You have been successfully registered"));
		return null;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getGender() {
		return gender;
	}
	public void setGender(String gender) {
		this.gender = gender;
	}
	public String getDateOfBirth() {
		return dateOfBirth;
	}
	public void setDateOfBirth(String dateOfBirth) {
		this.dateOfBirth = dateOfBirth;
	}
	public String getEmailAddress() {
		return emailAddress;
	}
	public void setEmailAddress(String emailAddress) {
		this.emailAddress = emailAddress;
	}
}

Home Page

Create index.xhtml file with the below source code and this file will be displayed upon hitting context path URL in the browser.

<?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>JSF 2.2 - immediate attribute example</title>
</h:head>
<h:body>
    <h2>Welcome to JSF 2.2</h2>
    <h:form>
        <h:panelGrid>
            <h:commandButton value="Click here to register"
                action="/register.jsf?faces-redirect=true" />
        </h:panelGrid>
    </h:form>
</h:body>
</html>

I have a command button in the index.xhtml page so when this page appears I can simply click on the button to go to the registration page as shown below in the next step.

Registration Page

Create register.xhtml page with below source code to allow user register into the application.

<?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>JSF 2.2 - immediate attribute example</title>
</h:head>
<h:body>
    <h2>Register yourself</h2>
    <h:form>
        <h:panelGrid>
            <h:panelGroup>
                <h:messages style="color:red" />
            </h:panelGroup>
            <h:outputText value="Name" />
            <h:inputText value="#{registrationBean.name}" required="true"
                requiredMessage="Enter your full name" />
            <h:outputText value="Gender" />
            <h:selectOneRadio required="true"
                requiredMessage="Select your gender">
                <f:selectItem itemValue="Male" itemLabel="Male" />
                <f:selectItem itemValue="Female" itemLabel="Female" />
            </h:selectOneRadio>
            <h:outputText value="Date of Birth" />
            <h:inputText value="#{registrationBean.dateOfBirth}" required="true"
                requiredMessage="Your Date of Birth" />
            <h:outputText value="Email" />
            <h:inputText value="#{registrationBean.emailAddress}" required="true"
                requiredMessage="Your valid email address" />
            <h:panelGroup>
                <h:commandButton value="Register"
                    action="#{registrationBean.register}" />
                <h:commandButton value="Cancel"
                    action="/index.jsf?faces-redirect=true" />
            </h:panelGroup>
        </h:panelGrid>
    </h:form>
</h:body>
</html>

You have two command buttons in this register page – Register for registering yourself to the system and Cancel for cancelling and getting back to the index page or home page.

Problem

Now suppose you have entered something or you are trying to submit the form without filling anything in the form, so you will get validation error(s) and now you thought you want to get back to the index or home page but you will not be able to go back to the index or home page because of validation error(s).

So in this situation you have to correct all errors then only you can go back to the home page.

This happens because, even though you are just clicking the Cancel button with an empty form, it is still handled as a postback request, meaning that the JSF lifecycle commences to process an assumed incoming set of name-value pairs from the form.

But since the form is empty, validation errors are encountered before the navigation handler can process the cancel action event and a response of the same page is rendered back to the client.

The validation errors are shown on the registration page in the below image:

jsf 2 immediate attribute

Solution

Therefore the solution is to add immediate attribute to the Cancel button in page register.xhtml as shown below:

...
<h:panelGroup>
	<h:commandButton value="Register"
		action="#{registrationBean.register}" />
	<h:commandButton value="Cancel"
		action="/index.jsf?faces-redirect=true" immediate="true"/>
</h:panelGroup>
...

An immediate attribute is added to the Cancel button (or any UICommand component) and its value is set to true, which will allow the lifecycle to immediately bypass any validation and navigate back to the index.xhtml page.

In general, setting the immediate attribute to true on a UICommand component triggers an action event to be fired immediately during the Apply Request Values phase before the Process Validations phase, so no validation errors are encountered.

Testing the Application

You will get the same output as shown above while you hit the URL http://localhost:8080/jsf2-immediate-attribute/index.jsf and go to the registration page.

Source Code

Download source code

Thanks for reading.

Leave a Reply

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