© Bauke Scholtz, Arjan Tijms 2018

Bauke Scholtz and Arjan Tijms, The Definitive Guide to JSF in Java EE 8, https://doi.org/10.1007/978-1-4842-3387-0_8

8. Backing Beans

Bauke Scholtz and Arjan Tijms2

(1)Willemstad, Curaçao

(2)Amsterdam, Noord-Holland, The Netherlands

The “backing bean ” is a JSF-specific concept. It represents the sole JavaBean class which is ultimately used as a “managed bean ” responsible for providing data, actions, and/or UI (User Interface ) components in a JSF page.

Model, View, or Controller?

JSF (JavaServer Faces ) is a MVC (model-view-controller ) framework . It’s a widely used architectural design pattern for software applications which has its roots in desktop application development.1

In a JSF framework’s point of view, the model is represented by the backing bean, the view is represented by the component tree, which in turn is usually defined in a Facelets file, and the controller is represented by the FacesServlet which is already provided by JSF. From a Java EE application server’s point of view, however, the model is represented by the service layer which in turn is usually defined in EJB (Enterprise JavaBeans ) classes and JPA (Java Persistence API ) entities, the view is represented by all your JSF-based code, and the controller is the FacesServlet. In a JSF developer’s point of view, the model is represented by the service layer, the view is represented by the Facelets file, and the controller is represented by the backing bean.

The backing bean class can thus be either the model, view, or controller, depending on your point of view, while the service layer is always the model, and the Facelets file is always the view, and the FacesServlet is always the controller. Note that in this context, the “JSF developer ” is you, who develops a web application using the JSF framework for a Java EE application server.

Figure 8-1 illustrates the position of the backing bean in JSF’s MVC paradigm. It’s a Venn diagram where the intersection of the controller and the view is represented by the JSF component tree which could be bound to a backing bean via the component’s binding attribute. The intersection of the view and the model is represented by property getters and setters of EL (Expression Language ) value expressions which could be bound to a backing bean, usually via the component’s value attribute. The intersection of the controller and the model is represented by action method invocations of EL method expressions which could be bound to a backing bean via the component’s action attribute. Finally, the intersection of all intersections is represented by the backing bean itself.

A454457_1_En_8_Fig1_HTML.jpg
Figure 8-1 The position of the backing bean in JSF’s MVC paradigm

In this MVC paradigm the backing bean has thus a rather unique position. Note that the backing bean doesn’t necessarily need to be represented by a single class. It can even be represented by multiple classes, each with its own managed bean scope, like the view can be represented by multiple Facelets files and the model can be represented by multiple EJB/JPA classes.

Coming back to the JSF developer’s point of view, we can even get a step further with considering whether the backing bean is a model or a controller, depending on how you code the backing bean class. Following is one way:

@Named @RequestScoped @Stateful
public class ProductBacking {


    private String productName;
    private String productDescription;


    @Inject
    private ActiveUser activeUser;


    @PersistenceContext
    private EntityManager entityManager;


    public void save() {
        Product product = new Product();
        product.setName(productName);
        product.setDescription(productDescription);
        product.setCreatedBy(activeUser.get());
        entityManager.persist(product);
        FacesContext.getCurrentInstance().addMessage(null,
            new FacesMessage("Product created!"));
    }


    // Add/generate getters and setters for product name and description.
}

In this rather naïve way, the entity’s properties are essentially duplicated in the backing bean class and the business logic is tightly coupled in the backing bean class. In other words, the backing bean class has incorrectly taken over the responsibilities of the real model. One would misinterpret such backing bean class as being the sole model. When we eliminate this duplication and unreusability, we find another way:

@Named @RequestScoped
public class ProductBacking {


    private Product product = new Product();

    @Inject
    private ProductService productService;


    public void save() {
        productService.create(product);
        FacesContext.getCurrentInstance().addMessage(null,
            new FacesMessage("Product created!"));
    }


    public Product getProduct() {
        return product;
    }
}

whereby the ProductService looks as follows:

@Stateless
public class ProductService {


    @PersistenceContext
    private EntityManager entityManager;


    @Inject
    private ActiveUser activeUser;


    public Long create(Product product) {
        product.setCreatedBy(activeUser.get());
        entityManager.persist(product);
        return product.getId();
    }
}

This is actually the correct way of authoring backing beans . When comparing it to the first way, you could argue that the backing bean has, in the JSF developer’s point of view, become a controller for the EJB/JPA model. The backing bean being a controller is not wrong from the JSF developer’s point of view, but this is not actually correct from the JSF framework’s point of view where the FacesServlet is the real controller. The FacesServlet treats the backing bean as a model, because the FacesServlet doesn’t have direct access to the real model, the service layer. You as the JSF developer can, of course, in your context treat the backing bean as a controller, because you can easily ignore all duties of the FacesServlet as you don’t need to worry about its job while writing JSF code. All you need to worry about while writing JSF code is the view, the model, and the backing bean . The rest is done transparently by JSF.

Managed Beans

The conceptual difference between a “backing bean ” and a “managed bean ” can be represented by the following lines of code executed under the hood of the bean management facility:

BackingBeanClass managedBeanInstance = new BackingBeanClass();
someContext.put("managedBeanName", managedBeanInstance, someScope);

In other words, the backing bean is the concrete class created by you, the JSF developer , and registered into some bean management facility, such as CDI. The bean management facility will automatically manage the bean’s life cycle by performing construction, dependency injection, and destruction when necessary, without you having to do it manually. If you’ve ever developed with JSP/Servlets, this basically removes the need to manually instantiate beans and put them as an attribute of the ServletContext, HttpSession, or ServletRequest.2 To register a backing bean class as a CDI managed bean for JSF views, simply put the @javax.inject.Named annotation3 on the class signature.

@Named
public class BackingBeanClass {
    // ...
}

It will then immediately be available in EL context by #{backingBeanClass} and in all other managed beans via @Inject. The EL context is directly available in Facelets files. By default, the managed bean name is derived from the backing bean’s class name by lowercasing the first character. This can optionally be overridden by specifying the value of the @Named annotation.

@Named("managedBeanName")
public class BackingBeanClass {
    // ...
}

This is now in EL context available by #{managedBeanName}. Nothing has changed for the @Inject approach. Once a JSF backing bean becomes a managed bean, it will be automatically instantiated and initialized whenever it’s accessed for the first time in the context associated with the bean’s scope. It will be automatically destroyed when the life cycle associated with the bean’s scope has ended. More about managed bean scopes in the next section.

Historically, JSF provided a native way to register backing bean classes as managed beans: first, in JSF 1.x via <managed-bean> entries in faces-config.xml, and since JSF 2.0 via @javax.faces.bean.ManagedBean annotation, which is, since JSF 2.3, officially deprecated in favor of CDI @Named. CDI was introduced for first time in Java EE 6 , at the same time as JSF 2.0, with the aim of unifying the management of context-sensitive instances and injecting the currently available instances in each other. Unfortunately, the JSF 2.0 @ManagedBean was already set in stone long before CDI was finished, so those two ways of managing beans did exist in parallel for some time. The CDI bean management facility has several advantages on top of JSF bean management facility.

First, injecting one managed bean in another managed bean using CDI’s @Inject doesn’t require a getter/setter pair in the parent backing bean class , while JSF’s @javax.faces.bean.ManagedProperty requires a getter/setter pair, which is considered poor practice as this exposes too much information to the outside, which is potentially confusing. Should we access the injected bean via #{bean} or #{parentBean.bean}?

