Notes on JSTL and Expression Language

waisttherapeuticSoftware and s/w Development

Nov 4, 2013 (3 years and 10 months ago)

87 views

Page
1

of
8

Notes on
JSTL and
Expression Language

Created 09/12
/07

Updated 09/1
5/07
, Updated 09
/28
/07
,
Updated 02/02/08
, Updated 02/24/08
, Updated 03/13/08
, Updated 03/21/08

Updated 04/04/08
, Updated 04/13/08
,

Updated 04/24/08
,
Updated 05/02/08
, Updated 05/04/08
, Upda
ted 05/07/08

Updated 05/10/08
, Updated 06/08/08
, Updated 07/13/08
,
Updated 08/02/08
, Updated 08/10
/08
, Updated 08/17/08

Updated 08/30/08
, Updated 09/08/08

Introduction

The JavaServer Pages Standard Tag Library (JSTL) encapsulates as simple tags the core fu
nctionality common to
many Web applications.

It evolved from several different sets during 2000 through 2003.
JSTL has support for
common, structural tasks such as iteration and conditionals, tags for manipulating XML documents,
internationalization tags
, and SQL tags.

It also provides a framework for integrating existing custom tags with JSTL
tags.


The JSTL 1.2 Maintenance Release aligns with the Unified Expression Language (EL) that is being delivered as part
of the JavaServer Pages (JSP) 2.1 specifi
cation.

Than
ks to the Unified EL, JSTL tags

such as the JSTL iteration tags

can now be used with JavaServer Faces c
omponents in an intuitive way.
JSTL 1.2 is part of the Java EE 5 platform.


The
early
downloads for JSTL are standard.jar (385KB), and jst
l.
jar (21KB), along with c.tld. T
hese were released
on 10/24/2004.

As of late 2007, JSTL is packaged into the Standard Java EE 5 libraries, as jstl
-
1.2.jar

Resources

JSTL documentation is at
http://java.sun.com/products/jsp/jstl/reference/docs/index.html
.



JSTL in Action
” by Shawn Bayern.


Manning Press
, July 2002, 480 pages. List price $39.95, Amazon Price
$26.37, used from $26.36. Rated 4.5 stars on Amazon.com. Consider
ed to be a well
-
written book and tutorial.



JavaServer Page
s, 3
rd

edition
”, by

Hans Bergsten, O'Reilly, December
2003, 668 pages. List price $44.95
, Am
azon
Price $28.66,
u
sed from $12.63. Rated 3.5

stars on Amzon.com.

Reviews considered it to not be as

well
-
written as
others,
but
it was

completely revised and updated to cover the JSP 2.0 and JSTL 1.1 specifications.

Apparently most
of the emphasis is on JSTL, so this could be good for us.



Core JSTL:


Mastering the JSP Standard Tag Library
”, by David
Geary, Sun Microsystems Pres
s
/Prentice Hall.
December 2002, 608 pages. List price $49.99, Amazon price $34.95, used from $32.95. Rated 4.5 stars on
Amazon.com.

Clear, concise.

S
olid coverage of a core tec
hnology for web development in J
ava.

This book

is at
the same time a useful reference and an easy tutorial.

Covers the EL scripting language, base, iteration, xml, sql,
networking actions.

Complete, easy to read and wit
h working example code for every

concept
.

David Geary went
on to write the highl
y
-
rated “Core JavaSever Faces” book, which builds heavily on these concepts.

Tags in Web A
pplications

The JSP

Standard Tag Library (JSTL) encapsulates, as simple tags, core functionality common to many JSP
applications. For example, instead of suggesting t
hat you iterate over lists using a scriptlet or different iteration tags
from numerous vendors, JSTL defines a standard tag that works the same everywhere.

This standardization lets you
learn a single tag and use it on multiple JSP containers.


Also, when

tags are standard, containers can recognize them
and optimize their implementations.


JSTL has support for common, structural tasks such as iteration and conditionals, tags for manipulating XML
documents, internationalization and locale
-
sensitive formatt
ing tags, and SQL tags.

