In our quest for an interim solution, JSTL is constrained by the fact that this solution must work in the context of JSP1.2, without requiring any change to the spec, and that it should integrate seamlessly with JSP.next (where an EL would be supported natively). It is also important to consider the fact that the specification of an expression language is a rather controversial issue that could trigger long debates among the expert group, preventing us from getting anything out in any timely fashion.
Our strategy therefore consists in allowing the easy integration, selection, and use of a variety of expression languages via an Expression Language Integration API, a set of tags, as well as conventions used throughout JSTL. We won't rule on any specific EL immediately. Rather we will allow various implementations of Expression Languages to all play in our sandbox. The hope is that through experimentation, it will be much easier to evaluate the merits of each approach, paving the way for the selection of a single or limited number of Expression Language(s) for the final draft of JSTL.
a. String literal
att="15"
b. rtexprvalue
att="<%= foo.getBar() %>"
c. elexprvalue
att="$foo.bar"
This requirement made a lot of sense for the following reasons
<%= request.getParameter("username") %>
-- and the user 'maliciously' enters text beginning with '$' in order to establish a context for unchecked evaluation of an expression, an application might be coerced into acting in unintentional and unpredicted ways. To be safe, every rtexprvalue that picks up data from user input would need to be wrapped in a routine that escapes a leading '$' if present.
Because of this security concern, it was decided to use a different mechanism to integrate an EL. It consists in using twin tag libraries, as described in the next section.
In an RT tag library, attributes that support expressions support them as 'rtexprvalues'; i.e. as expressions specified in the page's scripting language (and evaluated at runtime). This is exactly how things currently work in tag libraries.
In an EL tag library, attributes that support expressions support them as 'elexprvalues'; i.e. as expressions specified in the JSTL Expression Language (and evaluated at runtime as well). 'rtexprvalues' are not allowed when using an EL tag library. An 'elexprvalue' is a String literal in the syntax of the EL. It is the responsibility of the EL to define the metacharacter(s) used to discriminate expressions from String literals (e.g. use $ at the beginning of an expression).
JSTL therefore provides two sets of URIs, one for tags that accept rtexprvalues, and one for tags that accept elexprvalues. Twin libraries therefore support the same tags with the same syntax, except that one takes rtexprvalues, the other takes elexprvalues.
These twin tag libraries can be accessed in the following way in a JSP page
(using the "core" taglib as an example):
<%@ taglib uri="http://java.sun.com/jstl/core"
prefix="c" %>
<%@ taglib uri="http://java.sun.com/jstl/core-rt"
prefix="c-rt" %>
In our examples, we append the value '-rt' to differentiate the 'rtexprvalue" library from its 'elexprvalue' twin. It is possible to use the two libraries within the same page, although not recommended for clarity and consistency.
Within the same tag, all attribute values specified as expressions will have to be specified either as 'rtexprvalue' or 'elexprvalue' (cannot mix within the same tag), depending on which tag library the tag belongs to.
It is also possible to override the default expression language setting with the <expressionLanguage> action. For example:
<jx:expressionLanguage evaluator="evaluator-class">
<jx:forEach items="{products/@key}">
...
</jx:forEach>
</jx:expressionLanguage>
The scope of the expression language specified by the action <expressionLanguage> is limited to its body. <expressionLanguage> actions can be nested, where nested occurrences shadow their ancestors .
It is illegal to use an expression in a context where no expression evaluator is specified (i.e., no web.xml declaration and no enclosing <expressionLanguage>).
The above rules make it possible to validate the syntax of an elexprvalue at translation time.
If JSTL rules on a single EL, then both the context parameter and the tag will become illegal.
public class ExpressionEvaluatorManager {
/**
* Invokes the
evaluate() method on the
* "active" ExpressionEvaluator.
*/
public static Object
evaluate(String attributeName,
String expression,
Class expectedType,
Tag tag,
PageContext pageContext)
throws
ExpressionException, JspException;
}
As a result of evaluating an expression, two types of Exceptions can be thrown by the ExpressionEvaluator.
Fatal condition that should never be caught by the user code.
An error related to the evaluation of a particular exception, which is not expected to cause further problems when evaluating any other expressions. Tags may catch this if they wish to detect failure of an expression to complete evaluation satisfactorily.
public class ExpressionException extends JspException;
The integration of custom Expression Languages will be possible
during the Early Access phase of JSTL to help us experiment with various
ELs. An Expression Language implementation simply needs to implement interface
ExpressionEvaluator.
Check the details of the JSTL implementation to see if there are any constraints
on the implementation of an ExpressionEvaluator.
[For example, one could impose that the implementation of ExpressionEvaluator
be thread-safe, and that there is no guarantee that a single instance
will be used for all evaluations (if an implementation of an ExpressionEvaluator
wants to store state (such as an expression cache), a static member variable
with proper synchronization should then be used).]
public interface ExpressionEvaluator {
/**
* Translation
time validation of an expression.
* This method
will return a null String if the expression
* is valid; otherwise
an error message.
*/
public String validate(String
attributeName,
String expression);
/**
* Evaluates the
expression at request time.
*/
public Object evaluate(String
attributeName,
String expression,
Class expectedType,
Tag tag,
PageContext pageContext)
throws
ExpressionException, JspException;
}
Assuming a custom action named foo; one could have the following implementation classes:
FooTag
/ \
/
\
FooTagRT FooTagEL
The only code in FooTagRT and FooTagEL are the setter and getter methods for the attributes that support expressions (they cannot be inherited because the properties do not have the same type; String for EL and the "native" type for RT).
FooTagEL also needs to override doStartTag() to evaluate the elexprvalue first, and then call back into the base class. For example:
public void setFoo(String fooEL) throws JspException {
this.fooEL = fooEL;
}
public int doStartTag() throws JspException {
foo = ExpressionEvaluatorManager.evaluate
("foo", fooEL, FooType.class, this, pageContext);
}
return super.doStartTag();
}
It is important to note that the evaluation of the expression must be performed within the doStartTag() method. The lifecycle of a tag is such that the setter method of values that no not change (string literals) may not necessarily be called if the tag is reused by the container. Since an elexprvalue is specified as a string literal, this could cause an elexprvalue to not to be "re-evaluated" if the evaluation were to be performed in the setter method.
Two TLDs must be written. The only differences are:
It supports an initialization parameter (custom-taglibs) to specify the list of custom tag libraries that should be validated for elexprvalues (* to specify all).
For example:
<taglib>
...
<validator>
<validator-class>javax.servlet.jsp.jstl.core.ExpressionEvaluatorTLV</validator-class>
<init-param>
<param-name>custom-taglibs</param-name>
<param-value>*</param-value>
</init-param>
</validator>
...
</taglib>
If the JSTL ends up specifying a single EL, then translation-time validation could be performed within the TagExtraInfoClass by simply calling ExpressionEvaluatorManager.validate() on each elexprvalue.
When a JSP spec comes with native support for an EL (JSP.next), the assumption is that EL expressions would be supported natively only for attributes where rtexprvalue=true.
The twin libraries would behave as follows in a JSP.next environment:
Is it important or not? One may argue that most attributes support rtexprvalues, except for the few cases where the value needs to be known at translation time (in which case elexprvalues cannot be used). For example:
At the same time as JSP.next comes out, the goal would be to have a
new version of the tag library that removes the distinction between RT
and EL. For example: "http://java.sun.com/jsptl-1.0" (no suffix). The TLD
would state a dependency on JSP.next.