Jakarta Expression Language

We are working on a fresh, updated Jakarta EE Tutorial. This section hasn’t yet been updated.

This chapter introduces the Expression Language (also referred to as the EL), which provides an important mechanism for enabling the presentation layer (web pages) to communicate with the application logic (managed beans). The EL is used by several Jakarta EE technologies, such as Jakarta Faces technology, Jakarta Server Pages technology, and Dependency Injection for Jakarta EE (CDI). The EL can also be used in stand-alone environments. This chapter only covers the use of the EL in Jakarta EE containers.

Overview of the EL

The EL allows page authors to use simple expressions to dynamically access data from JavaBeans components. For example, the test attribute of the following conditional tag is supplied with an EL expression that compares 0 with the number of items in the session-scoped bean named cart.

<c:if test="${sessionScope.cart.numberOfItems > 0}">
  ...
</c:if>

See Using the EL to Reference Managed Beans for more information on how to use the EL in Jakarta Faces applications.

To summarize, the EL provides a way to use simple expressions to perform the following tasks:

  • Dynamically read application data stored in JavaBeans components, various data structures, and implicit objects

  • Dynamically write data, such as user input into forms, to JavaBeans components

  • Invoke arbitrary static and public methods

  • Dynamically perform arithmetic, boolean, and string operations

  • Dynamically construct collection objects and perform operations on collections

In a Jakarta Faces page, an EL expression can be used either in static text or in the attribute of a custom tag or standard action.

Finally, the EL provides a pluggable API for resolving expressions so that custom resolvers that can handle expressions not already supported by the EL can be implemented.

Immediate and Deferred Evaluation Syntax

The EL supports both immediate and deferred evaluation of expressions. Immediate evaluation means that the expression is evaluated and the result returned as soon as the page is first rendered. Deferred evaluation means that the technology using the expression language can use its own machinery to evaluate the expression sometime later during the page’s lifecycle, whenever it is appropriate to do so.

Those expressions that are evaluated immediately use the ${} syntax. Expressions whose evaluation is deferred use the #{} syntax.

Because of its multiphase lifecycle, Jakarta Faces technology uses mostly deferred evaluation expressions. During the lifecycle, component events are handled, data is validated, and other tasks are performed in a particular order. Therefore, a Jakarta Faces implementation must defer evaluation of expressions until the appropriate point in the lifecycle.

Other technologies using the EL might have different reasons for using deferred expressions.

Immediate Evaluation

All expressions using the ${} syntax are evaluated immediately. These expressions can appear as part of a template (static) text or as the value of a tag attribute that can accept runtime expressions.

The following example shows a tag whose value attribute references an immediate evaluation expression that updates the quantity of books retrieved from the backing bean named catalog:

<h:outputText value="${catalog.bookQuantity}" />

The Jakarta Faces implementation evaluates the expression ${catalog.bookQuantity}, converts it, and passes the returned value to the tag handler. The value is updated on the page.

Deferred Evaluation

Deferred evaluation expressions take the form #{expr} and can be evaluated at other phases of a page lifecycle as defined by whatever technology is using the expression. In the case of Jakarta Faces technology, its controller can evaluate the expression at different phases of the lifecycle, depending on how the expression is being used in the page.

The following example shows a Jakarta Faces h:inputText tag, which represents a field component into which a user enters a value. The h:inputText tag’s value attribute references a deferred evaluation expression that points to the name property of the customer bean:

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

For an initial request of the page containing this tag, the Jakarta Faces implementation evaluates the #{customer.name} expression during the render-response phase of the lifecycle. During this phase, the expression merely accesses the value of name from the customer bean, as is done in immediate evaluation.

For a postback request, the Jakarta Faces implementation evaluates the expression at different phases of the lifecycle, during which the value is retrieved from the request, validated, and propagated to the customer bean.

As shown in this example, deferred evaluation expressions can be

  • Value expressions that can be used to both read and write data

  • Method expressions

Value expressions (both immediate and deferred) and method expressions are explained in the next section.

Value and Method Expressions

The EL defines two kinds of expressions: value expressions and method expressions. Value expressions can be evaluated to yield a value, and method expressions are used to reference a method.

Value Expressions

Value expressions can be further categorized into rvalue and lvalue expressions. An lvalue expression can specify a target, such as an object, a bean property, or elements of a collection, that can be assigned a value. An rvalue expression cannot specify such a target.

