Chapter 30. Expression language enhancements

Seam provides an extension to the standard Unified Expression Language (EL) called JBoss EL. JBoss EL provides a number of enhancements that increase the expressiveness and power of EL expressions.

30.1. Parameterized Method Bindings

Standard EL assumes that any parameters to a method expression will be provided by Java code. This means that a method with parameters cannot be used as a JSF method binding. Seam provides an enhancement to the EL that allows parameters to be included in a method expression itself. This applies to any Seam method expression, including any JSF method binding, for example:

<h:commandButton action="#{hotelBooking.bookHotel(hotel)}" value="Book Hotel"/>

30.1.1. Usage

Parameters are surrounded by parentheses, and separated by commas:

<h:commandButton action="#{hotelBooking.bookHotel(hotel, user)}" value="Book Hotel"/>

The parameters hotel and user will be evaluated as value expressions and passed to the bookHotel() method of the component. This gives you an alternative to the use of @In.

Any value expression may be used as a parameter:

<h:commandButton action="#{hotelBooking.bookHotel(hotel.id, user.username)}" 
                 value="Book Hotel"/>

Note: You can not pass objects as arguments! All that is passed is names, for example, hotel.id and user.username. If you check the rendered code of the previous example, you will see that the command button contains these names. These name arguments will be submitted to the server when you press the button, and Seam will look up and resolve these names (in any available context) before the action method is called. If the arguments can not be resolved at that time (because hotel and user variables can not be found in any available context) the action method will be called with null arguments!

You may however pass literal strings using single or double quotes:

<h:commandLink action="#{printer.println('Hello world!')}" value="Hello"/>
<h:commandLink action="#{printer.println('Hello again')} value="Hello"/>

You might even want to use this notation for all your action methods, even when you don't have parameters to pass. This improves readability by making it clear that the expression is a method expression and not a value expression:

<s:link value="Cancel" action="#{hotelBooking.cancel()}"/>

30.1.2. Limitations

Please be aware of the following limitations:

30.1.2.1. Incompatibility with JSP 2.1

This extension is not currently compatible with JSP 2.1. So if you want to use this extension with JSF 1.2, you will need to use Facelets. The extension works correctly with JSP 2.0.

30.1.2.2. Calling a MethodExpression from Java code

Normally, when a MethodExpression or MethodBinding is created, the parameter types are passed in by JSF. In the case of a method binding, JSF assumes that there are no parameters to pass. With this extension, we can't know the parameter types until after the expression has been evaluated. This has two minor consequences:

  • When you invoke a MethodExpression in Java code, parameters you pass may be ignored. Parameters defined in the expression will take precedence.

  • Ordinarily, it is safe to call methodExpression.getMethodInfo().getParamTypes() at any time. For an expression with parameters, you must first invoke the MethodExpression before calling getParamTypes().

Both of these cases are exceedingly rare and only apply when you want to invoke the MethodExpression by hand in Java code.

30.2. Parameterized Value Bindings

Standard EL only allows access to properties that follow the JavaBean naming conventions. For example, the expression #{person.name} requires a getName() be present. Many objects, however, don't have appropriately named property accessors or require parameters. These values can be retrieved using the method syntax, which work similarly to parameterized method bindings. For example, the following expression returns the size of a string using the length() method.

#{person.name.length()}

You can access the size of a collection in a similar manner.

#{searchResults.size()}

In general any expression of the form #{obj.property} would be identical to the expression #{obj.getProperty()}.

Parameters are also allowed, and they follow the same restrictions as with method bindings. The following example calls the productsByColorMethod with a literal string argument.

#{controller.productsByColor('blue')}

30.3. Projection

JBoss EL supports a limited projection syntax. It is important to note that this syntax cannot be parsed by Facelets or by JavaServer Pages and thus cannot be used in xhtml or JSP files. We anticipate that the projection syntax will change in future versions of JBoss EL.

A projection expression maps a sub-expression across a multi-valued (list, set, etc...) expression. For instance, the expression

#{company.departments}

might return a list of departments. If you only need a list of department names, your only option is to iterate over the list to retrieve the values. JBoss EL allows this with a projection expression.

#{company.departments.{d|d.name}}

The subexpression is enclosed in braces. In this example, the expression d.name is evaluated for each department, using d as an alias to the department object. The result of this expression will be a list of String values.

Any valid expression can be used in an expression, so it would be perfectly valid to write the following, assuming you had a use for the lengths of all the department names in a company.

#{company.departments.{d|d.size()}}

Projections can be nested. The following expression returns the last names of every employee in every department.

#{company.departments.{d|d.employees.{emp|emp.lastName}}}

Nested projections can be slightly tricky, however. The following expression looks like it returns a list of all the employees in all the departments.

#{company.departments.{d|d.employees}}

However, it actually returns a list containing a list of the employees for each individual department. To combine the values, it is necessary to use a slightly longer expression.

#{company.departments.{d|d.employees.{e|e}}}