Technical Article
Web Tier to Go With Java EE 5: Summary of New Features in Java Standard Tag Library (JSTL) 1.2
By Pierre Delisle and Jennifer Ball, February 2006
The first article of the "Web Tier to Go With Java EE 5" series summarizes new features in JavaServer Pages (JSP) 2.1 technology. The maintenance release of the Java Standard Tag Library (JSTL) 1.2 also contributes significantly to the Java EE platform.
First, JSTL is now part of the Java EE 5 platform. This means that you don't need to bundle JSTL with your web applications anymore. If you do have a copy of the JSTL library bundled with your application, the library provided by the container takes precedence.
Second, the goal of the maintenance review of JSTL was to support the alignment work done on the JavaServer Pages (JSP) and JavaServer Faces 1.2 specifications, which the previous article in this series discusses. This article provides an overview of how JSTL 1.2 contributes to the alignment of the web-tier technologies.
Alignment of JSTL Iteration Tags With JavaServer Faces Components
In the past, the use of JavaServer Faces components inside the JSTL forEach
tag did not work. For example, consider the following tag:
<c:forEach var="color" items="${colorList}">
<h:inputText value="#{color.name}"/>
</c:forEach>
As you can see, the iteration variable color
is visible only within the boundaries of its iteration tag. This means that on a postback, the JavaServer Faces life cycle has no way to access the value associated with the variable color
.
To solve this issue, the JavaServer Faces input component needs the iteration variable to be a deferred expression that refers to the proper object within the collection over which the tag is iterating. One example of such an object might be colorList[0]
. With this solution, the deferred expression can be evaluated later on during the JavaServer Faces life cycle. Therefore, in JSTL 1.2, the items
attribute of the JSTL iteration tags now supports deferred expressions, as shown in the following example.
<c:forEach var="color" items="
#{colorList}">
<h:inputText value="#{color.name}"/>
</c:forEach>
Understanding how this works will give you some insight into the new unified expression language (EL) provided with JSP 2.1 technology.
As background information, you may want to read the article " Unified Expression Language," which provides a detailed description of the unified EL. In version 1.2, JSTL now defines the attribute items
of forEach
and forTokens
so that they accept both runtime expressions and deferred-value expressions. A runtime expression can be specified using the ${}
EL syntax, whereas a deferred-value expression is specified with the EL's #{}
syntax.
When a runtime expression is specified, it is evaluated immediately. For instance, in the example above, ${colorList}
evaluates to a collection of Color
objects. However, when a deferred-value expression is specified for the items
attribute, the tag handler now adds a mapping for the var
attribute into an EL VariableMapper
instance during each iteration.
The VariableMapper
instance is one of the components that is provided to the EL API when an EL expression is created with the ExpressionFactory.createValueExpression()
API.
Let's take a look at a simplified version of the tag handler implementation of forEach
as it relates to the VariableMapper
instance:
doStartTag()
...
// If items is a deferred value,
// get the current EL VariableMapper.
VariableMapper vm =
jspContext.getELContext().getVariableMapper();
// Create an expression to be assigned to the variable
// specified in the var attribute.
// The index variable is an iteration counter
// kept by the tag handler.
myimpl.IndexedExpression expr =
new myimpl.IndexExpression(getItems(), index);
// Assign the expression to the variable specified
// in the var attribute so that any reference to that
// variable will be replaced by the expression
// in subsequent EL evaluations.
oldMapping = vm.setVariable(getVar(), expr);
...
doEndTag()
...
// Restore the original state of the VariableMapper.
jspContext.getELContext().getVariableMapper()
.setVariable(getVar(), oldMapping);
...
When developing applications with this feature, keep in mind that if the number of items referenced by the items
attribute changes between the rendering of the page and the postback of the page, undefined behavior will result.
set
Tag's Support for Deferred Values In a fashion similar to the iteration tags, the set
standard action now also accepts deferred-value expressions. For example, consider this tag:
<c:setvar="d" value="#{handler.everythingDisabled}"/>
...
<h:inputText id="i1" disabled="#{d}"/>
<h:inputText id="i2" disabled="#{d}"/>
Just as is the case with the iteration tags, when a deferred-value expression is specified for the attribute, the tag handler adds a mapping for the var
attribute into the EL VariableMapper
instance.
Following is a simplified outline of how the tag handler for the set
tag might process a deferred-value expression specified for the value
attribute.
doStartTag()
...
// If value is a deferred value,
// get the current EL VariableMapper instance.
VariableMapper vm = jspContext.getELContext().getVariableMapper();
// Assign the expression to the variable specified
// in the var attribute so that any reference to
// that variable will be replaced by the expression
// in subsequent EL evaluations.
vm.setVariable(getVar(), (ValueExpression)getValue());
...
Conclusion
Although the changes in this maintenance release of JSTL are relatively small, they are essential to the alignment of the JSP and JavaServer Faces technologies. If you have any questions or comments, please write or join us at the forum. Meanwhile, stay tuned for the next article in the series, which introduces the new features of JavaServer Faces technology.