SeamFramework.orgCommunity Documentation
Seam uses JBoss EL which provides an extension to the standard Unified Expression Language (EL). JBoss EL provides a number of enhancements that increase the expressiveness and power of EL expressions.
Standard EL 2.1 does not allow you to use a method with user defined
parameters — of course, JSF listener methods (e.g. a
valueChangeListener
) take parameters provided by JSF.
Standard EL 2.2,
which is in Java EE 6, allows it now. So you don't have to use JBoss EL enhancements.
You can still use JBoss EL instead of standard EL 2.2 from Java EE 6 by
setting up com.sun.faces.expressionFactory
in web.xml
:
<context-param> <param-name>com.sun.faces.expressionFactory</param-name> <param-value>org.jboss.el.ExpressionFactoryImpl</param-value> </context-param>
JBoss EL and EL 2.2 removed this restriction. For example:
<h:commandButton action="#{hotelBooking.bookHotel(hotel)}" value="Book Hotel"/>
@Name("hotelBooking")
public class HotelBooking
{
public String bookHotel(Hotel hotel)
{
// Book the hotel
}
}
Just as in calls to method from Java, 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.
Any value expression may be used as a parameter:
<h:commandButton
action="#{hotelBooking.bookHotel(hotel.id, user.username)}"
value="Book Hotel"/>
It's important to fully understand how this extension to EL works.
When the page is rendered, the parameter names
are stored (for example, hotel.id
and
user.username
), and evaluated (as value
expressions) when the page is submitted. You can't pass objects as
parameters!
You must ensure that the parameters are available not only when the
page is rendered, but also when it is submittedIf the arguments can
not be resolved when the page is submitted the action method will be
called with null
arguments!
You can also pass literal strings using single quotes:
<h:commandLink action="#{printer.println('Hello world!')}" value="Hello"/>
Unified EL also supports value expressions, used to bind a field to
a backing bean. Value expressions use JavaBean naming conventions
and expect a getter/setter pair. Often JSF expects a value
expression where only retrieval (get) is needed (e.g. the
rendered
attribute). Many objects, however, don't
have appropriately named property accessors or require parameters.
JBoss EL removes this restriction by allowing values to be retrieved using the method syntax. For example:
<h:outputText value="#{person.name}" rendered="#{person.name.length() > 5}" />
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. The following example calls the
productsByColorMethod
with a literal string
argument:
#{controller.productsByColor('blue')}
When using JBoss EL you should keep the following points in mind:
Incompatibility with JSP 2.1 — JBoss EL can't currently be used with JSP 2.1 as the compiler rejects expressions with parameters in. 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.
Use inside iterative components —
Components like <c:forEach />
and
<ui:repeat />
iterate over a List or
array, exposing each item in the list to nested components.
This works great if you are selecting a row using a
<h:commandButton />
or
<h:commandLink />
:
@Factory("items")
public List<Item> getItems() {
return entityManager.createQuery("select ...").getResultList();
}
<h:dataTable value="#{items}" var="item">
<h:column>
<h:commandLink value="Select #{item.name}" action="#{itemSelector.select(item})" />
</h:column>
</h:dataTable>
However if you want to use <s:link />
or <s:button />
you
must expose the items as a
DataModel
, and use a
<dataTable />
(or equivalent from a
component set like <rich:dataTable />
). Neither <s:link />
or
<s:button />
submit the form (and
therefore produce a bookmarkable link) so a "magic" parameter
is needed to recreate the item when the action method is
called. This magic parameter can only be added when a
data table backed by a DataModel
is used.
Calling a MethodExpression
from
Java code — Normally, when a
MethodExpression
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.
JBoss EL supports a limited projection syntax. 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}}}
It is important to note that this syntax cannot be parsed by Facelets or JSP and thus cannot be used in xhtml or JSP files. We anticipate that the projection syntax will change in future versions of JBoss EL.