It also introduces a new
expression language to simplify page development, and it provides an API for developers to simplify the
configuration of JSTL tags and the development of custom tags that conform to JSTL conventions.


Page
2

of
8

One
of the characteristics of the unified expression language is that it uses the syntax “#{expr}” rather than
“${expr}”. Actually it supports both, but since all of the JSF and later third
-
documents are written with the latter
syntax
, we use it through
-
out t
hese notes.

Basic
Example

At the top of your HTML f
ile, you must add the namespace specifications for the JSTL and
related

libraries you are
going to use. This can be done in two ways. The first is part of the JSP environment:


<%@taglib uri=”
http://java
.sun.com/jstl/core"

prefix=”c” %>


The second is through the outer HTML tag, and is not
dependent

upon JSP:


<html xmlns:c=http://java.sun.com/jstl/core>


. . .

</html>


This provides access to the JSTL 1.2 core tags, which include the “out”, “if”, “forE
ach”. These are

probably

the
most commonly used.


You can use the JSTL tags such as c:out followed by an expression, or with JSP 2.0 you can use the expressions
without the c:out tags.


For instance, the following are equivalent:


<c:out value=
"
#{
pageCou
nt
}
"

/>

#{
pageCount
}


The expression is written in the “JSTL Expression Language”, which allows you to express references to variables
that part of the current environment, and can include information on the page, in the session, and in the application.

M
ore details below.

Iteration Example

The iteration tag can work over any object implementing Collection, or an array.


<c
:forEach var="customer" items="#
{customers}">


<c:out value="#
{customer
.name
}"/><br
/>

</c:forEach>


Displays the values of all custome
r objects.

In this case, the expression language’s facilities for accessing values in
objects are being used.

Conditional Logic Example

<c
:forEach var="customer" items="#
{customers}">


<c:if test="#
{customer.address.country == 'USA'}">


<c:out value="
#
{customer
.name
}"/><br
/
>


</c:if>

</c:forEach>


Only displays the customers if they live in the USA.

In this case, the expression language’s facilities for comparison
and
logic

are being used.

JSTL Expression Language

We start with an expression of the f
orm
a.b
.

For now, we will assume that we already know the object to which
a

refers.

If
a