All expressions that are evaluated immediately use the ${} delimiters, and although the expression can be an lvalue expression, no assignments will ever happen. Expressions whose evaluation can be deferred use the #{} delimiters and can act as both rvalue and lvalue expressions; if the expression is an lvalue expression, it can be assigned a new value. Consider the following two value expressions:

${customer.name}

#{customer.name}

The former uses immediate evaluation syntax, whereas the latter uses deferred evaluation syntax. The first expression accesses the name property, gets its value, and passes the value to the tag handler. With the second expression, the tag handler can defer the expression evaluation to a later time in the page lifecycle if the technology using this tag allows.

In the case of Jakarta Faces technology, the latter tag’s expression is evaluated immediately during an initial request for the page. During a postback request, this expression can be used to set the value of the name property with user input.

Referencing Objects

A top-level identifier (such as customer in the expression customer.name) can refer to the following objects:

  • Lambda parameters

  • EL variables

  • Managed beans

  • Implicit objects

  • Classes of static fields and methods

To refer to these objects, you write an expression using a variable that is the name of the object. The following expression references a managed bean called customer:

${customer}

You can use a custom EL resolver to alter the way variables are resolved. For instance, you can provide an EL resolver that intercepts objects with the name customer, so that ${customer} returns a value in the EL resolver instead. (Jakarta Faces technology uses an EL resolver to handle managed beans.)

An enum constant is a special case of a static field, and you can reference such a constant directly. For example, consider this enum class:

public enum Suit {hearts, spades, diamonds, clubs}

In the following expression, in which mySuit is an instance of Suit, you can compare suit.hearts to the instance:

${mySuit == suit.hearts}

Referencing Object Properties or Collection Elements

To refer to properties of a bean, static fields or methods of a class, or items of a collection, you use the . or [] notation. The same syntax can be used for attributes of an implicit object, because attributes are placed in a map.

To reference the name property of the customer bean, use either the expression ${customer.name} or the expression ${customer["name"]}. Here, the part inside the brackets is a String literal that is the name of the property to reference. The [] syntax is more general than the . syntax, because the part inside the brackets can be any String expression, not just literals.

You can use double or single quotes for the String literal. You can also combine the [] and . notations, as shown here:

${customer.address["street"]}

You can reference a static field or method using the syntax classname.field, as in the following example:

Boolean.FALSE

The classname is the name of the class without the package name. By default, all the java.lang packages are imported. You can import other packages, classes, and static fields as needed.

If you are accessing an item in an array or list, you must use the [] notation and specify an index in the array or list. The index is an expression that can be converted to int. The following example references the first of the customer orders, assuming that customer.orders is a List:

${customer.orders[1]}

If you are accessing an item in a Map, you must specify the key for the Map. If the key is a String literal, the dot (.) notation can be used. Assuming that customer.orders is a Map with a String key, the following examples reference the item with the key "socks":

${customer.orders["socks"]}

${customer.orders.socks}

Referencing Literals

The EL defines the following literals:

  • Boolean: true and false

  • Integer: As in Java

  • Floating-point: As in Java

  • String: With single and double quotes; " is escaped as \", ' is escaped as \', and \ is escaped as \\

  • Null: null

Here are some examples:

  • ${"literal"}

  • ${true}

  • ${57}

Parameterized Method Calls

The EL offers support for parameterized method calls.

Both the . and [] operators can be used for invoking method calls with parameters, as shown in the following expression syntax:

  • expr-a[expr-b](parameters)

  • expr-a.identifier-b(parameters)

In the first expression syntax, expr-a is evaluated to represent a bean object. The expression expr-b is evaluated and cast to a string that represents a method in the bean represented by expr-a. In the second expression syntax, expr-a is evaluated to represent a bean object, and identifier-b is a string that represents a method in the bean object. The parameters in parentheses are the arguments for the method invocation. Parameters can be zero or more values of expressions, separated by commas.

Parameters are supported for both value expressions and method expressions. In the following example, which is a modified tag from the guessnumber application, a random number is provided as an argument rather than from user input to the method call:

<h:inputText value="#{userNumberBean.userNumber('5')}">

The preceding example uses a value expression.

Consider the following example of a Jakarta Faces component tag that uses a method expression:

<h:commandButton action="#{trader.buy}" value="buy"/>

The EL expression trader.buy calls the trader bean’s buy method. You can modify the tag to pass on a parameter. Here is the revised tag in which a parameter is passed:

