UI-Component Sets
Project Documentation

Component Bindings

Introduction

JSF components interact with backing beans. However the lifecycles of these two types of objects are very different; beans may last just a request, or longer (eg a session bean). A component logically may last a number of page views, but physically new instances are created for each request, when the view is "restored".

JSF is designed so that in normal cases views "pull" data from backing beans, "push" data entered by the user into backing beans, and "invoke" event-handler methods on backing beans. In all cases, the dependency is unidirectional: views know about beans, but beans do not know about views. And the coupling is done only via EL strings, not hard references. This means that the lifecycles of the view components and the backing beans they reference are decoupled, and the lifecycle mismatch is not an issue.

However JSF does provide a mechanism for backing beans to access view components in the rare cases where this is necessary: "bindings". Unfortunately the coupling here is done via direct object references, not EL strings. And if a bean then holds on to these references then very bad things can happen if the lifetime of the bean is longer than a request. Just one of the possible problems is the ugly "duplicate component id" error.

Note that "bindings" are not generally a good idea, and should be avoided where possible. In the remainder of this page we assume that you have some very good reason for wanting bindings, and show you how they can be used with non-request-scoped beans.

Problem

In order to avoid the lifecycle mismatch between components and beans, any bean that stores a component binding must be request-scoped.

However what has been recommended in the "Orchestra best practices" is an access-scoped backing bean for a view and an additional (access or manual) conversation-scoped controller for multi-page conversations. The page controller/model now is stateful, which is exactly what we wanted, however when component bindings are needed then they should not be stored on these beans because they are not request-scoped.

Therefore the following construct is bound to fail:

<component binding="#{viewcontrollerbean.bindingattribute}" />          
        
due to the difference in scopes.

There are two possible solutions to this problem.

Solution 1: Spring aop-proxy

Spring in 2.0 has introduced a construct called aop-proxy. This is a special tag which can be embedded into beans which basically does nothing more than to weave a proxy object around an existing object which inherits the scope of the referencing bean. The inner part of the proxy or own bean then can have a scope of its own which can be smaller than the scope of the referencing object.

So how does this help? Lets look again at our example

<component binding="#{viewcontrollerbean.componentbindingmodel.bindingattribute}" />          
        

The accessor path has slightly changed, we have introduced a second bean; a model bean which specifically holds our component bindings.

What happens on the spring configuration side is simply the following:

<bean id="componentbindingmodel" scope="request" class="path.to.our.model.class"/>
<bean id="viewcontrollerbean" scope="conversation.access" ...>
      <property name="componentbindingmodel"
            ref="componentbindingmodel" />
</bean>
        

The associated component binding model class is a class which only holds the components as attributes and provides associated setter and getter methods. The viewcontrollerbean class can then invoke its methods to get access to the bound component instances.

When the viewcontrollerbean object is instantiated, Spring sees that it must inject the bean named "componentbindingmodel" into it. However that bean is marked as an aop:proxy, so what spring injects is just a "proxy" object, not a real componentbindingmodel bean. Whenever the viewcontrollerbean then invokes a method on that proxy object, the proxy looks up bean "componentbindingmodel" in the specified scope (request), then invokes that method on the object it found. This does have a significant performance impact; each method call on the proxy performs the bean lookup again. However it always acts on the "latest" version of that bean, which would not happen if a real reference had been held. At the end of the request, the request-scoped componentbindingmodel object is discarded as normal, and only the proxy "shell" remains. At the next request, a new componentbindingmodel instance is created and added into the request scope, and methods invoked on the proxy will then automatically work against this new object.

Solution 2: A request-scoped facade

Only a few of the methods on the non-request-scoped backing bean will need access to the bound components. Therefore, these methods can be moved into a request-scoped bean. Add the component binding methods to this request-scoped bean too, and inject a reference to the "real" backing bean into it. Alter the view so that EL expressions that need those component bindings to be evaluated point to the request-scoped bean.

Another way of thinking about this is that the "real" backing bean for the page is implemented as request-scoped, and any state it needs to retain is pushed into a "helper" object that is of conversation scope. The request-scoped bean has access to the components without problems.

While either of these solutions means yet another backing-bean class for the view, there is no "spring magic" required.