Second, the injected CDI managed bean can be of a narrower scope than the parent managed bean. This is possible because CDI @Inject actually injects a proxy instance which in turn delegates to the currently available instance, while JSF @ManagedProperty “injects” the actual instance by invoking the setter method directly after the construction of the parent bean.

Third, CDI managed beans are accessible in all other Java EE artifacts which are not directly managed by JSF, such as web servlets, web filters, web listeners, socket end points, web service end points, enterprise beans, etc. This allows a very easy way of exchanging data across various layers within the same application, particularly within the same HTTP session.

Once again, the JSF bean management facility is officially deprecated since JSF 2.3. You should absolutely not use it any more in new JSF applications. It will still be there in the JSF API for backward compatibility, but chances are that the javax.faces.bean package will be removed altogether in a future JSF version. Existing JSF applications should be migrated to CDI as soon as possible. CDI is natively available in normal Java EE application servers and relatively easy to install in barebones servlet containers. For example, JBoss Weld, one of the CDI implementations, can already be installed in Tomcat by simply adding the single dependency org.jboss.weld.servlet:weld-servlet-shaded to the project4 without any further effort .

Scopes

The managed bean scope basically represents the lifetime of the managed bean. As hinted in the previous section, in plain JSP/Servlet perspective the scopes are represented by the object being put as an attribute of the ServletContext, HttpSession, or ServletRequest. Those objects will then become application scoped, session scoped, and request scoped, respectively. This is still how it works with CDI and all; it only adds an extra abstract layer over it so that you don’t any more need to manually create and put the objects in a certain scope.

In standard JSF, the following CDI managed bean scopes are available for JSF backing beans, ordered from the longest living to the shortest living.

  1. @javax.enterprise.context.ApplicationScoped

  2. @javax.enterprise.context.SessionScoped

  3. @javax.enterprise.context.ConversationScoped

  4. @javax.faces.flow.FlowScoped

  5. @javax.faces.view.ViewScoped

  6. @javax.enterprise.context.RequestScoped

  7. @javax.enterprise.context.Dependent

Note that the javax.faces.bean package also defines a set of scopes, but they are only applicable on the beans managed by JSF’s @ManagedBean, not on beans managed by CDI. Moreover, the javax.faces.bean package is deprecated since JSF 2.3 in favor of CDI.

@ApplicationScoped

An application-scoped managed bean instance is tied to the lifetime of the web application itself. It’s under the hood represented as an attribute of the ServletContext which is created on the web application’s deployment and destroyed on the web application’s undeployment. Note that this is not equal to the server’s startup and shutdown. Web applications can be deployed and undeployed on a running server.

In other words, there’s only one instance of an application-scoped managed bean throughout the web application’s lifetime which is shared across all requests and sessions. You could argue that it behaves like a singleton. However, it doesn’t actually follow the singleton design pattern. It follows the “just create one” design pattern.5 A real singleton doesn’t have any public constructor but only a static method which returns a statically initialized lazy loaded instance. A real JavaBean, on the other hand, requires the presence of a default constructor.

By default, an application-scoped bean managed instance is created for the first time when the web application’s code accesses it for the first time during the web application’s lifetime. It’s thus not, per definition, immediately created when the ServletContext instance is created. It is, however, guaranteed when the ServletContext instance is destroyed.

Application-scoped managed beans are useful for application-wide data which needs to be initialized only once in the application’s lifetime, or needs to provide non-static getters which delegate to static variables, or needs to provide functions for usage in EL. The following example makes sure that application settings stored in the database are loaded only once and provided as a Map by #{settings} during the rest of the application’s lifetime .

@ApplicationScoped
public class ApplicationSettingsProducer {


    private Map<String, String> settings;

    @Inject
    private ApplicationSettingsService applicationSettingsService;


    @PostConstruct
    public void init() {
        settings = applicationSettingsService.getAll();
    }


    @Produces @Named
    public Map<String, String> getSettings() {
        return settings;
    }
}

Note that the @Named annotation is placed on the getter, which implies a managed bean name matching the property name: #{settings}. Also note that the getter in turn needs the @Produces annotation in order to be recognized as a managed bean producer. Following is another example which offers text formatting functions .

@Named @ApplicationScoped
public class Format {


    public String date(LocalDate localDate) {
        if (localDate != null) {
            return localDate.format(DateTimeFormatter.ISO_LOCAL_DATE);
        }
        else {
            return "n/a";
        }
    }


    public String currency(BigDecimal amount) {
        if (amount != null) {
            return NumberFormat.getCurrencyInstance(Locale.US)
                .format(amount);
        }
        else {
            return "n/a";
        }
    }
}

This could be useful in, for example, a data table to keep the Facelets code terse.

<h:dataTable value="#{cart.products}" var="product">
    <h:column>#{format.date(product.lastModified)}</h:column>
    <h:column>#{format.currency(product.discount)}</h:column>
</h:dataTable>

It’s also useful in case you need a formatted value in an attribute which doesn’t allow a nested <h:outputText><f:convertXxx>.

<h:commandLink ... title="Last visited #{format.date(user.lastVisited)}">

@SessionScoped

A session-scoped managed bean instance is tied to the lifetime of the established HTTP session. It’s under the hood represented as an attribute of the HttpSession which is created for every unique client on demand of the web application’s code. When the web application’s code directly or indirectly pokes the HttpSession for the first time via HttpServletRequest#getSession(),the servlet container will create a new HttpSession instance, generate a long and unique ID, and store it in server’s memory. The servlet container will also set a session cookie on the HTTP response with “JSESSIONID” as the cookie name and the unique session ID as the cookie value. A “session cookie” is identified by the absence of the “maximum age” attribute.

As per the HTTP cookie specification, the client (the web browser) is required to send this cookie back in the header of the subsequent requests as long as the cookie is valid. In any decent web browser you can inspect the request and response headers in the “Network” section of the web developer’s toolset which is accessible by pressing F12 in the web browser. The servlet container will check every incoming HTTP request for the presence of the cookie with the name “JSESSIONID” and use its value (the session ID) to get the associated HttpSession instance from server’s memory.

On the server side, the HttpSession instance stays alive until it has not been accessed for more than the timeout value as specified in the <session-timeout> setting of web.xml, which defaults to 30 minutes on most if not all servlet containers. So, when the client doesn’t visit the web application for longer than the time specified, the servlet container will destroy the HttpSession instance. Every subsequent HTTP request, even with the cookie specified, will not have access to the HttpSession instance anymore; the servlet container will create a new HttpSession instance and overwrite the cookie value with the new session ID.

On the client side, by default, all session cookies stay alive for as long as the browser instance is running. So, when the client shut downs the browser instance, all session cookies are destroyed on the client side. In a new browser instance, the session cookies from a previous browser session are not available any more, so the browser won’t send any JSESSIONID cookie. The server will then interpret it as a brand-new session. The HttpSession instance associated with the previous browser session will silently expire on the server side.

By default, a session-scoped managed bean instance is created for the first time when the web application’s code accesses it for the first time during the HTTP session’s lifetime. It’s thus not, per definition, immediately created when the HttpSession instance is created. It is, however, guaranteed to be destroyed when the HttpSession instance is destroyed. Session-scoped managed beans are effectively shared across all browser tabs within the same browser session .

Session-scoped managed beans are useful for keeping track of client-specific data, such as the entity representing the currently logged-in user, the selected language, and other user-related preferences. The following example calculates the current locale and provides a getter/setter for it so that it can be obtained in the view and modified by an UIInput component.

@Named @SessionScoped
public class ActiveLocale implements Serializable {


    private Locale current;