<h:commandButton action="#{trader.buy('SOMESTOCK')}" value="buy"/>

In the preceding example, you are passing the string 'SOMESTOCK' (a stock symbol) as a parameter to the buy method.

Where Value Expressions Can Be Used

Value expressions using the ${} delimiters can be used

  • In static text

  • In any standard or custom tag attribute that can accept an expression

The value of an expression in static text is computed and inserted into the current output. Here is an example of an expression embedded in static text:

<some:tag>
    some text ${expr} some text
</some:tag>

A tag attribute can be set in the following ways.

  • With a single expression construct:

    <some:tag value="${expr}"/>
    
    <another:tag value="#{expr}"/>

    These expressions are evaluated, and the result is converted to the attribute’s expected type.

  • With one or more expressions separated or surrounded by text:

    <some:tag value="some${expr}${expr}text${expr}"/>
    
    <another:tag value="some#{expr}#{expr}text#{expr}"/>

    These kinds of expression, called composite expressions, are evaluated from left to right. Each expression embedded in the composite expression is converted to a String and then concatenated with any intervening text. The resulting String is then converted to the attribute’s expected type.

  • With text only:

    <some:tag value="sometext"/>

    The attribute’s String value is converted to the attribute’s expected type.

You can use the string concatenation operator += to create a single expression from what would otherwise be a composite expression. For example, you could change the composite expression

<some:tag value="sometext ${expr} moretext"/>

to

<some:tag value="${sometext += expr += moretext}"/>

All expressions used to set attribute values are evaluated in the context of an expected type. If the result of the expression evaluation does not match the expected type exactly, a type conversion will be performed. For example, the expression ${1.2E4} provided as the value of an attribute of type float will result in the following conversion:

Float.valueOf("1.2E4").floatValue()

Method Expressions

Another feature of the EL is its support of deferred method expressions. A method expression is used to refer to a public method of a bean and has the same syntax as an lvalue expression.

In Jakarta Faces technology, a component tag represents a component on a page. The component tag uses method expressions to specify methods that can be invoked to perform some processing for the component. These methods are necessary for handling events that the components generate and for validating component data, as shown in this example:

<h:form>
    <h:inputText id="name"
                 value="#{customer.name}"
                 validator="#{customer.validateName}"/>
    <h:commandButton id="submit"
                     action="#{customer.submit}" />
</h:form>

The h:inputText tag displays as a field. The validator attribute of this h:inputText tag references a method, called validateName, in the bean, called customer.

Because a method can be invoked during different phases of the lifecycle, method expressions must always use the deferred evaluation syntax.

Like lvalue expressions, method expressions can use the . and the [] operators. For example, #{object.method} is equivalent to #{object["method"]}. The literal inside the [] is converted to String and is used to find the name of the method that matches it.

Method expressions can be used only in tag attributes and only in the following ways:

  • With a single expression construct, where bean refers to a JavaBeans component and method refers to a method of the JavaBeans component:

    <some:tag value="#{bean.method}"/>

    The expression is evaluated to a method expression, which is passed to the tag handler. The method represented by the method expression can then be invoked later.

  • With text only:

    <some:tag value="sometext"/>

    Method expressions support literals primarily to support action attributes in Jakarta Faces technology. When the method referenced by this method expression is invoked, the method returns the String literal, which is then converted to the expected return type, as defined in the tag’s tag library descriptor.

Lambda Expressions

A lambda expression is a value expression with parameters. The syntax is similar to that of the lambda expression in the Java programming language, except that in the EL, the body of the lambda expression is an EL expression.

For basic information on lambda expressions, see https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html.

Lambda expressions are part of Java SE 8

A lambda expression uses the arrow token (->) operator. The identifiers to the left of the operator are called lambda parameters. The body, to the right of the operator, must be an EL expression. The lambda parameters are enclosed in parentheses; the parentheses can be omitted if there is only one parameter. Here are some examples:

x -> x+1
(x, y) -> x + y
() -> 64

A lambda expression behaves like a function. It can be invoked immediately. For example, the following invocation evaluates to 7:

((x, y) -> x + y)(3, 4)

You can use a lambda expression in conjunction with the assignment and semicolon operators. For example, the following code assigns the previous lambda expression to a variable and then invokes it. The result is again 7:

v = (x, y) -> x + y; v(3, 4)

A lambda expression can also be passed as an argument to a method and be invoked in the method. It can also be nested in another lambda expression.