is an array, a list, or a map, then special rules apply (see "
Using Brackets
" below).

If
a

is any other
Page
3

of
8

object, then
b

must be the name of a property of
a
.

The exa
ct meaning of
a.b

depends on whether the expression is
used in
rvalue mode

or
lvalue mode
.


This terminology is used in the theory of programming languages to denote that an expression on the
right
-
hand side

of an
assignment is treated differently from an
expression on
the
left
-
hand side
.

Consider the assignment


left = right;


A compiler generates different code for the
left

and
right

expressions. The
right

expression is evaluated in
rvalue mode and yields a value. The
left

expression is evaluated in lval
ue mode and stores a value in a location.


The same phenomenon happens when you use a value expression in a user interface component:


<h:inputText value="#{user.name}"/>


When the text field is rendered, the expression
user.name

is evaluated in rvalue mo
de, and the
getName

method is
called.

During decoding, the same expression is evaluated in lvalue mode and the
setName

method is called.


In general, the expression
a.b

in rvalue mode is evaluated by calling the property getter, whereas
a.b

in lvalue
mode

calls the property setter.

Using Brackets

Just as in JavaScript, you can use brackets instead of the dot notation.

That is, the following three expressions all
have the same meaning:


a.b


a["b"]


a['b']


For example,
user.password
,
user["password"]
,

and
user['password']

are equivalent expressions.


Why would anyone write
user["password"]

when
user.password

is much easier to type? There are a number
of reasons:



When you access an array or map, the
[]

notation is more intuitive.



You can use the
[]

notat
ion with strings that contain periods or dashes


for example,
msgs["error.password"].



The
[]

notation allows you to dynamically compute a property:
a[b.propname]
.


Tip


Use single quotes in value expressions if you delimit attributes with double quotes:
v
alue="#{user['password']}"
. Alternatively, you can switch single and double quotes:
value='#{user["password"]}'
.

Map and List Expressions

The value expression language goes beyond bean property access.

For example, let
m

be an object of any class that
im
plements the
Map

interface.

Then
m["key"]

(or the equivalent
m.key
) is a binding to the associated value. In
rvalue mode, the value


m.get("key")


is fetched. In lvalue mode, the statement


m.put("key", right);


is executed.

Here,
right

is the
right
-
ha
nd side

value

that is assigned to
m.key
.

Page
4

of
8


You can also access a value of any object of a class that implements the
List

interface (such as an
ArrayList
).

You specify an integer index for the list position.

For example,
a[i]

(or, if you prefer,
a.i
) binds

the
i
th element
of the list
a
.

Here
i

can be an integer, or a string that can be converted to an integer. The same rule applies for
array types. As always, index values start at zero.

See the table below:


Evaluating the Value Expression
a.b

Type of
a

Type of
b

lvalue Mode

rvalue Mode

null

any

E
rror

null

any

null

E
rror

null

Map

any

a.put(b, right)

a.get(b)

List

convertible to
int

a.set(b, right)

a.get(b)

array

convertible to
int

a[b] = right

a[b]

bean

any

call setter of property with name
b.toStri
ng()

call getter of property with name
b.toString()


Caution


Unfortunately, value expressions do not work for indexed properties. If
p

is an indexed property of a
bean
b
, and
i

is an integer, then
b.p[i]

does not access the
i
th value of the property. It

is simply a
syntax error. This deficiency is inherited from the JSP expression language.

Resolving the Initial Term

Now you know how an expression of the form
a.b

is resolved. The rules can be applied repetitively to expressions
such as
a.b.c.d

(or, of c
ourse,
a['b'].c["d"]
). We still need to discuss the meaning of the initial term
a
.


In the examples you have seen so far, the initial term referred to a bean that was configured in the
faces
-
config.xml

file or to a message bundle map.

Those are indeed the

most common situations.

But it is also possible
to specify other names.


There are a number of predefined objects
, as indicated below.


Predefined Objects in the Value Expression Language

Variable Name

Meaning

header

A
Map

of HTTP header parameters, co
ntaining only the first value for each name.

headerValues

A
Map

of HTTP header parameters, yielding a
String[]
array of all values for a given name.

param

A
Map

of HTTP request parameters, containing only the first value for each name.

paramValues

A
Map

of HTTP request parameters, yielding a
String[]
array of all values for a given name.

cookie

A
Map

of the cookie names and values of the current request.

initParam

A
Map

of the initialization parameters of t
his web application
.

Page
5

of
8

Predefined Objects in the Value Expression Language

Variable Name

Meaning

requestScope

A
Map

of all
request scope attributes.

sessionScope

A
Map

of all session scope attributes.

applicationScope

A
Map

of all application scope attributes.

facesContext

The
FacesContext

instance of this request.

view

The
UIViewRoot

instance of this request.


If the ini
tial term is not one of the predefined objects, the JSF implementation looks for it in the
request
,
session
, and
application scopes
, in that order.

Those scopes are map objects that are managed by the servlet container.

For
example, when you define a man
aged bean, its name and value are added to the appropriate scope map.


Finally, if the name is still not found, it is passed to the
VariableResolver

of the JSF application. The default
variable resolver looks up
managed
-
bean

elements in a configuration res
ource, typically the
faces
-
config.xml

file.


Consider, for example, the expression


#{user.password}


The term
user

is not one of the predefined objects.

When it is encountered for the first time, it is not an attribute
name in request, session, or appli
cation scope.


Therefore, the variable resolver processes the
faces
-
config.xml

entry:


<managed
-
bean>


<managed
-
bean
-
name>user</managed
-
bean
-
name>


<managed
-
bean
-
class>com.corejsf.UserBean</managed
-
bean
-
class>


<managed
-
bean
-
scope>session</ma
naged
-
bean
-
scope>


</managed
-
bean>


The variable resolver calls the default constructor of the class
com.corejsf.User
-
Bean
.

Next, it adds an
association to the
sessionScope

map.

Finally, it returns the object as the result of the lookup.


When the term

user

needs to be resolved again in the same session, it is located in the session scope.

Unfound Identifiers

If a symbol cannot be found, it will have the following effect:



If the symbol is being used simply for a value, the value will be null and there w
ill be no error.



If the symbol is a property that doesn’t exist on a found identifier, the value will be null.



If identifier is being used where a managed bean must be present (because it is being operated on), you will
get a null pointer exception in the
JSF trace.

Composite Expressions

You can use a limited set of operators inside value expressions:




Arithmetic operators
+
-

* / %
.


The last two operators have alphabetic variants
div

and
mod
.



Relational operators
< <= > >= == !=

and their alphabetic varia
nts
lt le gt ge eq ne
.
The first four variants are required for XML safety.

Page
6

of
8



Logical operators
&& || !

and their alphabetic variants
and or not
.

The first variant is required
for XML safety.



The
empty

operator. The expression
empty a

is
true

if
a

is
null
,
an array or
String

of length
0, or a
Collection

or
Map

of size 0.



The ternary
?:

selection operator.


Operator precedence follows the same rules as in Java. The
empty

operator has the same precedence as the unary
-

and
!

operators.


Generally, you do not w
ant to do a lot of expression computation in web pages



that would violate the separation
of presentation and business logic.


However, occasionally, the presentation layer can benefit from operators.

For
example, suppose you want to hide a component whe
n the
hide

property of a bean is true.

To hide a component,
you set its
rendered

attribute to
false
.

Inverting the bean value requires the
!

(or
not
) operator:


<h:inputText rendered="#{!bean.hide}" ... />


Finally, you can concatenate plain strings and

value expressions by placing them next to each other.

Consider, for
example,


<h:outputText value="#{messages.greeting}, #{user.name}!"/>


The statement concatenates four strings: the string returned from
#{messages. greeting}
,

the string consisting
of
a comma and a space, the string returned from
#{user.name}
,

and the string consisting of an exclamation mark.


We have now reviewed all of the
rules that are applied to resolve value expressions.

Of course, in practice, most
expressions are of the form
#
{
bean.property}
.

Also, remember that a non
-
found property doesn’t create an error,
it just returns null.

Method Expressions

A
method expression

denotes an object, together with a method that can be applied to it.


For example, here is a typical use of a me
thod expression:


<h:commandButton action="#{user.checkPassword}"/>


We assume that
user

is a value of type
UserBean

and
checkPassword

is a method of that class. The
method expression is a convenient way of describing a method invocation that needs to be
carried out at some future
time.


When the expression is evaluated, the method is applied to the object.


In our example, the command button component will call
user.checkPassword()

and pass the returned string to
the navigation handler.


Syntax rules for
method expressions are similar to those of value expressions. All but the last component are used to
determine an object. The last component must be the name of a method that can be applied to that object.


Four component attributes can take a method expre
ssion:



action



validator



valueChangeListener



actionListener

The parameter and return types of the method depend on the context in which the method
expression is used.

For example, an
action

must be bound to a method with no parameters and
return type
Strin
g
, whereas an
actionListener

is bound to a method with one parameter of type
Page
7

of
8

ActionEvent

and return type
void
.

The code that invokes the method expression is responsible
for supplying parameter values and processing the return value.

Expression Language E
valuation

Where do the expressions get their values? From the page context:
k
eep in mind that when using an identifier (like
book
, for example)
, it is the same thing as if you had done
PageContext.findAttribute(identifier)
.

The
identifier itself can res
ide in any of the known JSP scopes
, including:




request



page



request



session



application scope


If the identifier isn't found in any scope, then a
null

value is returned.


The most important note about using the JSTL tags is that you can access a bean prop
erty (using a get method), but
you cannot run methods that require arguments. As a way around this, you typically develop custom tags.


In JSF, tags are evaluated in a “deferred” mode. This
means that the technology using t
he unified EL takes over and
ev
aluates

the expression at the appropriate time during the page l
ifecycle. The

EL is called by JSF or Facelets
to
evaluate the expression at the appropriate time.

JSF EL expressions take the form of
#{defExpr}
.


The following example shows a JSF
inputTex
t

tag, which represents a text field component into which a user
enters a value.

The
inputText

tag's
value

attribute references an expression that points to the
name

property of
the
book

bean.

<h:inputText id="name" value="#{student.name}"/>

For an initia
l request of the page containing this tag, the JSF implementation evaluates the
#{student.name}

expression during the "render response" phase of the lifecycle.

During this phase, the expression merely accesses
the value of quantity from the
book

bean, as
is done in immediate evaluation.


For a postback, the implementation evaluates the expression during the "apply request values," "process
validations," and "update model" phases, during which the value is retrieved from the request, validated, and
propagat
ed to the
book

bean.

Programmatic Use of Expression Language

The EL API is located in the class javax.el.*, and documented at
http://java.sun.com/products/jsp/2.1/docs/jsp
-
2_1
-
pfd2
.


E
xpression
language

strings are processed, or compiled,
into an internal representation, which is represented by
instances of javax.el.MethodExpression and javax.el.ValueExpression. Once these objects are made, they can be
passed to JSF components or used
in other parts of the code.


A typical call is:


vb = ef.createValueExpression(elContext,
"#{auction."
+name+
"}"
, Object.
class
);





In this case, the
ef and elContext are

describe
d

below, the second argument is the string, and the third argument is
the cla
ss that is expected as the val
u
e of the expression.



The ExpressionFactory interface supports parsing a
String

into a
ValueExpressio
n

or
MethodExpression

instance for later evaluation.

Page
8

of
8

Classes that implement the EL expression language expose their functionality

via this abstract class. There is no
concrete implementation of this API available in this package. Technologies such as JavaServer Pages and
JavaServer Faces provide access to an implementation via factory methods.

The
createValueExpression(javax.el.ELContext, java.lang.String,
java.lang.Class)

method is used to parse expre
ssions that evaluate to values (both l
-
values and r
-
values are
supported). The
createMethodExpression(javax.el.ELContext, java.lang.String,
java.lang.Class, java.lang.Class[])

method is used to parse expressions that evaluate to a reference
to a method on an object.


The ElContext is used to hold informati
on for expression evaluation.

To evaluate an
Expression
, an
ELContext

must be provided. The
ELContext

holds:



a reference to the base
ELResolver

that will be consulted to resolve model objects and their properties



a reference to
FunctionMapper

that will be used to resolve EL Functions.



a reference to
VariableMapper

that will be used to resolve EL Variables.



a collection of all the relevant context objects for use by
ELResolver
s



state information during the evaluation of an expression, such as whether a property has been resolved
yet

The collection of context objects is necessary because each
ELResolver

may need access to a different context
object. For example, JSP and Faces resolvers need access to a
JspContext

and a
javax.faces.context.FacesContext
, respectively.

Creation of
ELContext

objects is controlled through the underlying technology. For example, in JSP the
JspContext.getELContext()

fact
ory method is used. Some technologies provide the ability to add an
ELContextListener

so that applications and frameworks can
ensure their own context objects are attached to
any newly created
ELContext
.

Because it stores state during expression evaluation, an
ELContext

object is not thread
-
safe. Care should be taken
to never share an
ELContext

instance between two or more thread
s.

In JSF, both the ExpressionFactory and the default ELContext can be

found from the following calls:


FacesContext facesContext = FacesContext.
getCurrentInstance
();



Application app = facesContext.getApplication();

ExpressionFactory ef = app.getE
xpressionFactory();

ELContext elContext = facesContext.getELContext();