    @PostConstruct
    public void init() {
        FacesContext context = FacesContext.getCurrentInstance();
        current = context.getApplication()
            .getViewHandler().calculateLocale(context);
    }


    // Getter+setter.
}

A more elaborate example can be found in the section “Changing the Active Locale” in Chapter 14. Do note that session-scoped managed beans must implement Serializable because the HttpSession instance itself, where those beans are being stored, is subject to being written to disk in case of a server restart or even to being transferred over the network to a different server in case of a server cluster configuration with a distributable session .

Another classic example is a “shopping cart.”

@Named @SessionScoped
public class Cart implements Serializable {


    private List<Product> products = new ArrayList<>();

    public void addProduct(Product product) {
        products.add(product);
    }


    // ...
}

@ConversationScoped

A conversation-scoped managed bean is tied to the lifetime of the injected javax.enterprise.context.Conversation instance which offers begin() and end() methods which must be explicitly invoked by the web application’s code in order to indicate the start and end of the conversation scope. The conversation scope is represented by a predefined HTTP request parameter with a default name of “cid” (“Conversation ID”) whose value references represents the conversation ID. The conversation ID in turn references an isolated mapping in the current HTTP session where the conversation-scoped managed bean instances will be stored.

As long as the conversation scope has not started, the conversation-scoped managed bean will behave like a request-scoped managed bean. When the application code explicitly invokes Conversation#begin(), then the conversation scope will start and a custom javax.faces.application.ViewHandler provided by the CDI implementation will make sure that all its getXxxURL() methods such as getActionURL() and getBookmarkableURL() return a URL (uniform resource locator) with the conversation ID parameter included. In case of Weld, that’s the ConversationAwareViewHandler.6 All JSF UIForm and UIOutcomeTarget components derive their action and target URLs from those methods of the ViewHandler. The generated HTML output of those components will thus ultimately include the conversation ID in the target URL.

On an incoming HTTP request, when the conversation ID parameter is present in the request, and it is still valid, the CDI implementation will obtain the associated conversation scope from the HTTP session and make sure that all conversation-scoped managed beans are obtained from exactly this conversation scope identified by the conversation ID. This works on both GET and POST requests. Any form submit or any link/navigation to a URL with the conversation ID included will provide access to the very same conversation scope, as long as it’s still valid. The conversation scope ends when the application code explicitly invokes Conversation#end(). When the end user reuses the “cid” request parameter later, or manipulates its value to one which isn’t started in its own browser session, or when the underlying HttpSession instance is destroyed, then CDI will throw a javax.enterprise.context.NonexistentConversationException.

Conversation-scoped managed beans are particularly useful in order to be able to return to a particular stateful page within the same browser session after being redirected elsewhere. A classic example is a third-party web service which is included in an HTML <iframe> or opened in a new browser tab or even targeted in the action attribute of a plain HTML <form>, and can, via a specific request parameter, be configured to redirect back to your web application after completing the service. When you include the conversation ID in the redirect URL, then you will in the redirected page be able to resume with exactly the same conversation-scoped managed bean instance as it was before the redirect. This allows you the opportunity to finalize and unlock any pending transactions and, of course, end the conversation .

Given a checkout button which looks as follows,

<h:form>
    ...
    <ui:fragment rendered="#{empty payment.url}">
        ...
        <h:commandButton value="Checkout" action="#{payment.checkout}">
            <f:ajax render="@form" />
        </h:commandButton>
    </ui:fragment>
    <ui:fragment rendered="#{not empty payment.url}">
        <iframe src="#{payment.url}"></iframe>
    </ui:fragment>
</h:form>

here’s what the associated conversation-scoped bean behind #{payment} looks like:

@Named @ConversationScoped
public class Payment implements Serializable {


    private Order order;
    private String url;


    @Inject
    private Cart cart;


    @Inject
    private OrderService orderService;


    @Inject
    private Conversation conversation;


    public void checkout() {
        conversation.begin();
        order = orderService.lockProductsAndPrepareOrder(cart);
        url = "http://third.party.com/pay?returnurl="
            + URLEncoder.encode("http://my.site.com/paid?cid="
            + conversation.getId(), "UTF-8");
    }


    public void confirm() {
        orderService.saveOrderAndCreateInvoice(order);
        conversation.end();
    }


    @PreDestroy
    public void destroy() {
        orderService.unlockProductsIfNecessary(order);
    }


    public String getUrl() {
        return url;
    }
}

Basically, the checkout button is only rendered when there’s no payment URL set. Once the button is pressed, all products of the shopping cart are locked and the order is prepared. Also, depending on the third-party payment service, the URL referring it must be prepared whereby you include the return URL as some query parameter in the URL of the payment service. The return URL should in turn include the “cid” request parameter representing the conversation ID. In the redirected page which will actually be loaded in the <iframe>, you can just mark the conversation complete with <f:viewAction>.

<f:metadata>
    <f:viewAction action="#{payment.confirm}" />
</f:metadata>

Of course, the average third-party payment service should have a more elaborate Java or even JavaScript API instead of <iframe>; also, it should be possible to provide different return pages for each payment outcome such as payment failed and payment aborted. The above example is just to give the general idea.

@FlowScoped

A flow-scoped managed bean is tied to the lifetime of a JSF flow. It uses the same principle as conversation scope, only the conversation is further narrowed down to a specific set of JSF views in an isolated subfolder. Once the end user clicks a JSF link or button component which navigates to a specific entry page of a JSF flow, then the flow scope will automatically start. The flow scope cannot be started when you open the entry page without navigating via a JSF component. That is, JSF will, with help of the ViewHandler, automatically append the predefined HTTP request parameter “jfwid” (“javax.faces Window ID”) to the outcome URL whose value represents the JSF client window ID. The JSF client window ID in turn references an isolated mapping in the current HTTP session where the flow-scoped managed beans are stored.

Additionally, particularly when using a UIOutcomeTarget component instead of a UICommand component to navigate, the query string may be accompanied with “jffi” (javax.faces Flow ID) and “jftfdi” (javax.faces To Flow Document ID) request parameters. Those are actually only mandatory for starting a JSF flow using a GET request. Technically, for the rest of the JSF flow, “jfwid” is sufficient. As long as the “jfwid” parameter is present, and is still valid, then the JSF flow is idempotent and can be resumed using a GET request. When you open a new browser tab and navigate into the JSF flow, then actually a new flow scope will be started, independent of the JSF flow in other tab. Once a postback request within the JSF flow navigates to a page outside the JSF flow, then the flow scope will automatically end. When the end user reuses the “jfwid” request parameter later, or manipulates its value to one which isn’t started in its own browser session, or enters the flow directly, or when the underlying HttpSession instance is destroyed, then CDI will throw a javax.enterprise.context.ContextNotActiveException.

The major difference between the flow scope and the conversation scope is thus that the pages within a JSF flow cannot be entered directly. They will automatically start when the end user navigates to the entry page of the JSF flow and they will automatically end when a postback navigates outside the JSF flow. Flow-scoped managed beans are useful in order to isolate a conversation to a specific set of JSF pages. A classic real-world example is a booking application which is spread over multiple forms in physically different pages.

There are various ways to define a JSF flow. One way is by convention, another way is by declarative configuration in the /[flowId]/[flowId]-flow.xml file, and yet another way is by programmatic configuration using javax.faces.flow.FlowBuilder API.7 In this book we’ll restrict ourselves to convention over configuration. First, create the following folder structure:

A454457_1_En_8_Figa_HTML.jpg

