JSF backing bean structure (best practices)
I hope that in this post, I can get people's opinions on best practices for the interface between JSF pages and backing beans.
One thing that I never can settle on is the structure of my backing beans. Furthermore, I have never found a good article on the subject.
What properties belong on which backing beans? When is it appropriate to add more properties to a given bean as opposed to creating a new bean and adding the properties onto it? For simple applications, does it make sense to just have a single backing bean for the whole page, considering the complexity involved with injecting one bean into another? Should the backing bean contain any actual business logic, or should it strictly contain data?
Feel free to answer these questions and any others that may come up.
As for reducing coupling between the JSF page and the backing bean, I never allow the JSF page to access any backing bean property's properties. For example, I never allow something such as:
<h:outputText value="#{myBean.anObject.anObjectProperty}" />
I always require something like:
<h:outputText value="#{myBean.theObjectProperty}" />
with a backing bean value of:
public String getTheObjectProperty()
{
return anObject.getAnObjectProperty();
}
When I loop over a collection, I use a wrapper class to avoid drilling down into an object in a data table, for instance.
In general, this approach feels "right" to me. It avoids any coupling between the view and the data. Please correct me if I'm wrong.
You might want to check this out: making distinctions between different kinds of JSF managed beans.
Here is a description of the different bean types, as defined in the above article by Neil Griffin:
- Model Managed-Bean: Normally session scope. This type of managed-bean participates in the "Model" concern of the MVC design pattern. When you see the word "model" -- think DATA. A JSF model-bean should be a POJO that follows the JavaBean design pattern with getters/setters encapsulating properties. The most common use case for a model bean is to be a database entity, or to simply represent a set of rows from the result set of a database query.
- Backing Managed-Bean: Normally request scope. This type of managed-bean participates in the "View" concern of the MVC design pattern. The purpose of a backing-bean is to support UI logic, and has a 1::1 relationship with a JSF view, or a JSF form in a Facelet composition. Although it typically has JavaBean-style properties with associated getters/setters, these are properties of the View -- not of the underlying application data model. JSF backing-beans may also have JSF actionListener and valueChangeListener methods.
- Controller Managed-Bean: Normally request scope. This type of managed-bean participates in the "Controller" concern of the MVC design pattern. The purpose of a controller bean is to execute some kind of business logic and return a navigation outcome to the JSF navigation-handler. JSF controller-beans typically have JSF action methods (and not actionListener methods).
- Support Managed-Bean: Normally session or application scope. This type of bean "supports" one or more views in the "View" concern of the MVC design pattern. The typical use case is supplying an ArrayList to JSF h:selectOneMenu drop-down lists that appear in more than one JSF view. If the data in the dropdown lists is particular to the user, then the bean would be kept in session scope. However, if the data applies to all users (such as a dropdown lists of provinces), then the bean would be kept in application scope, so that it can be cached for all users.
- Utility Managed-Bean: Normally application scope. This type of bean provides some type of "utility" function to one or more JSF views. A good example of this might be a FileUpload bean that can be reused in multiple web applications.
Great question. I suffered a lot with the same dilemma when I moved to JSF. It really depends on your application. I'm from the Java EE world so I would recommend to have as little business logic in your backing beans as possible. If the logic is purely related to the presentation of your page, then it is fine to have it in the backing bean.
I believe one of the (many) strengths of JSF is actually the fact that you can expose domain objects directly on the managed beans. I would therefore strongly recommend the <:outputText value="#{myBean.anObject.anObjectProperty}" />
approach, otherwise you end up making too much work for yourself in manually exposing each property. Furthermore it would be a bit of a mess when inserting or updating data if you encapsulated all the properties. There are situations where a single domain object may not be sufficient. In those cases I prepare a ValueObject before exposing it on the bean.
EDIT: Actually, if you are going to encapsulate every object property that you want to expose, I would recommend that you instead bind UI components to the backing bean and then inject the content directly into the value of the component.
In terms of bean structure the turning point for me was when I forcefully ignored all the stuff I knew about building web applications and started treating it as a GUI application instead. JSF mimics Swing a lot and therefore the best practices for developing Swing applications would mostly also apply to building JSF applications.