5 min read

(For more resources on JSF, see here.)

JSF 2.0 annotations

One of the most important and useful features of JSF 2.0 consists in annotations. Based on them, JSF 2.0 provides an easy way to accomplish important tasks. In this recipe, we will present the most commonly used annotations and we will see what they can do for us.

How to do it…

If you are a JSF 1.2 fan, then you are familiar with the faces-config.xml configuration file. Starting with JSF 2.0, the content of this descriptor can be partially (sometimes totally) replaced with annotations.

Annotations for managed beans

The most common case is represented by the managed bean, which can be annotated as shown, instead of placing a specific declaration in faces-config.xml:


import javax.faces.bean.ManagedBean;

@ManagedBean
public class MyBean {
...
}

In the previous example, the bean is referenced as myBean, but you may specify another name, as shown next:

@ManagedBean(name="coolBean")

And what is a managed bean without a context (a scope)? JSF 2.0 supports an entire list of scope annotation, as shown next:

Annotation

Annotation Class

@RequestScoped

javax.faces.bean.RequestScoped

@SessionScoped

javax.faces.bean.SessionScoped

@ApplicationScoped

javax.faces.bean.ApplicationScoped

@ViewScoped

javax.faces.bean.ViewScoped

@NoneScoped

javax.faces.bean.NoneScoped

@CustomScoped(value=”#{someMap}”)

javax.faces.bean.CustomScoped

In addition, we can annotate a managed bean’s properties using the @ManagedProperty annotation . The presence of this annotation on a field of a class annotated with @ManagedBean instructs the system to inject a value into this property:

@ManagedProperty("fooval")
private String foo;

@ManagedProperty("#{fooval}")
private String foo;

Going further, you can react to the creation and the destruction of a managed bean, as shown next:

public class MyBean {

@PostConstruct
public void postCreate(){
...
}

@PreDestroy
public void preDestroy(){
...
}

If you use JSF inside of a JEE container you can inject resources, session, message-driven beans, and web services into your managed beans. Something like the following is perfectly legal:

@ManagedBean
@SessionScoped
public class MyBean implements Serializable {

@EJB
private Facade facade;
...

@ResourceDependency annotation

JSF 2.0 specification has added the @ResourceDependency annotation to allow component authors to declare the resources the component will need. For example:

@ResourceDependency(name="my.css",library="libus")
public class MyComponent extends UIComponentBase {
...
}

You may use more than one @ResourceDependency using the @ResourceDependencies annotation, as the following:

@ResourceDependencies({ @ResourceDependency(name="my.
css",library="libus"),
@ResourceDependency(name="my.js",library="libus",target="head")
})
public class MyComponent extends UIComponentBase {
...
}

Now the components can be used without any knowledge about any of the CSS or JS code. The necessary dependencies will be rendered automatically.

The @ListenerFor annotation

A component will be annotated with the @ListenerFor annotation to indicate that it is subscribing to a particular set of events. Therefore, we will have two renderers that act as listeners for particular events and that implement the ComponentSystemEventListener interface (a detailed description of this interface is available at http://blogs.sun.com/ rlubke/entry/jsf_2_0_new_feature1, but as a quick description, system events are new in JSF 2.0, and there are system events that are global and others that are related to a component. They are created at various moments of application or request lifetime).

Let’s see what this looks like:

@ListenerFor(systemEventClass=AfterAddToParentEvent.class,
sourceClass=UIOutput.class)
public class MyRenderer extends Renderer implements
ComponentSystemEventListener {
...
public void processEvent(ComponentSystemEvent event) throws
AbortProcessingException {
UIComponent component = event.getComponent();
FacesContext context = FacesContext.getCurrentInstance();
String target = (String)component.getAttributes().get("target");
if (target != null) {
context.getViewRoot().addComponentResource(context,
component, target);
}
}
...
}

There is also a plural version, named @ListenersFor.

There is one more annotation in which we are interested, named @NamedEvent, which will be discussed in the JSF declarative event handling recipe.

How it works…

Annotations for managed beans

Once you have annotated a class as a managed bean, it can be referred to as a bean with #{beanName.foo}, where beanName is class name (except packages) with the first letter changed to lower case, and “foo” is either an exact method name or a shortcut for a getter and setter method.

Regarding managed beans scopes we have:

@RequestScope: (this is the default scope of a managed bean). This puts the bean in request scope. It makes a new instance for every HTTP request. Commonly, the bean is instantiated twice, once when form is displayed and once when it is submitted.

@SessionScope: This puts a Serializable bean in session scope. When the same user with the same cookie returns then the same bean instance is used (for this, the session timeout should not be expired).

@ApplicationScoped: This puts the bean in application scope. All users will have access to this bean, therefore the bean either should have no state or you must manually and carefully synchronize access to it.

@ViewScoped: This puts the bean in view scoped. The same bean instance is used as long as the same user is on same page (for example, with AJAX).

@CustomScope: This puts the bean in custom scope. The bean is stored in the Map, and the developer can control its lifecycle.

@NoneScope: The bean is not put in a scope. Commonly these beans are referenced by other beans that are in scopes.

@ViewScoped, @CustomScoped and @NoneScoped are available only in JSF 2.0.

@ResourceDependency annotation

Once a component is created, it will be added as a child to another component. Before returning from the add() method, the component will be checked for @ResourceDependency annotations (both versions). When the @ResourceDependency is found a new UIOutput component instance is created. The ResourceHandler is queried for an appropriate Renderer based on the content type of the resource. In our case this is text/css, therefore the style sheet renderer will be used as the Renderer for this UIOutput component.

The values of the name, library (optional), and target (optional) attributes from the annotation are stored in the component’s attribute map. UIViewRoot. addComponentResource() is called passing in the UIOutput and the value of the target attribute from the annotation (if exists).

Now when we render the view, for the head renderer we encode each of the resources that have been targeted for the head, like so:

...
UIViewRoot viewRoot = context.getViewRoot();
for (UIComponent ui_comp:viewRoot.getComponentResources(context,
"head")) {ui_comp.encodeAll(context);}
...

The @ListenerFor annotation

When the Renderer for this component is obtained it is queried for @ListenerFor annotations. For each annotation, the Renderer will be added as a component listener for the corresponding event. Going further, when the component is added in the tree, the event is invoked and the processEvent method will be called for adding the component as a resource to the VewRoot with the corresponding target.

LEAVE A REPLY

Please enter your comment!
Please enter your name here