The first convention is that the flow entry page must have exactly the same name as the subfolder it is sitting in. In this case, that’s “booking”. This is considered the Flow ID. The second convention is that there must be a *-flow.xml file in the subfolder whose name is prefixed with the Flow ID, i.e., booking-flow.xml. This XML configuration file can be kept empty for now. It’s only useful when you want to fine-grain the JSF flow configuration , e.g., by specifying a different entry page. Without this file, the JSF flow scope won’t be activated. One disadvantage of at least one activated JSF flow in the web application, however, is that the JSF client Window ID parameter “jfwid” will be appended to every single navigation URL, even when it doesn’t target a JSF flow. This URL pollution may for some developers be the main reason to not use the JSF flow scope at all.

The navigation component in order to enter a JSF flow must be placed in a JSF page outside the flow subfolder. The navigation outcome must reference the subfolder name, which is the Flow ID. Here’s an example in /home.xhtml.

<h:button value="Start booking" outcome="booking" />

Of course, this can be substituted with <h:link>. It’s recommended to use GET just for this so that the booking page’s URL reflects in the browser’s address bar. Then, in all pages within the subfolder, you can reference a flow-scoped managed bean which will be shared across all these pages. You can navigate back and forth between these pages as well while retaining the flow-scoped managed bean instance. We recommend that you use Ajax with redirect for this. The Ajax submits will improve the user experience . The redirects will make sure that the individual pages are still bookmarkable.

/booking/booking.xhtml:

<h:form>
    <h:inputText value="#{booking.startDate}" />
    ...
    <h:commandButton value="Next" action="persons?faces-redirect=true">
       <f:ajax execute="@form" render="@form" />
    </h:commandButton>
</h:form>

/booking/persons.xhtml:

<h:form>
    <ui:repeat value="#{booking.persons}" var="person">
        <h:inputText value="#{person.name}" />
        ...
    </ui:repeat>
    ...
    <h:commandButton value="Back" action="booking?faces-redirect=true">
       <f:ajax execute="@form" render="@form" />
    </h:commandButton>
    <h:commandButton value="Next" action="confirm?faces-redirect=true">
       <f:ajax execute="@form" render="@form" />
    </h:commandButton>
</h:form>

/booking/confirm.xhtml:

<h:form>
    <h:outputText value="#{booking.startDate}" />
    ...
    <h:commandButton value="Back" action="persons?faces-redirect=true">
       <f:ajax execute="@form" render="@form" />
    </h:commandButton>
    <h:commandButton value="Next" action="payment?faces-redirect=true">
       <f:ajax execute="@form" render="@form" />
    </h:commandButton>
</h:form>

/booking/payment.xhtml:

<h:form>
    <h:selectOneMenu value="#{booking.paymentMethod}">
        ...
    </h:selectOneMenu
    ...
    <h:commandButton value="Back" action="confirm?faces-redirect=true">
       <f:ajax execute="@form" render="@form" />
    </h:commandButton>
    <h:commandButton value="Submit" actionListener="#{booking.submit()}"
       action="/home?faces-redirect=true">
       <f:ajax execute="@form" render="@form" />
    </h:commandButton>
</h:form>

And, finally, the flow-scoped bean behind #{booking}:

@Named @FlowScoped("booking")
public class Booking implements Serializable {


    private LocalDate startDate;
    private List<Person> persons;
    private PaymentMethod paymentMethod;
    // ...


    public void submit() {
        // ...
    }
}

You see, the most of navigation task is done by the action attribute of the command components.?faces-redirect=true is a special request parameter which is internally recognized by JSF as an instruction to perform a redirect after postback and of course strip off from the target URL before performing the actual redirect. Once the postback leaves the flow, the flow-scoped managed bean is destroyed and the previously presented page URLs are not reusable anymore.

@ViewScoped

A view-scoped managed bean is tied to the lifetime of the JSF view state. The JSF view state is elaborated in the section “View State” in Chapter 3. In a nutshell, a view-scoped managed bean lives as long as the end user is performing postback requests on the very same JSF view and the invoked action methods keep returning null or void. Once the action method returns non-null, even if it’s an empty string or represents the same view, then the view scope will end. View-scoped managed beans are not shared across browser tabs within the same browser session. Each one gets its own unique instance. Effectively, they are indirectly identified by the javax.faces.ViewState hidden input field in the generated HTML representation of a JSF form.

However, view-scoped managed beans are not stored in the JSF view state, not even when client-side state saving is enabled. They are actually stored in the HTTP session, regardless of the JSF state saving method. They are not immediately destroyed when the end user unloads the web page either by performing a GET request via a link or bookmark or editing the URL in browser’s address bar, or by closing the browser tab. They will stick around in the HTTP session and only get destroyed when the HTTP session expires.

As an end user can in theory spawn an unlimited amount of browser tabs within the same session, and thus also as many JSF view states and view-scoped managed beans, there’s a configurable maximum limit on the amount of JSF view states and view-scoped managed beans which will be stored in the HTTP session. Once this limit is reached, the least recently used JSF view state and view-scoped managed bean will be expired and destroyed. When the end user actually goes back to the tab that originally referenced the now expired JSF view state, and performs a postback request on it, JSF will throw a ViewExpiredException. The limit on the amount of JSF view states is dependent on the JSF implementation used. In Mojarra, this limit is configurable by the com.sun.faces.numberOfLogicalViews context parameter in web.xml whose default value is 15.8

<context-param>
    <param-name>com.sun.faces.numberOfLogicalViews</param-name>
    <param-value>25</param-value>
</context-param>

If your web application, however, invites being opened in many more browser tabs, such as a discussion forum or a Q&A site, then you’d better switch to client-side state saving. This way the JSF view states are no longer stored in the HTTP session and will therefore also never expire. However, the associated view-scoped managed beans are still stored in the HTTP session and expirable. When the end user actually goes back to the tab that originally referenced the now expired view scoped-managed bean, and performs a postback request on it, JSF will not throw a ViewExpiredException but instead will create a new one from scratch, thereby losing all the state changes to the original managed bean instance. The limit on the amount of view-scoped managed beans is also dependent on the JSF implementation used. In Mojarra, this limit is not yet configurable by a web.xml context parameter. It’s only configurable by explicitly setting the session attribute with the name com.sun.faces.application.view.activeViewMapsSize whose default value is 25. This can be achieved with an application-scoped managed bean as follows, which observes the initialization of the session scope.

@ApplicationScoped
public class Config {


    public void sessionCreated
        (@Observes @Initialized(SessionScoped.class) HttpSession session)
    {
        session.setAttribute
            ("com.sun.faces.application.view.activeViewMapsSize", 15);
    }
}

This configuration actually decreases the default value to be equal to default maximum amount of JSF view states in session. This is fine when you’re using server-side state saving and all your JSF views effectively reference only one view-scoped managed bean instance. However, in a decently developed and refactored JSF web application, the average JSF page usually references multiple view-scoped managed beans. If you have, for example, a maximum amount of three different view-scoped managed beans per JSF view, then you’d best set the limit to three times the value of com.sun.faces.numberOfLogicalViews. You only need to take into account the possible memory consumption. It will quickly go overboard when the view-scoped managed beans in turn hold, relatively, a lot of data.

View-scoped managed beans are very useful for retaining state across Ajax-based postbacks on the same JSF view, particularly if those postbacks result in changes in the value of the rendered attribute of any UIComponent, or the disabled or readonly attribute of an UIInput component, or the disabled attribute of any UICommand component within the same JSF view. That is, on a subsequent postback, JSF will, as part of a safeguard against a tampered request, recheck them before actually processing the component. If the managed bean holding the state was request scoped instead of view scoped, then those changes in the conditions would get lost in a subsequent postback and the postback wouldn’t get processed as intuitively expected. In other words, view-scoped managed beans are particularly useful in dynamic forms .