Operations on Collection Objects

The EL supports operations on collection objects: sets, lists, and maps. It allows the dynamic creation of collection objects, which can then be operated on using streams and pipelines.

Like lambda expressions, operations on collection objects are part of Java SE 8.

For example, you can construct a set as follows:

{1,2,3}

You can construct a list as follows; a list can contain various types of items:

[1,2,3]
[1, "two", [three,four]]

You can construct a map by using a colon to define the entries, as follows:

{"one":1, "two":2, "three":3}

You operate on collection objects using method calls to the stream of elements derived from the collection. Some operations return another stream, which allows additional operations. Therefore, you can chain these operations together in a pipeline.

A stream pipeline consists of the following:

  • A source (the Stream object)

  • Any number of intermediate operations that return a stream (for example, filter and map)

  • A terminal operation that does not return a stream (for example, toList())

The stream method obtains a Stream from a java.util.Collection or a Java array. The stream operations do not modify the original collection object.

For example, you might generate a list of titles of history books as follows:

books.stream().filter(b->b.category == "history")
              .map(b->b.title)
              .toList()

The following simpler example returns a sorted version of the original list:

[1,3,5,2].stream().sorted().toList()

Streams and stream operations are documented in the Java SE 8 API documentation, available at https://docs.oracle.com/javase/8/docs/api/. The following subset of operations is supported by the EL:

allMatch

anyMatch

average

count

distinct

filter

findFirst

flatMap

forEach

iterator

limit

map

max

min

noneMatch

peek

reduce

sorted

substream

sum

toArray

toList

See the Expression Language specification at https://jakarta.ee/specifications/expression-language/4.0/ for details on these operations.

Operators

In addition to the . and [] operators discussed in Value and Method Expressions, the EL provides the following operators, which can be used in rvalue expressions only.

  • Arithmetic: +, - (binary), *, / and div, % and mod, - (unary).

  • String concatenation: +=.

  • Logical: and, &&, or, ||, not, !.

  • Relational: ==, eq, !=, ne, <, lt, >, gt, <=, ge, >=, le. Comparisons can be made against other values or against Boolean, string, integer, or floating-point literals.

  • Empty: The empty operator is a prefix operation that can be used to determine whether a value is null or empty.

  • Conditional: A ? B : C. Evaluate B or C, depending on the result of the evaluation of A.

  • Lambda expression: ->, the arrow token.

  • Assignment: =.

  • Semicolon: ;.

The precedence of operators, highest to lowest, left to right, is as follows:

  • [] .

  • () (used to change the precedence of operators)

  • - (unary) not ! empty

  • * / div % mod

  • + - (binary)

  • +=

  • <> <= >= lt gt le ge

  • == != eq ne

  • && and

  • || or

  • ? :

  • ->

  • =

  • ;

Reserved Words

The following words are reserved for the EL and should not be used as identifiers:

and

or

not

eq

ne

lt

gt

le

ge

true

false

null

instanceof

empty

div

mod

Examples of EL Expressions

Example Expressions contains example EL expressions and the result of evaluating them.

Example Expressions
EL Expression Result

${1 > (4/2)}

false

${4.0 >= 3}

true

${100.0 == 100}

true

${(10*10) ne 100}

false

${'a' > 'b'}

false

${'hip' lt 'hit'}

true

${4 > 3}

true

${1.2E4 + 1.4}

12001.4

${3 div 4}

0.75

${10 mod 4}

2

${((x, y) → x + y)(3, 5.5)}

8.5

[1,2,3,4].stream().sum()

10

[1,3,5,2].stream().sorted().toList()

[1, 2, 3, 5]

${!empty param.Add}

False if the request parameter named Add is null or an empty string

${pageContext.request.contextPath}

The context path

${sessionScope.cart.numberOfItems}

The value of the numberOfItems property of the session-scoped attribute named cart

${param['mycom.productId']}

The value of the request parameter named mycom.productId

${header["host"]}

The host

${departments[deptName]}

The value of the entry named deptName in the departments map

${requestScope['jakarta.servlet.forward.servlet_path']}

The value of the request-scoped attribute named jakarta.servlet.forward.servlet_path

#{customer.lName}

Gets the value of the property lName from the customer bean during an initial request; sets the value of lName during a postback

#{customer.calcTotal}

The return value of the method calcTotal of the customer bean

Further Information about the Expression Language

For more information about the Expression Language, see