Java EE CDI ViewScoped example
Introduction
Java EE 7 introduced a new set of CDI bean scopes. One of them - and the one we will cover in this article - is the view scope. As with other CDI beans, we configure a view scoped bean by using the @ViewScoped annotation.
View scoped beans have the same life time as the view which initially referenced them. This means that their scope is shorter that session, but greater than request. As soon as a view references a view scoped bean, the CDI container will create a new bean instance and reuse it across the view life time.
This behaviour may be useful when we need to provide Ajax functionality within a JSF view: Since the view scoped beans will keep state during the view life time, and consequently across subsequent bean action method invocations, we may develop a kind of conversation between the client and the server. We issue requests to the server and update our view according to the received responses without the need of a full page refresh.
View scoped beans will be discarded by the container as soon as an invoked action method returns a value (a method that is not void). By returning a value we are navigating into a fresh view so the bean should be discarded as it's not needed any more.
This tutorial considers the following environment:
- Ubuntu 12.04
- JDK 1.7.0.21
- Glassfish 4.0
The CDI view scoped bean
We start this example by defining a CDI view scoped bean:
package com.byteslounge.beans; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import javax.annotation.PostConstruct; import javax.faces.view.ViewScoped; import javax.inject.Named; @Named @ViewScoped public class TestBean implements Serializable { private static final long serialVersionUID = 1L; private List<String> items; private String item; @PostConstruct private void init() { items = new ArrayList<>(); items.add("Item 1"); items.add("Item 2"); items.add("Item 3"); } public void addItem() { if (item != null && !item.isEmpty()) { items.add(item); item = null; } } public String getItem() { return item; } public void setItem(String item) { this.item = item; } public List<String> getItems() { return items; } }
As we have mentioned before, the view scoped bean must be annotated with @ViewScoped (note that we are using the Java EE 7 CDI view scoped package [javax.faces.view.ViewScoped] and not the one that is managed by JSF).
As soon as the bean instance is created, the method that is annotated with the standard @PostConstruct annotation will be executed. This is where we usually load the needed data in order to support the conversation with the client. In this example we are simply initializing a dummy ArrayList that will hold a list of items.
The client will be able to add new items to the list by the means of an Ajax enabled form, as we will see in the next section.
The view
Now we will define a JSF view that will interact with the view scoped bean we just created:
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:ui="http://java.sun.com/jsf/facelets"> <h:head> <title>CDI ViewScoped example</title> </h:head> <h:body> <h:form> <ui:repeat value="#{testBean.items}" var="item"> <div> <h:outputText value="#{item}" /> </div> </ui:repeat> <br /> <h:inputText value="#{testBean.item}" /> <h:commandButton value="Add item" action="#{testBean.addItem}"> <f:ajax execute="@form" render="@form" /> </h:commandButton> </h:form> </h:body> </html>
The view is very straight forward: We display the item list along with an input text that allows the user to add more items to the list.
The command button is Ajax enabled, so the form data will be submitted asynchronously to the server and the form will be refreshed with the new list data as soon as the server response arrives. The page will not be fully refreshed (only the form will be refreshed, as we defined in the render attribute of the ajax element within the command button).
Testing
Let's test our sample. As soon as we access the view, a new view scoped bean instance will be created (and initialized) resulting in the following content:
Now we may add new items to the list and confirm that the page will not be fully refreshed. The items list will be preserved across requests so we may confirm that the bean life cycle is behaving as expected.
The source code used in this article is available for download at the end of this page.