One example is a drop-down which conditionally renders a free text field when the “other” option is chosen.

<f:metadata>
    <f:importConstants type="com.example.project.model.Title" />
</f:metadata>
...
<h:form>
    <h:selectOneMenu value="#{bean.customer.title}">
        <f:selectItems value="#{Title}" />
        <f:ajax render="other" />
    </h:selectOneMenu>
    <h:panelGroup id="other">
        <h:inputText rendered="#{bean.customer.title eq 'OTHER'}"
            value="#{bean.customer.titleOther}" required="true" />
    </h:panelGroup>
    ...
    <h:commandButton value="Save" action="#{bean.save}" />
</h:form>

This construct won’t work when the managed bean is request scoped and is thus recreated on every request. When the drop-down changes, it creates a new instance of the request-scoped bean, sets the title there, and renders the free text field and finally the request-scoped bean instance gets destroyed. When the form submits, it creates a new instance of the request-scoped bean, thus without the customer title, and when JSF checks the rendered attribute during the apply request values phase (second phase) of the free text field and notices it’s false, ultimately it won’t process the free text field at all. It will only work when the managed bean is view scoped because the customer title set during the drop-down change is still available during the apply request values phase (second phase) of the form submit.

There is, however, a work-around. You could let the rendered attribute check the HTTP request parameter instead of the model value. As explained in Chapter 4, the HTTP request parameter name is specified by the component’s client ID. You could bind the drop-down component to the view and then use its client ID to obtain the HTTP request parameter value .

<h:selectOneMenu binding="#{title}" value="#{bean.customer.title}">
    <f:selectItems value="#{Title}" />
    <f:ajax render="other" />
</h:selectOneMenu>
<h:panelGroup id="other">
    <h:inputText rendered="#{param[title.clientId] eq 'OTHER'}"
        value="#{bean.customer.titleOther}" required="true" />
</h:panelGroup>

This way, when JSF checks the rendered attribute during the apply request values phase (second phase) of the form submit, it will notice it’s true and continue processing the free text field, even when the managed bean is request scoped and thus #{bean.customer.title} is still null at that point. Note that the binding attribute doesn’t reference a managed bean property. This is unnecessary as it wouldn’t be used over there. All of this is also applicable on the readonly attribute of any UIInput component and the disabled attribute of any UIInput and UICommand component.

There may also be cases wherein a request-scoped managed bean will work just fine but imposes a risk of a corrupted state as compared to a view-scoped managed bean, certainly when relying on data coming from a shared database which could be mutated by other users. This affects primarily use cases whereby UIInput or UICommand components are nested in an iterating component such as <h:dataTable>, <ui:repeat> and <c:forEach> which iterates over a model coming from the database. This was explained previously in Chapter 6, but for the sake of refreshment, we will explain it once more. Imagine a table of products with a delete button in a column.

<f:form id="list">
    <h:dataTable id="products" value="#{products.list}" var="product">
        ...
        <h:column>
            <h:commandButton id="delete" value="Delete"
                action="#{products.delete(product)}">
                <f:ajax render="@namingcontainer" />
            </h:commandButton>
        </h:column>
    </h:dataTable>
</h:form>

With this backing bean:

@Named @ViewScoped
public class Products implements Serializable {


    private List<Product> list;

    @Inject
    private ProductService productService;


    @PostConstruct
    public void init() {
        list = productService.list();
    }


    public void delete(Product product) {
        productService.delete(product);
        list.remove(product);
    }


    public List<Product> getList() {
        return list;
    }
}

The submitted button is under the hood identified by the iteration index. When JSF is about to process the form submit, and a product has been added or removed or even reordered in the meanwhile, causing the iteration index to be changed, then the invoked action would possibly be performed against the wrong item currently at the initially known index. This is dangerous for the integrity of the model . In such a case the value of the iteration component must refer a view-scoped model.

Also here, there is a work-around. Instead of relying on the iteration index, you can also rely on the unique identifier of the iterated object which must be passed as an HTTP request parameter instead of as an EL method argument.

<f:form id="list">
    <h:dataTable id="products" value="#{products.list}" var="product">
        ...
        <h:column>
            <h:commandButton id="delete" value="Delete"
                action="#{products.delete}">
                <f:param name="id" value="#{product.id}" />
                <f:ajax render="@namingcontainer" />
            </h:commandButton>
        </h:column>
    </h:dataTable>
</h:form>

Whereby the backing bean is adjusted as follows:

@Named @RequestScoped
public class Products {


    private List<Product> list;

    @Inject @ManagedProperty("#{param.id}")
    private Long id;


    @Inject
    private ProductService productService;


    @PostConstruct
    public void init() {
        list = productService.list();
    }


    public void delete() {
        productService.delete(id);
        list.removeIf(product -> product.getId().equals(id));
    }


    public List<Product> getList() {
        return list;
    }
}

No, the action="#{products.delete(product.id)}" instead of using <f:param> won’t work. The technical reason is that <f:param> is executed immediately during the render response phase of the form, long before the end user presses the delete button. Thus, at the moment the end user presses the delete button, it’s guaranteed to have the correct value. The EL method argument, on the contrary, is only evaluated after the end user has pressed the delete button. When the model has changed in the meanwhile, it would thus evaluate to the wrong ID when the iteration index of the particular product has changed.

As explained in the beginning of this section, the standard JSF view-scoped bean management facility has thus two major disadvantages: first, the instances don’t immediately expire when the end user unloads the web page and stick around in the HTTP session; second, even with client-side state saving enabled they are stored in the HTTP session. Those problems are currently not yet solved in the standard JSF API.

For now, the JSF utility library OmniFaces offers an enhanced @ViewScoped annotation which solves those two disadvantages.9 View-scoped managed beans annotated with @org.omnifaces.cdi.ViewScoped will actually get destroyed when the end user unloads the page. This is under the hood done with help of Navigator.sendBeacon API10 in JavaScript, and a specialized ViewHandler implementation provided by OmniFaces which listens on those unload requests. There have been production applications making heavy use of view-scoped managed beans whereby the memory usage has reduced for up to 80% after switching from standard JSF @ViewScoped to OmniFaces @ViewScoped. This makes the destroy-on-unload feature a major candidate to be added to the future version of the standard JSF API.

In order to save the physical view-scoped managed bean in the JSF view state when client-side state saving is enabled, the saveInViewState attribute of the OmniFaces @ViewScoped annotation must be set to true. You only need to keep in mind that those beans will never expire, not even when the page gets unloaded, or when the HTTP session expires. In fact, the entire bean has physically become part of the generated HTML output, in the javax.faces.ViewState hidden input field. There have been community requests to make JSF state management more flexible, such as toggling between client- and server-side state saving on a per-view (per UIViewRoot) or even per-form (per UIForm) basis, and being able to store view-scoped managed beans in the actual view state instead of in the HTTP session. This may also be reconsidered in a future version of the standard JSF API.

@RequestScoped

A request-scoped managed bean is among others tied to the lifetime of the HTTP request, which is for JSF the most important case. Other cases include the lifetimes of a call to an EJB asynchronous method invocation (method annotated by @Asynchronous), an EJB timer timeout method, or when a message-driven bean (MDB) processes a message. Note that an Ajax request also counts as a single HTTP request.

