Java Server Faces 1.2 as a specification has been out for some time now. JSF 2.0 is in the works – probably looking at finalizing in the Spring of 2009. Several implementations of JSF 1.2 are available (MyFaces 1.2, JBoss RichFaces 3.1 & Seam 2.x for example), and a very important one is about to be added: ADF Faces release 11g from Oracle. (ADF 10g was based on the JSF 1.1 specifications). The JSF 1.2 release has a number of interesting new features that are worth knowing about. In this article, I briefly list some of the more important ones I have come across.
Unified EL Expression Language (aligned with JSP 2.1)
The boundaries between various flavors of EL have vanished (by and large at least). This means for example that in JSF pages that use JSP as their vehicle, we can use the JSLT forEach tag to iterate over elements in a collection. Note: ADF has contained the af:forEach tag for quite some time, that gave us the same functionality. In JSF 1.2 we can also use:
<c:forEach var="item" items="#{shoppingCart.items}"> <tr> <td><h:outputText value="#{item.name}" /></td> <td><h:outputText value="#{item.price}" /></td> <td><h:inputText value="#{item.quantity}" /></td> </tr> </c:forEach>
ValueExpression replaces ValueBinding
Instead of class ValueBinding, properties set with EL and EL expressions in general should be evaluated as ValueExpression. Code to programmatically evaluate EL value expressions in JSF 1.2 should look like:
FacesContext ctx = FacesContext.getCurrentInstance(); ELContext elCtx = ctx.getELContext(); Application app = ctx.getApplication(); String bookTitle = (String)app.evaluateValueExpression(elCtx, "#{book.title}" , String.class);
To specify an attribute on a component with a value expression (an EL expression) rather than a straightforward value, the code would be something like:
FacesContext context = FacesContext.getCurrentInstance(); ValueExpression vex = context.getApplication().getExpressionFactory().createValueExpression(context.getELContext(), "#{book.title}", String.class); // set the label attribute on myComponent: myComponent.setValueExpression("label", vex); // to get access to the value the expression #{book.title} evaluates to, you could write it out: System.out.println("Book Title is "+ vex.getValue(context.getELContext()); // to set the value of the value expression, do: vex.setValue( context.getELContext(), "The Oracle 11g SOA Suite Handbook");
Note that code referring to ValueBinding will still run, but will compile with deprecated warnings.
MethodExpression replaces MethodBinding
Just like ValueExpression takes the place of ValueBinding, replaces MethodExpression the MethodBinding. We use MethodExpression in similar way as ValueExpression. Code to set the action attribute on an Action Component with a MethodExpression looks like this:
FacesContext context = FacesContext.getCurrentInstance(); MethodExpression mex = context.getApplication().getExpressionFactory().createMethodExpression(context.getELContext(), "#{library.borrow}", String.class, new Class[] {}); myComponent.setActionExpression(methodEx );
To invoke MethodExpressions programmatically, use code like this:
FacesContext context = FacesContext.getCurrentInstance(); ELContext elCtx = context.getELContext(); MethodExpression mex = context.getApplication().getExpressionFactory().createMethodExpression(context.getELContext(), "#{library.countBooks}", Integer.class, new Class[] {String.class, String.class}); try { Integer count = mex.invoke( elCtx, new Object[] {"John Grisham","en"}); } catch (ELException ele) { // handle exception } myComponent.setActionExpression(methodEx );
Converters have binding attribute to dynamically evaluate which converter to use
The Converter tag has a binding attribute, that takes a ValueExpression that evaluates to a Converter. Thus, we can have the application dynamically decide which converter logic to apply, based on whatever the EL expression specifies.
ValueChangeListeners and ActionListeners can be managed beans instead of on the fly instantiated classes
One annoying fact with ActionListeners used to be that while the actionListener attribute, available on components such as CommandLink, could refer to a specific method on a specific managed bean, ActionListeners could only refer to a class that implements the ActionListener interface. Such a class would be instantiated on the fly – without specific context, references to bean values etc. In JSF 1.2, the ActionListener component has a binding attribute that is set to a ValueExpression that evaluates to an ActionListener, or rather an object that implements javax.faces.event.ActionListener. That could be a managed bean that already has context (state and references to other beans).
The same applies to ValueChangeListener: the ValueChangeListener component now has a binding attribute that refers to a bean implementing the ValueChangeListener interface.
Note: if both the type and the binding attribute are specified on the ActionListener or the ValueChangeListener component, an object will be instantiated according to the class indicated by type and subsequently stored in the location specified by binding.
Custom Messages to override validator and converter messages
InputComponents now have attributes requiredMessage, converterMessage, and validatorMessage. These can be used to specify custom messages that override the standard messages associated with the required validator, associated converter or validator. These attributes accept literal values as well as value expressions. Use them like this:
<h:inputText value="#{address.postalCode}" validatorMessage="#{nls.postalCodeLength}" > <f:validateLongRange minimum="6" maximum="6"/> </h:inputText>
Input Components now also have a label attribute (ADF Faces components had them before of course). The label attribute accepts both literal and value expressions. This attribute is used as substitution parameter in standard validator/converter messages, for example the following message is associated with the DATE_ID message identifier of DateTimeConverter:
{2}: "{0}" could not be understood as a date.
When the converter feels the need to display the message, it will substitute {2} with the value of the Label attribute.
Per View PhaseListener
We can define a phaseListener child component for a view component. That means basically that every page can have a different PhaseListener associated with it. The phaseListener component has a binding attribute: a ValueExpression expression that evaluates to an object that implements javax.faces.event.PhaseListener (the same interface used for application level phase listeners defined in faces-config.xml).
The view tag also supports attribute beforePhase and afterPhase. These attributes take Method Expressions that evaluate to a public method that accepts a PhaseEvent and returns void.
Annotations and Managed Beans – Leveraging Java EE 5 Annotations in Managed Beans
JSF Implementations that are running as a part of Java EE 5 must allow managed bean implementations to use the annotations specified in section 14.5 of the Servlet 2.5 Specification to allow the container to inject references to container managed resources into a managed bean instance before it is made accessible to the JSF application. Only beans declared to be in request, session, or application scope are eligble for resource injection.
In addition to the annotations from Section 14.5 of the Servlet 2.5 Specification, JSF implementations running in a Java EE 5 compliant container must support attaching the @PostConstruct and @PreDestroy annotations to aid in awareness of the managedbean lifecycle.
Methods on managed beans declared to be in request, session, or application scope, annotated with @PostConstruct, must be called by the JSF implementation after resource injection is performed (if any) but before the bean is placed into scope.
These methods take no arguments, return void and throw no checked exception. They can be public, private or anything in between.
Per Application Resource Bundle
Using the <resource-bundle> child element of <application> in the faces-config.xml file, we can now specify a resource bundle that is available in all pages of the application as well as in code executed during other life cycle phases than render response.
<application> <resource-bundle> <var>nls</var> <base-name>resources.SpecialBundle</base-name> <locale-config> ... </resource-bundle> ...
With the new resource-bundle element, you can load any number of resource bundles into the entire application. Not only does this new element eliminate the need to add a loadBundle tag to multiple pages, but it also has significant performance benefits because loading a resource bundle is an expensive operation.
The standard JSF alternative for the ADF setActionListener component
One of the very useful components ADF Faces have always made available to us is the setActionListener component. This component allows us to have values copied to EL expressed targets (typically managed bean properties) when an Action Component is activated – for example commandLink, commandButton. It is a tremendously useful mechanism to associated values with an action. The JSF 1.2 specification has adopted this concept as well, though named slightly differently (of course). The JSF counterpart to setActionListener is called setPropertyActionListener. It has properties target and value as opposed to from and to that we have in setActionListener.
The setPropertyActionListener is used like this:
<h:commandButton id="remove" action="#{library.remove}" value="#{nls.DeleteBook}"> <f:setPropertyActionListener target="#{requestScope.book}" value="#{row.book}"/> </h:commandButton>
New method invokeOnComponent() added on UIComponent to address individual rows in table components (aiding AJAX processing)
A new method invokeOnComponent() has been added to UIComponent:
boolean UIComponent.invokeOnComponent(FacesContext faces, String clientId, ContextCallback callback)
This method can be used to get hold of individual components within table, forEach, iterator etc. The method findComponent can be used to find the common UIComponent, but not the individual instances inside the iterating containers. So the specific client identifiers such as container:table:2:firstName and container:tree:2:nodeLabel are not accessible using findComponent. But they are with invokeOnComponent(). Note that using this method takes some getting used to.
A code example based on Jacob Hookom’s blog:
public static final ContextCallback RENDER = new ContextCallback() {
public void invokeContextCallback(FacesContext ctx, UIComponent c) {
c.renderAll(ctx);
}
};
// custom ajax request
String clientId = paramMap.get("renderId");
UIViewRoot root = faces.getViewRoot();
boolean found = root.invokeOnComponent(faces, clientId, RENDER);
if (!found) throw new FacesException(clientId + " not found!");
Here the clientId of the component we should rerender is found in the parameter renderId passed in from the Client. From the View Root, using the new invokeComponent method, we pass the RENDER method as the callback act on the specific clientId (renderId). Even if renderId contains the id of the nth row in a table, something like table:5:firstName, the callback acts on the 6th firstName input element, something we cannot do in JSF 1.1.
Miscellaneous
The structure of the faces-config file is now based on an XSD rather than a DTD.
<faces-config xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd" version="1.2">
The structure of the TLD (Tag Library) for JSP 2.1 is based on an XSD instead of a DTD as was the case with earlier versions of JSP (and JSF). Custom components are configured in a TLD and will now have to follow the XSD based structure.
The View component has a renderKitId attribute, that takes either a string identifying a render kit or an EL ValueExpression that evaluates to string that points at a render kit. By having a page rendered by various render kits, it can be displayed in alternate layout styles (skins).
Resources
JSF 1.2 Specifications (JSR-252) Home Page
Introduction to New features in JSF 1.2
Overview of Unified Expression Language
JSF Extensions at Java.Net
Writing JSF Components (1.1 and 1.2)
Clearing Up JSF 1.2 JSF 1.1 and MyFaces Confusion (by Ed Burns)
New Feature for JSF 1.2 – invokeOnComponent() to address individual elements within table, forEach and other iterations