When the client sends an HTTP request to the server, the servlet container will create HttpServletRequest and HttpServletResponse instances representing the HTTP request and response, and pass them through the authentication modules, filters, and servlets. They will be destroyed immediately after all authentication modules, filters, and servlets are finished processing the request and response. In other words, every HTTP request creates a new instance of a request-scoped managed bean which is available only during that request and not in other requests.

Request-scoped managed beans are useful for simple and static forms which don’t have any dynamic Ajax-based updates, for which you would rather use a view-scoped managed bean. Think of a login form or a contact form.

@Named @RequestScoped
public class Login {


    private String username;
    private String password;


    // ...
}

Sure, those forms can be tied to a view-scoped managed bean as well without problems, but that’s a waste of memory space. Note that you should absolutely not make the JPA entity itself a managed bean. In other words, the following approach is factually wrong:

@Named @RequestScoped
@Entity
public class Product {
    // ...
}

Not only does this violate the Law of Demeter,11 but it also risks that JPA won’t be able to persist it, because CDI actually wraps the managed bean in a proxy class and JPA would then not be able to obtain the entity information from it when you’re about to pass an injected instance to JPA. Hibernate would in such case throw “Unknown entity: com.example.Entity$Proxy$_$$_WeldClientProxy”, which thus actually represents the CDI proxy class .

You might at this point wonder how exactly CDI actually works. First, it will during the web application’s startup collect all classes that are annotated with a CDI-compatible scope annotation. Then, it will generate proxy classes for all of them. Ultimately instances of those proxy classes are being injected. Given an example bean class com.example.Bean, the generated CDI proxy class may look as follows:

public class Bean$Proxy$_$$_CDI extends Bean implements Serializable {

    public String getSomeProperty() {
        Bean actualInstance = CDI.resolveItSomehow();
        return actualInstance.getSomeProperty();
    }


    public void setSomeProperty(String someProperty) {
        Bean actualInstance = CDI.resolveItSomehow();
        actualInstance.setSomeProperty(someProperty);
    }
}

You see, it extends the bean class, makes it serializable, and uses an “impossible to clash” class name and lets all methods delegate to the actual instance obtained from the CDI context. You’ll probably also immediately understand why the CDI bean management facility requires the bean classes to be public and have a public default constructor. You’ll also see that when such a proxy class is created and injected, the underlying actual instance is not necessarily created. It’s only automatically created when the fictive CDI.resolveItSomehow() method is invoked. Under the hood, it will obtain the context from a thread local variable, exactly how FacesContext#getCurrentInstance() works.

By the way, EJB also works with serializable proxies this way. That’s why it could seemingly magically perform all the heavy lifting of starting or joining a transaction and use pooled instances. The legacy JSF @ManagedBean facility, however, did not use proxies at all. That’s exactly why it was impossible to inject a JSF managed bean of a narrower scope in a JSF managed bean of a broader scope . With CDI bean management facility this is just possible.

Note that CDI has also a @javax.enterprise.inject.Model stereotype annotation which basically bundles both @Named and @RequestScoped into a single annotation. This is in no way different from a request-scoped managed bean. Unfortunately, it does not represent a non-proxy instance; otherwise it would be nice to put it on an @Entity. The @Model annotation exists just for convenience.

@Dependent

A dependent-scoped managed bean is tied to the lifetime of the scope wherein it’s being created for the first time. So, if you inject it into an @ApplicationScoped, then it will become application scoped too. And if you inject it into a @ViewScoped, it will become view scoped too. And so on. This is the default CDI scope.

This has, however, a caveat. When you forget to declare the CDI scope annotation on your backing bean, or import a scope with exactly the same name from the wrong package, e.g., javax.faces.bean.RequestScoped instead of javax.enterprise.context.RequestScoped, and you reference it directly in EL, as in #{dependentScopedBean}, instead of referencing it via another managed bean, as in #{requestScopedBean.dependentScopedBean}, then every EL evaluation will basically create a brand-new instance which exists only within that EL context. In other words, imagine a JSF form with two input fields and a submit button, each bound to a dependent-scoped managed bean, then you will effectively end up with three separate instances. One wherein the first input field is set, one wherein the second input field is set, and one wherein the action method is invoked. So, if you ever observe odd behavior of null submitted values in the action method even though the required validation has passed, the first thing to check is the actually used CDI managed bean scope.

The major technical difference with other scopes is that dependent-scoped managed beans are not proxied. In other words, what’s being injected is the actual instance .

@Dependent
public class Entities {


    @Produces
    public Product getProduct() {
        return new Product();
    }
}


@Named @RequestScoped
public class Products {


    @Inject
    private Product product;


    @Inject
    Private ProductService productService;


    public void add() {
        productService.create(product);
    }


    public Product getProduct() {
        return product;
    }
}

Note that you still can’t use <h:inputText value="#{product.name}">, because it would get its own instance. You still need to use #{products.product.name}. For exactly this reason, the producer isn’t @Named. Also note that in case of a view-scoped managed bean, you’d need to force JSF to restart the view scope by returning a non-null outcome from action method; otherwise the injected Product instance would be reused for the next view.

Which scope to choose?

Which scope to choose depends solely on the data (instance variables aka the state) the bean holds and represents. You should strive to put the state in the shortest possible acceptable scope. Start with a @RequestScoped bean. Once you notice that some state needs to be retained after a postback on the same view, split that state exactly into a new @ViewScoped bean which you, in turn, @Inject in the @RequestScoped bean. Once you notice that some state needs to be retained on another GET request within the same session, split that state exactly into a new @ConversationScoped bean which you in turn @Inject in the @RequestScoped bean. And so on.

Abusing an @ApplicationScoped bean for session-, conversation-, flow-, view-, or request-scoped data would make it to be shared among all users, so anyone else can see each other’s data, which is just plain wrong. Abusing a @SessionScoped bean for conversation-, flow-, view-, or request-scoped data would make it to be shared among all browser tabs in the same session, so the end user may experience inconsistencies when interacting with every view after switching between tabs, which is bad for user experience. Abusing a @RequestScoped bean for view-, flow-, or conversation-scoped data would make view-, flow-, or conversation-scoped data be reinitialized to default on every single (Ajax) postback, causing possibly non-working forms. Abusing a @ViewScoped, @FlowScoped, or @ConversationScoped bean for request-, session-, or application-scoped data, and abusing a @SessionScoped bean for application-scoped data doesn’t affect the end user, but it unnecessarily occupies server memory and is plain inefficient.

Note that the scope should rather not be chosen based on performance implications, unless you really have a low memory footprint and want to go completely stateless. You’d then need to exclusively use stateless forms with @RequestScoped beans and fiddle with request parameters to maintain any client’s state. In other words, you would possibly need to reinvent whatever already is being done by the javax.faces.ViewState hidden input field.

Where Is @FlashScoped?

At last, JSF also supports the flash scope. It is backed by a short living cookie which is associated with a data entry in the session scope. Before the redirect, a cookie will be set on the HTTP response with a value which is uniquely associated with the data entry in the session scope. After the redirect, the presence of the flash scope cookie will be checked and the data entry associated with the cookie will be removed from the session scope and be put in the request scope of the redirected request. Finally the cookie will be removed from the HTTP response. This way the redirected request has access to request-scoped data which was been prepared in the initial request.

This is actually not available as a managed bean scope by standard JSF API. In other words, there is no such thing as @FlashScoped. The flash scope is only available as a map via ExternalContext#getFlash() in managed beans and #{flash} in EL. Historically, the flash scope was primarily introduced in order to be able to show a faces message set in the action method in the redirected page. Imagine the use case of saving an edited product in a detail page and redirecting back to the master page.

public String save() {
    FacesContext context = FacesContext.getCurrentInstance();


    try {
        productService.update(product);
        context.addMessage(null, new FacesMessage("Product saved!"));
        return "/products?faces-redrect=true";
    }
    catch (Exception e) {
        context.addMessage(null, new FacesMessage(
            "Cannot save product. Error: " + e.getMessage()));
        return null;
    }
}

The faces message “Product saved!” wouldn’t show up in the <h:messages globalOnly> of the redirected page because faces messages are inherently request scoped (actually, “faces context scoped”). Historically, during the JSF 1.x era, this problem was solved with a phase listener which copies after the render response phase all undisplayed faces messages into the HTTP session and re-adds after the restore view phase any of them back into the faces context. Since the introduction of the flash scope in JSF 2.0, this problem could be solved in an easier way by simply invoking Flash#setKeepMessages() 12.

productService.update(product);
context.addMessage(null, new FacesMessage("Product saved!"));
context.getExternalContext().getFlash().setKeepMessages(true);
return "/products?faces-redrect=true";

This way, the faces messages are before redirect automatically stored in the flash scope and restored after redirect.

The flash scope is not only useful for faces messages. It’s also useful for passing entire objects while redirecting from one view to another view, without needing to pass some object identifier as a request parameter . Following is an example which prepares an entity for the next step without needing to save it in the database first:

@Named @RequestScoped // or @ViewScoped
public class Home {


    private Product product = new Product();

    public String prepareProduct() {
        FacesContext context = FacesContext.getCurrentInstance();
        context.getExternalContext().getFlash().put("product", product);
        return "/next?faces-redirect=true";
    }


    public Product getProduct() {
        return product;
    }
}

Whereby the bean of the next step looks as follows:

@Named @ViewScoped
public class Next implements Serializable {


    @Inject @ManagedProperty("#{flash.product}")
    private Product product;


    public void save() {
        // ...
    }


    public Product getProduct() {
        return product;
    }
}

And the /next.xhtml redirects back to /home.xhtml when the entity is absent in the flash scope.

<f:metadata>
    <f:viewAction action="/home" if="#{empty flash.product}" />
</f:metadata>

Note that this redirect will take place when you open /next.xhtml directly, or when you refresh the page in the web browser. In case you’d like to avoid that, you can instruct the flash scope to keep the entry value in the flash scope by prefixing the entry key with the predefined “keep” key on the #{flash} map.

@Named @RequestScoped
public class Next {


    @Inject @ManagedProperty("#{flash.keep.product}")
    private Product product;


    // ...
}

This way, the lifetime of the flash scope will expand until the end user closes the browser window, or when the application navigates to a different view, or when the underlying HTTP session expires. This way you can even make the managed bean request scoped instead of view scoped and not lose the entity while submitting a form in the /next.xhtml page or even refreshing the page. This is a relatively powerful feature of the flash scope .

Managed bean initialization and destruction

Managed bean instances can be initialized based on injected dependencies in a @PostConstruct annotated method. Managed bean instances can hook on destroy event in a @PreDestroy annotated method.

@Named
public class Bean {


    @PostConstruct
    public void init() {
        // ...
    }


    @PreDestroy
    public void destroy() {
        // ...
    }
}

The method names are not predefined. The method names init() and destroy() are basically taken over from the HttpServlet. You can of course choose your own, such as onload() and cleanup(). It’s useful to know that those annotations are inheritable. In other words, you could put those methods and annotations in an abstract base class.

In the postconstruct method you have the opportunity to perform initialization based on injected dependencies. They are not available in the constructor yet. The bean management facility can only inject the dependencies after having constructed the managed bean instance. It will then immediately invoke the @PostConstruct annotated method. In the pre-destroy method you have the opportunity to perform any necessary cleanup, such as closing resources , deleting files, etc.

Injecting JSF vended types

Backing beans can obviously be injected as demonstrated many times over in the examples above. Next to injecting your own types, a variety of JSF vended types can be injected via CDI as well. These types largely correspond to the implicit EL objects we saw in Table 7-1 in Chapter 7. This is no coincidence. Internally implicit objects in JSF are implemented by so-called Bean<T> instances from CDI. These CDI Bean<T> instances are effectively the factory objects that know how to generate beans, with what type and optional qualifier and/or with what name.

When the name of an implicit object is used in expression language, the CDI EL resolver does a lookup for that object by name, which results in a call to a certain Bean<T> instance. When we’re injecting, the type into which we inject, together with any explicit or implicit qualifiers, forms an alternative key that’s being used for this lookup. Both types of keys will result in the exact same CDI Bean<T> instance being used.

It should be noted that compared to the implicit EL objects mentioned in Table 8-1 a few are missing for CDI-injectable JSF vended types, namely:

  • #{component}

  • #{cc}

  • #{request}

  • #{session}

  • #{application}

Both #{component} and #{cc} resolve to UIComponent which is not injectable, since this would require a special proxy or custom scope that’s narrow enough to resolve the “current” instance of those at the time the injected type is accessed. Since such scope is not available in JSF yet, and there was only a little time and few resources remaining to finish the JSF 2.3 spec, these had been excluded from CDI injection.

The #{request}, #{session}, and #{application}, respectively, representing HttpServletRequest, HttpSession, and ServletContext in a Servlet container have been omitted since these types are not owned by JSF and therefore JSF should not provide CDI injection capabilities for those. The fact that JSF does provide implicit EL objects for those is mostly historical. The only specification that should provide injection for those types is the Servlet API, which owns those types directly.

Table 8-1 shows the JSF vended types that are injectable via CDI.

Table 8-1 Injectable JSF Vended types, All Since 2.3

Injectable JSF type

Resolves to

javax.faces.context.FacesContext

FacesContext#getCurrentInstance(  )

javax.faces.context.ExternalContext

FacesContext#getExternalContext(  )

javax.faces.component.UIViewRoot

FacesContext#getViewRoot(  )

javax.faces.context.Flash

ExternalContext#getFlash(  )

@RequestMap Map<String, Object>

ExternalContext#getRequestMap(  )

@ViewMap Map<String, Object>

UIViewRoot#getViewMap(  )

@FlowMap Map<Object, Object>

FlowHandler#getCurrentFlowScope(  )

@SessionMap Map<String, Object>

ExternalContext#getSessionMap(  )

@ApplicationMap Map<String, Object>

ExternalContext#getApplicationMap(  )

@InitParameterMap Map<String, String>

ExternalContext#getInitParameterMap(  )

@RequestParameterMap Map<String, String>

ExternalContext#getRequestParameterMap(  )

@RequestParameterValuesMap Map<String, String[]>

ExternalContext#getRequestParameterValuesMap(  )

@HeaderMap Map<String, String>

ExternalContext#getRequestHeaderMap(  )

@HeaderValuesMap Map<String, String[]>

ExternalContext#getRequestHeaderValuesMap(  )

@RequestCookieMap Map<String, Cookie>

ExternalContext#getRequestCookieMap(  )

javax.faces.application.ResourceHandler

Application#getResourceHandler(  )

As can be seen from Table 8-1, for objects for which there is only one instance and that instance is vended (owned) by JSF, no qualifier is needed. When it concerns more general types, such as the various maps, a qualifier is needed. All these qualifier annotations are available from the javax.faces.annotation package.13

A caveat is that all of the above types are request scoped, but the time during which they are valid is actually smaller, namely, from shortly after the moment the service() method of the FacesServlet is called until shortly before the moment that method is exited. Care should be taken not to inject and access these types outside that time. It’s expected that a future revision of the JSF spec will address this problem.

The following shows an example of injecting two of the JSF vended types :

@Named @RequestScoped
public class Bean {


    @Inject
    private Flash flash;


    @Inject @RequestParameterMap
    private Map<String, String> requestParameterMap;


    public void someMethod() {
        if (requestParameterMap.containsKey("something")) {
             flash.put("aKey", "aValue");
        }
    }
}

Eager Initialization

Managed beans are by default lazily initialized whenever they are, for the first time, referenced in an EL expression or as an injected dependency. Managed beans can be eagerly initialized on the start of any scope by an observer method which observes the initialization of the scope of interest. One example was previously given in the “@ViewScoped” section. The method pattern is as follows:

public void startup(@Observes @Initialized(XxxScoped.class) S scope) {
    // ...
}

Where XxxScoped.class can be any CDI-compatible scope and the S represents the owner of the scope. For the following scopes that are thus:

  • ApplicationScoped.class – javax.servlet.ServletContext

  • SessionScoped.class – javax.servlet.http.HttpSession

  • ConversationScoped.class – javax.servlet.ServletRequest

  • FlowScoped.class – javax.faces.flow.Flow

  • ViewScoped.class – javax.faces.component.UIViewRoot

  • RequestScoped.class - javax.servlet.ServletRequest

Note that the containing bean must be of at least the same scope in order to have @Observes @Initialized take effect. Eager initialization has for an application-scoped managed bean the advantage that you can configure it as a “startup” bean without needing to reference it in some other bean in order to get it initialized.

@ApplicationScoped
public class Startup {


    public void contextInitialized
        (@Observes @Initialized(ApplicationScoped.class)
            ServletContext context)
    {
        // ...
    }
}

Eager initialization has for a request-scoped bean the advantage that you can if necessary invoke an asynchronous DB query long before the FacesServlet is invoked.

@Named @RequestScoped
public class EagerProducts {


    private Future<List<Product>> list;

    @Inject
    private ProductService productService;


    public void requestInitialized
        (@Observes @Initialized(RequestScoped.class)
            HttpServletRequest request)
    {
        if ("/products.xhtml".equals(request.getServletPath())) {
            list = productService.asyncList();
        }
    }


    public List<Product> getList() {
        try {
            return list.get();
        }
        catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new FacesException(e);
        }
        catch (ExecutionException e) {
            throw new FacesException(e);
        }
    }
}

Where the ProductService looks like this:

@Stateless
public class ProductService {


    @TransactionAttribute(SUPPORTS)
    public List<Product> list() {
        return entityManager
            .createQuery("FROM Product ORDER BY id DESC", Product.class)
            .getResultList();
    }


    @Asynchronous
    public Future<List<Product>> asyncList() {
        return new AsyncResult<>(list());
    }
}

Note particularly the requestInitialized() method which observes the start of any request scope and thus needs to determine the actual path beforehand so that it doesn’t unnecessarily hit the business service. In this specific example, that will only happen once the request hits /products.xhtml. That JSF page can in turn just reference the product list as usual.

<h:dataTable value="#{eagerProducts.list}" var="product">
    ...
</h:dataTable>

When opening this JSF page, the request scoped bean will be initialized before the FacesServlet is invoked and asynchronously fetch the List<Products> from the database. Depending on the server hardware used, the available server resources and all code running between the invocation of the first servlet filter and entering the JSF render response, this approach may give you a time space of 10ms ~ 500ms (or perhaps even more when there’s some inefficient code in the pipeline) to fetch data from DB in a different thread parallel with the HTTP request, and thus a speed improvement equivalent to the time the DB needs to fetch the data (which thus doesn’t need to be done in the same thread as the HTTP request).

Layers

While implementing backing beans , it’s very important to understand the importance of the separation of the JSF backing bean from the JPA entity and the EJB service. In other words, when developing backing beans, you should make sure that your backing beans are as slick as possible and that they delegate as much as possible model properties to JPA entities and business logic to EJB services. You should realize that JPA entities and EJB services should be fully reusable on a completely different front end than JSF, such as JAX-RS or even plain JSP/Servlet.

This thus also means that you should make sure that you don’t directly or indirectly include a JSF-specific dependency in a JPA entity or an EJB service. For example, the following approach is factually wrong:

@Entity
public class Product {


    private String name;
    private String description;


    public static Product of(ProductBacking backingBean) {
        Product product = new Product();
        product.setName(backingBean.getName());
        product.setDescription(backingBean.getDescription());
        return product;
    }


    // ...
}

Here, the JPA entity is tightly coupled to a JSF backing bean. Not only are the entity properties reused in the backing bean, but also the entity has a dependency on the backing bean. It wouldn’t be possible to extract the entity into a JAR module which is reusable across different JSF web applications .

And the following approach is also factually wrong:

@Stateless
public class ProductService {


    @Inject
    private EntityManager entityManager;


    public void create(Product product) {
        entityManager.persist(product);
        FacesContext.getCurrentInstance().addMessage(null,
            new FacesMessage("Product created!"));
    }
}

Here, the EJB pokes the faces context and sets a message there. This would fail with a NullPointerException when the EJB method is being invoked from, e.g., a JAX-RS service or a Servlet, because there’s no instance of the faces context anywhere over there. This UI messaging task is not the responsibility of the back-end code but of the front-end code. In other words, adding a faces message should only happen in the JSF artifact, such as a backing bean.

The correct approach is as follows, as demonstrated previously in the section “Model, View, or Controller?”:

@Named @RequestScoped
public class ProductBacking {


    private Product product = new Product();

    @Inject
    private ProductService productService;


    public void save() {
        productService.create(product);
        FacesContext.getCurrentInstance().addMessage(null,
            new FacesMessage("Product created!"));
    }


    public Product getProduct() {
        return product;
    }
}

Naming Conventions

There is no strict convention specified by JSF itself. I’ve seen the following conventions across various JSF projects:

  • Foo

  • FooBean

  • FooBacking

  • FooBackingBean

  • FooManager

  • FooManagedBean

  • FooController

whereby Foo can in turn represent one of the following:

  • JSF view ID,

    e.g., EditProduct for /edit/product.xhtml

  • JSF view name,

    e.g., Products for /view/products.xhtml

  • JPA entity name,

    e.g., Product for @Entity class Product

  • JSF form ID,

    e.g., EditProduct for <h:form id="editProduct">

First and foremost, names ending with Bean like FooBean, FooBackingBean, and FooManagedBean must be avoided to all extent. The “bean” suffix is superfluous and too ambiguous as practically any class in Java can be marked as a JavaBean. You don’t immediately use “ProductBean” for your JPA entity or “ProductServiceBean” or even “ProductServiceEnterpriseBean” for your EJB service, right? True, #{bean} or #{myBean} or even #{yourBean} to indicate a JSF or CDI managed bean is very often used across generic code examples in blogs, forums, Q&A sites, and even this book. But this is merely done for clarity and simplicity of the code snippets.

That leaves us with Foo, FooBacking, FooManager, and FooController. All are equally acceptable. Personally, I tend to use FooBacking for request-, view-, flow-, and conversation-scoped beans, and FooManager for session- and application-scoped beans. As to the naming convention of Foo part, that generally depends on whether the backing bean is tightly tied to a particular JSF view or a JSF form, or generally reusable across multiple JSF views or forms referring a particular entity.

In any case, this is a pretty subjective item which can hardly be answered objectively with “the One and Correct” answer. It really doesn’t matter that much to me or anyone else what you make of it, as long as you’re consistent with it throughout the entire project .

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.173.78