Java Expression Language (EL) is a compact and powerful mechanism that enables dynamic communication in JSP and JSF-based applications (including development frameworks based on JSF such as PrimeFaces, ICEfaces, and RichFaces); we embed expressions in the presentation layer to communicate with the application logic layer. EL provides bidirectional communication, which means that we can expose application logic data to the user, but we also can submit user data to be processes. Generically speaking, EL can be used to populate HTTP requests with user data, to extract and expose data from HTTP responses, to update HTML DOM, to conditionally process data, and much more.
Note
Commonly, EL expressions will be present in JSP and JSF pages, but they can also appear outside, in faces-config.xml
, for example.
In this chapter, you will see how to use EL in web pages to communicate with managed beans, which is the most common case in JSF applications. We will cover the following topics:
EL syntax, operators, and reserved words
EL immediate and deferred evaluation
EL value and method expressions
The conditional text in JSF
Write a custom EL resolver
In this section, you can see an overview of the main aspects of EL 2.2 and 3.0 syntax. EL supports a handful of operators and reserved words. Each of these are quickly described in the following section (more details are in the EL specification document (http://download.oracle.com/otndocs/jcp/el-3_0-fr-eval-spec/index.html)).
EL supports the following categories of operators—arithmetic, relational, logical, conditional, empty and added starting with EL 3.0, string concatenation, assignment and semicolon operators:
EL evaluates expressions as immediate or deferred.
Immediate evaluation returns the result as soon as the page is first rendered. These kinds of expressions are read-only value expressions and they can be present only in tags that accept runtime expressions. They are easy to recognize after the ${}
notation. Usually, they are used for arithmetic and logical operations in JSP pages.
Deferred evaluation can return the result at different phases of a page's life cycle depending on the technology that is using the expression. JSF can evaluate the expression at different phases of the life cycle (for example, during the rendering and postback phase), depending on how the expression is being used in the page. These kind of expressions can be value and method expressions, and they are marked by the #{}
notation.
Value expressions are probably used the most, and they refer to objects and their properties and attributes. Such expressions are dynamically used to evaluate results or set bean properties at runtime. Through value expressions, you can easily access JavaBeans components, collections, and Java SE enumerated types. Moreover, EL provides a set of implicit objects that can be used to get attributes from different scopes and parameter values. Furthermore, you will see how EL deals with each of these objects.
Note
Value expressions that can read data, but cannot write it are known as rvalue (${}
expressions are always rvalue), while those that can read and write data are known as lvalue (#{}
expressions can be rvalue and/or lvalue).
Referencing a managed bean is not exactly a useful example, but it is a good point to start. Most commonly, your managed bean will look like the following code (in this case, the bean's class name is PlayersBean
):
@ManagedBean //some scope public class PlayersBean{ ... }
Or, in the CDI version, your managed bean will be as follows:
@Named //some scope public class PlayersBean{ ... }
Or, with an explicit name, your managed bean will be as follows:
@ManagedBean(name = "myPlayersBean") //some scope public class PlayersBean{ ... } @Named(value = "myPlayersBean") //some scope public class PlayersBean{ ... }
Now, for the first two examples, EL refers to the PlayersBean
managed bean, like this—the name is obtained from taking the unqualified class name portion of the fully qualified class name and converting the first character to lowercase as follows:
#{playersBean}
In addition, for the next two examples, EL uses the explicit name as follows:
#{myPlayersBean}
Note
You should use CDI beans whenever possible since they are more flexible than JSF managed beans, and because annotations from javax.faces.bean
will be deprecated in a future JSF version. Therefore, the CDI ones are recommended.
When the referenced managed bean cannot be found in any scope, a null
value will be returned.
Tip
Downloading the example code
You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you.
As is commonly known, managed beans usually contain private fields, which are accessible through getter and setter methods as bean properties, and some public methods that exploits these properties to serve different logic tasks.
EL expressions that can access these properties contain the dot or square brackets notation, []
. For example, let's suppose that the PlayersBean
managed bean contains two fields defined like the following lines:
private String playerName = "Rafael"; private String playerSurname = "Nadal";
EL can access these fields through their getter methods; therefore, you need to define them as shown in the following code:
public String getPlayerName() { return playerName; } public String getPlayerSurname() { return playerSurname; }
Now, an expression that accesses the playerName
property can use the dot notation (.
) to refer it, as shown in the following line of code:
#{playersBean.playerName}
Alternatively, this expression can use the square brackets notation, []
, as shown in the following line of code:
#{playersBean['playerName']}
Note
JSF evaluates this expression from left to right. First, it searches for playersBean
in all available scopes (such as request, session, and application). Then, the bean is instantiated and the getPlayerName
/getPlayerSurname
getter methods are called (in the case of Boolean properties, the getter method will be named as is
XXX).When you are using the []
notation, you can use simple or double quotes. Just remember to alternate them correctly in cases like the following quotations.
An incorrect quotation (you cannot use double quotes inside double quotes) is:
<h:outputText value="#{playersBean["playerName"]}"/>
An incorrect quotation (you cannot use simple quotes inside simple quotes) is:
<h:outputText value='#{playersBean['playerName']}'/>
A correct quotation (you can use simple quotes in double quotes) is:
<h:outputText value="#{playersBean['playerName']}"/>
A correct quotation (you can use double quotes in simple quotes) is:
<h:outputText value='#{playersBean["playerName"]}'/>
Usually, managed beans use nested properties. Such properties can be accessed by EL using the .
and []
notations multiple times in the same expression.
For example, the PlayersBean
managed bean may represent general data about tennis players, such as name, surname, titles, and finals. More detailed information, such as birthday, birthplace, height, and weight can be represented through a different class named PlayersDetails
. Now, the PlayersBean
managed bean contains a field of type PlayersDetails
, which means that birthday, birthplace, and so on become nested properties of PlayersBean
. Speaking in code lines, the relevant part of the PlayersDetails
class is as follows:
public class PlayerDetails { private Date birthday; private String birthplace; ... public Date getBirthday() { return birthday; } public String getBirthplace() { return birthplace; } ... }
The managed bean of the PlayersBean
class is as follows:
@Named public class PlayersBean{ private String playerName = "Rafael"; private String playerSurname = "Nadal"; private PlayerDetails playerDetails; public String getPlayerName() { return playerName; } public String getPlayerSurname() { return playerSurname; } public PlayerDetails getPlayerDetails() { return playerDetails; } ... }
You already know how to call the playerName
and playerSurname
properties using the .
and []
notations. Next, you can use the same notations to access the birthday
and birthplace
nested properties, as shown in the following code:
#{playersBean.playerDetails.birthday} #{playersBean.playerDetails.birthplace} #{playersBean['playerDetails']['birthday']} #{playersBean['playerDetails']['birthplace']}
Or, you can use both notations in the same expressions, as shown in the following code:
#{playersBean.playerDetails['birthday']} #{playersBean.playerDetails['birthplace']} #{playersBean['playerDetails'].birthday} #{playersBean['playerDetails'].birthplace}
Of course, the PlayerDetails
class can contain its own nested properties and so. In this case, just use the .
and []
notations to get deeper in the hierarchy of objects until you reach the desired property.
In the preceding expressions, JSF search for playersBean
in all the available scopes (request, session, application, and so on) and obtain an instance of it. Afterwards, it calls the getPlayerDetails
method and the getBirthday
method on result of the getPlayerDetails
method (and the same for the birthplace
property).
EL can access Java SE enumerated types using a String
literal. For example, let's have an enumerated type defined in PlayersBean
, as shown in the following code:
public enum Plays { Left, Right }; private Plays play; ... play = Plays.Left;//initialization can be done in constructor ... public Plays getPlay() { return play; } ...
You can easily output the play
value as shown in the following line of code:
#{playersBean.play}
To refer to the Plays
constant, Plays.Left
, with an expression, use the String
literal Left
(or Right
for Plays.Right
), for example, you can test whether play
is Left
or Right
, as shown in the following code:
#{playersBean.play == 'Left'} //return true #{playersBean.play == 'Right'}//return false
Collection items (arrays, lists, maps, sets, and so on) can be accessed from EL expressions by specifying a literal value that can be converted to an integer or the []
notation with an integer and without quotes.
For example, let's suppose that the PlayersBean
managed bean contains an array named titles_2013
that keeps the titles won by a player in 2013. The array is defined as shown in the following code:
private String[] titles_2013 = {"Sao Paulo", "Acapulco", "ATP World Tour Masters 1000 Indian Wells", "Barcelona", ...}; ... public String[] getTitles_2013() { return titles_2013; }
Now, you can access the first title from the array by specifying its position in array, which is 0
:
#{playersBean.titles_2013[0]}
This is equivalent in Java to getting or setting the value for titles_2013[0]
.
However, sometimes you need to iterate over the array instead of accessing a specific item. This can be easily accomplished with the c:forEach
JSTL tag (http://www.oracle.com/technetwork/java/index-jsp-135995.html). The following code snippet iterates over the titles_2013
array and outputs each item (this is a pretty uncommon usage, so do not try it in production):
<c:forEach begin="0" end="${fn:length(playersBean.titles_2013)-1}" var="i"> #{playersBean.titles_2013[i]}, </c:forEach>
You can simplify it as shown in the following code:
<c:forEach var="title" items="#{playersBean.titles_2013}"> <i>#{title}</i>, </c:forEach>
You can also use the <ui:repeat>
tag as shown in the following code:
<ui:repeat var="title" value="#{playersBean.titles_2013}"> <i>#{title}</i>, </ui:repeat>
This tag is detailed in Chapter 12, Facelets Templating, in the Iterating with <ui:repeat> section.
You can use the same approach for every List
. For example, in the case of List
, the expression #{playersBean.titles_2013[0]}
is equivalent in Java to titles_2013.get(0)
and titles_2013.set(0,
some_value)
.
In the case of collections of type key-value (for example, Map
), the EL expressions obtain items by key. For example, let's add a Map
in PlayersBean
that stores some match facts of a player. It can be defined as shown in the following code:
private Map<String, String> matchfacts = new HashMap<>(); ... matchfacts.put("Aces", "12"); matchfacts.put("Double Faults", "2"); matchfacts.put("1st Serve", "70%"); ... public Map<String, String> getMatchfacts() { return matchfacts; }
Now, an EL expression that accesses the item with the key Aces
can be written like the following line of code:
#{playersBean.matchfacts.Aces}
Note
Notice that this approach is not supported on arrays or lists. For example, #{playersBean.titles_2013.0}
is not correct.
When the key is not an acceptable variable name (for example, Double Faults
), you need to use brackets and quotes, as shown in the following code:
#{playersBean.matchfacts["Double Faults"]}
JSF provides several objects related to the current request and environment. EL exposes these objects (known as implicit objects) that can be accessed at runtime in a Facelet, servlets, or backing bean—these objects are accessible through value expressions and are managed by the container. For each expression, EL first checks if the value of the base is one of these implicit objects, and, if it is not, then it will check beans in progressively wider scopes (from request to view, and finally to application scope).
Note
In EL, the part of the expression before the dot or the square bracket is named base and it usually indicates where the bean instances should be located. The part after the first dot, or the square bracket, is called a property and is recursively cracked in smaller parts, which represents the bean's properties to get from the base.
You can see a short overview of these objects in the following table:
With EL expressions, we can call arbitrary static and public methods that live on the server side in managed beans. Such expressions are usually present in tag's attributes (that is, inside an action
or actionListener
attribute) and must use the deferred evaluation syntax since a method can be called during different phases of the life cycle. Commonly, methods are called to respond with actions to different kinds of events and for autopages navigation.
Let's see some examples of calling bean methods using EL (all methods were defined in the PlayersBean
managed bean):
Calling the
vamosRafa_1
void bean method with no arguments, as shown in the following code:public void vamosRafa_1(){ System.out.println("Vamos Rafa!"); } #{playersBean.vamosRafa_1()}
Calling the
vamosRafa_2
bean method with no arguments. It returns a string, as shown in the following code:public String vamosRafa_2() { return "Vamos Rafa!"; } #{playersBean.vamosRafa_2()}
The returned string,
Vamos Rafa!
, can be displayed on the web page or used for other purposes. In other words, the expression will be evaluated to this string.Calling the
vamosRafa_3
bean method with one argument. It returns void, as shown in the following code:public void vamosRafa_3(String text) { System.out.println(text); } #{playersBean.vamosRafa_3('Vamos Rafa!')}
Notice that the
String
arguments are passed by using quotes.Calling the
vamosRafa_4
bean method with two arguments. It returns a string, as shown in the following code:public String vamosRafa_4(String name, String surname) { return "Vamos " + name + " " + surname + "!"; } #{playersBean.vamosRafa_4(playersBean.playerName, playersBean.playerSurname)}
The expression will be evaluated to the string,
Vamos Rafael Nadal!
.Calling the
vamosRafa_5
bean method for autonavigation. First, define the method in the managed bean to return a view (outcome) name (vamos
is the view name for thevamos.xhtml
file), as shown in the following code:public String vamosRafa_5(){ return "vamos"; }
Furthermore, extract the view name in the action
attribute of any JSF UI component as shown in the following code:
<h:form> <h:commandButton action="#{playersBean.vamosRafa_5()}" value="Vamos ..." /> </h:form>
Now, when the button labeled Vamos... is clicked, JSF will resolve the view name, vamos
, to the vamos.xhtml
file. Moreover, JSF will look for the vamos.xhtml
file in the current directory and will navigate to it. Commonly, these navigation methods are used for conditional navigation between JSF pages.
Note
We have used parentheses to call a method, even when the method doesn't contain arguments. A special case is represented by the methods that contain an ActionEvent
argument. These methods should be called without parentheses, except in the case when you override the ActionEvent
argument altogether by passing and specifying custom argument(s).
EL expressions can also be used inside JavaScript function calls. For example, when you want to pass bean properties to a JavaScript function, you need to place them between quotes, as shown in the following code:
<h:form> <h:commandButton type="button" value="Click Me!" onclick="infoJS('#{playersBean.playerName}', '#{playersBean.playerSurname}')"/> </h:form>
The JavaScript function for this is shown in the following code:
<script type="text/javascript"> function infoJS(name, surname) { alert("Name: " + name + " Surname: " + surname); } </script>
When you need to output the conditional text (without the HTML content), you can use the EL ternary operator, which has the following syntax:
boolean_test ? result_for_true : result_for_false
For example, you can use this operator to select between two CSS classes, as shown in the following code:
.red { color:#cc0000; } .blue { color: #0000cc; }
Now, you want to conditionally output a red or a blue text, as shown in the following code:
<h:outputText styleClass="#{playersBean.play == 'Left' ? 'red': 'blue'}" value="#{playersBean.play}"/>
So, if the value of play
is Left
, the text will be displayed using the red
CSS class, and if it is not Left
, then the blue
class will be used.
Note
Keep in mind that the HTML content is not recommended (for security reasons do not use escape="false"
), and the else
part of the condition cannot be omitted.
For better understanding, let's look at another example. Remember that you have iterated over the titles_2013
array and output each item as shown in the following code:
<c:forEach var="title" items="#{playersBean.titles_2013}"> <i>#{title}</i>, </c:forEach>
Well, the output of this code will be something like the following screenshot:

Everything looks fine except the last comma, which should not appear since the US Open term is the last item to display. You can easily fix this issue with the EL ternary operator, as shown in the following code:
<c:forEach var="title" items="#{playersBean.titles_2013}" varStatus="v"> <i>#{title}</i> #{v.last ? '':','} </c:forEach>
Sometimes you just need to show or hide text based on a condition. For this, you can place a Boolean expression as the value of the rendered
attribute (all JSF UI components have this attribute). For example, the following line of code will output a player's Facebook address only if such an address exists:
<h:outputText value="Facebook address: #{playersBean.facebook}" rendered="#{!empty playersBean.facebook}" />
Another common situation is to display or hide non-HTML text using two buttons of type "Show something..." and "Hide something...". For example, you can have a button labeled Show Career Prize Money and one labeled Hide Career Prize Money. Obviously, you want to display the career prize money when the first button is clicked and to hide the career prize money when the second button is clicked. For this, you can use the rendered
attribute, as shown in the following code:
<h:form id="prizeFormId"> <h:commandButton value="Show Career Prize Money"> <f:ajax render="rnprizeid" listener="#{playersBean.showPrizeMoney()}"/> </h:commandButton> <h:panelGrid id="rnprizeid"> <h:outputText value="#{playersBean.prize}" rendered="#{playersBean.show_prize}"> <f:convertNumber type="currency" currencySymbol="$" /> </h:outputText> </h:panelGrid> <h:commandButton value="Hide Career Prize Money"> <f:ajax render="rnprizeid" listener="#{playersBean.hidePrizeMoney()}"/> </h:commandButton> </h:form>
Both the buttons use AJAX mechanism and an EL method expression to call the showPrizeMoney
and hidePrizeMoney
methods. These methods just modify the value of a boolean
property, named show_prize
, as shown in the following code:
private boolean show_prize = false; ... public boolean isShow_prize() { return show_prize; } ... public void showPrizeMoney(){ this.show_prize = true; } public void hidePrizeMoney(){ this.show_prize = false; }
When the request is complete, JSF will re-render the panel grid component with the ID rnprizeid
; this was indicated in the render
attribute of the f:ajax
tag. As you can see, the re-rendered component is a panel that contains a simple h:outputText
tag that outputs the prize
property depending on the Boolean value of the EL expression present in the rendered
attribute, as shown in the following code:
private int prize = 60941937; ... public int getPrize() { return prize; }
Showing and hiding text can be useful, but not enough. Usually, we need to show or hide the HTML content. For example, you may need to show or hide a picture:
<img src="resources/images/babolat.jpg" width="290" height="174"/>
This task can be easily accomplished by nesting the HTML code inside the Facelets ui:fragment
tag, which supports the rendered
attribute, as shown in the following code:
<ui:fragment rendered="#{playersBean.show_racquet}"> <img src="#{resource['images:babolat.jpg']}" width="290" height="174"/> </ui:fragment>
As you can see, the EL expression of the rendered
attribute indicates a boolean
property of the PlayersBean
managed bean, as shown in the following code:
private boolean show_racquet = false; ... public boolean isShow_racquet() { return show_racquet; }
Now, you can let the user decide when to show or hide the image. You can easily adapt the preceding example, with two buttons labeled Show Image and Hide Image, or more elegant, you can use a checkbox, as shown in the following code:
... <h:form> <h:selectBooleanCheckbox label="Show Image"valueChangeListener="#{playersBean.showHideRacquetPicture}"> <f:ajax render="racquetId"/> </h:selectBooleanCheckbox> <h:panelGroup id="racquetId"> <ui:fragment rendered="#{playersBean.show_racquet}"> <img src="resources/images/babolat.jpg" width="290" height="174"/> </ui:fragment> </h:panelGroup> </h:form> ...
The showHideRacquetPicture
method sets the value of the show_racquet
property to true
or false
, depending on the checkbox status. After this method is executed, JSF will re-render the content of the ui:fragment
tag—this is accomplished via the HTML content rendered by the <h:panelGroup>
tag, because the <ui:fragment>
tag doesn't render the HTML content; therefore, it cannot be referenced by the ID. The following is the code for the showHideRacquetPicture
method:
public void showHideRacquetPicture(ValueChangeEvent e){ if(e.getNewValue() == Boolean.TRUE){ this.show_racquet=true; } else { this.show_racquet=false; } }
So, we can conclude that the rendered
attribute can be used to conditionally output the HTML/non-HTML content. The user interaction and internal conditions can be used to play with this attribute value.
The complete application is named ch1_1
.
EL flexibility can be tested by extending it with custom implicit variables, properties, and method calls. This is possible if we extend the VariableResolver
or PropertyResolver
class, or even better, the ELResolver
class that give us flexibility to reuse the same implementation for different tasks. The following are three simple steps to add custom implicit variables:
Create your own class that extends the
ELResolver
class.Implement the inherited abstract methods.
Add the
ELResolver
class infaces-config.xml
.
Next, you will see how to add a custom implicit variable by extending EL based on these steps. In this example, you want to retrieve a collection that contains the ATP singles rankings using EL directly in your JSF page. The variable name used to access the collection will be atp
.
First, you need to create a class that extends the javax.el.ELResolver
class. This is very simple. The code for the ATPVarResolver
class is as follows:
public class ATPVarResolver extends ELResolver { private static final Logger logger = Logger.getLogger(ATPVarResolver.class.getName()); private static final String PLAYERS = "atp"; private final Class<?> CONTENT = List.class; ... }
Second, you need to implement six abstract methods:
getValue
: This method is defined in the following manner:public abstract Object getValue(ELContext context, Object base, Object property)
This is the most important method of an
ELResolver
class. In the implementation of thegetValue
method, you will return the ATP items if the property requested is namedatp
. Therefore, the implementation will be as follows:@Override public Object getValue(ELContext ctx, Object base, Object property) { logger.log(Level.INFO, "Get Value property : {0}", property); if ((base == null) && property.equals(PLAYERS)) { logger.log(Level.INFO, "Found request {0}", base); ctx.setPropertyResolved(true); List<String> values = ATPSinglesRankings.getSinglesRankings(); return values; } return null; }
getType
: This method is defined in the following manner:public abstract Class<?> getType(ELContext context, Object base,Object property)
This method identifies the most general acceptable type for our property. The scope of this method is to determine if a call of the
setValue
method is safe without causing aClassCastException
to be thrown. Since we return a collection, we can say that the general acceptable type isList
. The implementation of thegetType
method is as follows:@Override public Class<?> getType(ELContext ctx, Object base, Object property) { if (base != null) { return null; } if (property == null) { String message = MessageUtils.getExceptionMessageString(MessageUtils.NULL_PARAMETERS_ERROR_MESSAGE_ID, "property"); throw new PropertyNotFoundException(message); } if ((base == null) && property.equals(PLAYERS)) { ctx.setPropertyResolved(true); return CONTENT; } return null; }
setValue
: This method is defined in the following manner:public abstract void setValue(ELContext context, Object base, Object property, Object value)
This method tries to set the value for a given property and base. For read-only variables, such as
atp
, you need to throw an exception of typePropertyNotWritableException
. The implementation of thesetValue
method is as follows:@Override public void setValue(ELContext ctx, Object base, Object property, Object value) { if (base != null) { return; } ctx.setPropertyResolved(false); if (property == null) { String message = MessageUtils.getExceptionMessageString(MessageUtils.NULL_PARAMETERS_ERROR_MESSAGE_ID, "property"); throw new PropertyNotFoundException(message); } if (PLAYERS.equals(property)) { throw new PropertyNotWritableException((String) property); } }
isReadOnly
: This method is defined in the following manner:public abstract boolean isReadOnly(ELContext context, Object base, Object property)
This method returns
true
if the variable is read-only andfalse
otherwise. Since theatp
variable is read-only, the implementation is obvious. This method is directly related to thesetValue
method, meaning that it signals whether it is safe or not to call thesetValue
method without gettingPropertyNotWritableException
as a response. The implementation of theisReadOnly
method is as follows:@Override public boolean isReadOnly(ELContext ctx, Object base, Object property) { return true; }
getFeatureDescriptors
: This method is defined in the following manner:public abstract Iterator<FeatureDescriptor> getFeatureDescriptors(ELContext context, Object base
This method returns a set of information about the variables or properties that can be resolved (commonly it is used by a design time tool (for example, JDeveloper has such a tool) to allow code completion of expressions). In this case, you can return
null
. The implementation of thegetFeatureDescriptors
method is as follows:@Override public Iterator<FeatureDescriptor> getFeatureDescriptors(ELContext ctx, Object base) { return null; }
getCommonPropertyType
: This method is defined in the following manner:public abstract Class<?> getCommonPropertyType(ELContext context, Object base)
This method returns the most general type that this resolver accepts. The implementation of the
getCommonPropertyType
method is as follows:@Override public Class<?> getCommonPropertyType(ELContext ctx, Object base) { if (base != null) { return null; } return String.class; }
Note
How do you know if the ELResolver
class acts as a VariableResolver
class (these two classes are deprecated in JSF 2.2) or as a PropertyResolver
class? The answer lies in the first part of the expression (known as the base argument), which in our case is null
(the base is before the first dot or the square bracket, while property is after this dot or the square bracket). When the base is null
, the ELresolver
class acts as a VariableResolver
class; otherwise, it acts as a PropertyResolver
class.
The getSinglesRankings
method (that populates the collection) is called from the getValue
method, and is defined in the following ATPSinglesRankings
class:
public class ATPSinglesRankings { public static List<String> getSinglesRankings(){ List<String> atp_ranking= new ArrayList<>(); atp_ranking.add("1 Nadal, Rafael (ESP)"); ... return atp_ranking; } }
Third, you register the custom ELResolver
class in faces-config.xml
using the <el-resolver>
tag and specifying the fully qualified name of the corresponding class. In other words, you add the ELResolver
class in the chain of responsibility, which represents the pattern used by JSF to deal with ELResolvers
:
<application> <el-resolver>book.beans.ATPVarResolver</el-resolver> </application>
Note
Each time an expression needs to be resolved, JSF will call the default expression language resolver implementation. Each value expression is evaluated behind the scenes by the getValue
method. When the <el-resolver>
tag is present, the custom resolver is added in the chain of responsibility. The EL implementation manages a chain of resolver instances for different types of expression elements. For each part of an expression, EL will traverse the chain until it finds a resolver capable to resolve that part. The resolver capable of dealing with that part will pass true
to the setPropertyResolved
method; this method acts as a flag at the ELContext
level.
Furthermore, EL implementation checks, after each resolver call, the value of this flag via the getPropertyResolved
method. When the flag is true
, EL implementation will repeat the process for the next part of the expression.
Done! Next, you can simply output the collection items in a data table, as shown in the following code:
<h:dataTable id="atpTableId" value="#{atp}" var="t"> <h:column> #{t} </h:column> </h:dataTable>
Well, so far so good! Now, our custom EL resolver returns the plain list of ATP rankings. But, what can we do if we need the list items in the reverse order, or to have the items in uppercase, or to obtain a random list? The answer could consist in adapting the preceding EL resolver to this situation.
First, you need to modify the getValue
method. At this moment, it returns List
, but you need to obtain an instance of the ATPSinglesRankings
class. Therefore, modify it as shown in the following code:
public Object getValue(ELContext ctx, Object base, Object property) { if ((base == null) && property.equals(PLAYERS)) { ctx.setPropertyResolved(true); return new ATPSinglesRankings(); } return null; }
Moreover, you need to redefine the CONTENT
constant accordingly as shown in the following line of code:
private final Class<?> CONTENT = ATPSinglesRankings.class;
Next, the ATPSinglesRankings
class can contain a method for each case, as shown in the following code:
public class ATPSinglesRankings { public List<String> getSinglesRankings(){ List<String> atp_ranking= new ArrayList<>(); atp_ranking.add("1 Nadal, Rafael (ESP)"); ... return atp_ranking; } public List<String> getSinglesRankingsReversed(){ List<String> atp_ranking= new ArrayList<>(); atp_ranking.add("5 Del Potro, Juan Martin (ARG)"); atp_ranking.add("4 Murray, Andy (GBR)"); ... return atp_ranking; } public List<String> getSinglesRankingsUpperCase(){ List<String> atp_ranking= new ArrayList<>(); atp_ranking.add("5 Del Potro, Juan Martin (ARG)".toUpperCase()); atp_ranking.add("4 Murray, Andy (GBR)".toUpperCase()); ... return atp_ranking; } ... }
Since the EL resolver returns an instance of the ATPSinglesRankings
class in the getValue
method, you can easily call the getSinglesRankings
, getSinglesRankingsReversed
, and getSinglesRankingsUpperCase
methods directly from your EL expressions, as shown in the following code:
<b>Ordered:</b><br/> <h:dataTable id="atpTableId1" value="#{atp.singlesRankings}"var="t"> <h:column>#{t}</h:column> </h:dataTable> <br/><br/><b>Reversed:</b><br/> <h:dataTable id="atpTableId2" value="#{atp.singlesRankingsReversed}" var="t"> <h:column>#{t}</h:column> </h:dataTable> <br/><br/><b>UpperCase:</b><br/> <h:dataTable id="atpTableId3" value="#{atp.singlesRankingsUpperCase}" var="t"> <h:column>#{t}</h:column> </h:dataTable>
The complete applications to demonstrate custom ELResolvers
are available in the code bundle of this chapter and are named ch1_2
and ch1_3
.
In order to develop the last example of writing a custom resolver, let's imagine the following scenario: we want to access the ELContext
object as an implicit object, by writing #{elContext}
instead of #{facesContext.ELContext}
. For this, we can use the knowledge accumulated from the previous two examples to write the following custom resolver:
public class ELContextResolver extends ELResolver { private static final String EL_CONTEXT_NAME = "elContext"; @Override public Class<?> getCommonPropertyType(ELContext ctx,Object base){ if (base != null) { return null; } return String.class; } @Override public Iterator<FeatureDescriptor> getFeatureDescriptors(ELContext ctx, Object base) { if (base != null) { return null; } ArrayList<FeatureDescriptor> list = new ArrayList<>(1); list.add(Util.getFeatureDescriptor("elContext", "elContext","elContext", false, false, true, ELContext.class, Boolean.TRUE)); return list.iterator(); } @Override public Class<?> getType(ELContext ctx, Object base, Object property) { if (base != null) { return null; } if (property == null) { String message = MessageUtils.getExceptionMessageString(MessageUtils.NULL_PARAMETERS_ERROR_MESSAGE_ID, "property"); throw new PropertyNotFoundException(message); } if ((base == null) && property.equals(EL_CONTEXT_NAME)) { ctx.setPropertyResolved(true); } return null; } @Override public Object getValue(ELContext ctx, Object base, Object property) { if ((base == null) && property.equals(EL_CONTEXT_NAME)) { ctx.setPropertyResolved(true); FacesContext facesContext = FacesContext.getCurrentInstance(); return facesContext.getELContext(); } return null; } @Override public boolean isReadOnly(ELContext ctx, Object base, Object property) { if (base != null) { return false; } if (property == null) { String message = MessageUtils.getExceptionMessageString(MessageUtils.NULL_PARAMETERS_ERROR_MESSAGE_ID, "property"); throw new PropertyNotFoundException(message); } if (EL_CONTEXT_NAME.equals(property)) { ctx.setPropertyResolved(true); return true; } return false; } @Override public void setValue(ELContext ctx, Object base, Object property, Object value) { if (base != null) { return; } ctx.setPropertyResolved(false); if (property == null) { String message = MessageUtils.getExceptionMessageString(MessageUtils.NULL_PARAMETERS_ERROR_MESSAGE_ID, "property"); throw new PropertyNotFoundException(message); } if (EL_CONTEXT_NAME.equals(property)) { throw new PropertyNotWritableException((String) property); } } }
The complete application is named, ch1_6
. The goal of these three examples was to get you familiar with the main steps of writing a custom resolver. In Chapter 3, JSF Scopes – Lifespan and Use in Managed Beans Communication, you will see how to write a custom resolver for a custom scope.
EL 3.0 (JSR 341, part of Java EE 7) represents a major boost of EL 2.2. The main features of EL 3.0 are as follows:
New operators
+
,=
, and;
Lambda expressions
Collection objects support
An API for standalone environments
In the upcoming sections, you will see how to use EL 3.0 features in JSF pages.
In an expression of type, x = y
, the assignment operator (=
), assign the value of y
to x
. In order to avoid an error of the kind PropertyNotWritableException
, the x
value must be an lvalue. The following examples show you how to use this operator in two simple expressions:
#{x = 3}
evaluates to 3#{y = x + 5}
evaluates to 8
The assignment operator is right-associative (z = y = x
is equivalent with z = (y = x)
). For example, #{z = y = x + 4}
evaluates to 7.
In an expression of type, x += y
, the string concatenation operator (+=
) returns the concatenated string of x
and y
. For example:
#{x += y}
evaluates to 37#{0 += 0 +=0 += 1 += 1 += 0 += 0 += 0}
evaluates to 00011000
In EL 2.2, you can do this using the following code:
#{'0'.concat(0).concat(0).concat(1).concat(1).concat(0).concat(0).concat(0)}
In an expression of type, x; y
, x
is first evaluated, and its value is discarded. Next, y
is evaluated and its value is returned. For example, #{x = 5; y = 3; z = x + y}
evaluates to 8.
A lambda expression can be disassembled in three main parts: parameters, the lambda operator (->
), and the function body.
Basically, in Java language, a lambda expression represents a method in an anonymous implementation of a functional interface. In EL, a lambda expression is reduced to an anonymous function that can be passed as an argument to a method.
It is important to not confuse Java 8 lambda expressions with EL lambda expressions, but in order to understand the next examples, it is important to know the fundamentals of Java 8 lambda expressions (http://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html). They don't have the same syntax, but they are similar enough to not cause notable discomfort when we need to switch between them.
An EL lambda expression is a parameterized ValueExpression
object. The body of an EL lambda expression is an EL expression. EL supports several kinds of lambda expressions. The simplest type of EL lambda expressions are immediately invoked, for example:
#{(x->x+1)(3)}
evaluates to 4#{((x,y,z)->x-y*z)(1,7,3)}
evaluates to -20
Further, we have assigned lambda expressions. These are invoked indirectly. For example, #{q = x->x+1; q(3)}
evaluates to 4.
Indirectly, invocation can be used to write functions. For example, we can write a function to calculate n mod m
(without using the %
operator). The following example is evaluated to 3:
#{modulus = (n,m) -> m eq 0 ? 0 : (n lt m ? n: (modulus(n-m, m))); modulus(13,5)}
We can call this function from other expressions. For example, if we want to calculate the greatest common divisor of two numbers, we can exploit the preceding function; the following example is evaluated to 5:
#{gcd = (n,m) -> modulus(n,m) == 0 ? m: (gcd(m, modulus(n,m))); gcd(10, 15)}
Lambda expressions can be passed as arguments to methods. For example, in the following example, you call a method named firstLambdaAction
—the lambda expression is invoked from this method:
#{lambdaBean.firstLambdaAction(modulus = (n,m) -> m eq 0 ? 0 : (n lt m ? n: (modulus(n-m, m))))}
Now, the firstLambdaAction
method is as follows:
public Object firstLambdaAction(LambdaExpression lambdaExpression) { //useful in case of a custom ELContext FacesContext facesContext = FacesContext.getCurrentInstance(); ELContext elContext = facesContext.getELContext(); return lambdaExpression.invoke(elContext, 8, 3); //or simply, default ELContext: //return lambdaExpression.invoke(8, 3); }
Another powerful feature of lambda expressions consists of nested lambda expressions. For example (first, is evaluated the inner expression to 7, afterwards the outer expression to as, 10 - 7): #{(x->x-((x,y)->(x+y))(4,3))(10)}
evaluates to 3.
Do you think EL lambda expressions rocks? Well, get ready for more. The real power is unleashed only when we bring collection objects into equations.
EL 3.0 provides powerful support to manipulate collection objects by applying operations in a pipeline. The methods supporting the collection operations are implemented as ELResolvers
, and lambda expressions are indicated as arguments for these methods.
The main idea behind manipulating collection objects is based on streams. More precisely, the specific operations are accomplished as method calls to the stream of elements obtained from the collection. Many operations return streams, which can be used in other operations that return streams, and so on. In such a case, we can say that we have a chain of streams or a pipeline. The entry in the pipeline is known as the source, and the exit from the pipeline is known as the terminal operation (this operation doesn't return a stream). Between the source and terminal operation, we may have zero or more intermediate operations (all of them return streams).
The pipeline execution begins when the terminal operation starts. Because intermediate operations are lazy evaluated, they don't preserve intermediate results of the operations (an exception is the sorted operation, which needs all the elements to sort tasks).
Now, let's see some examples. We begin by declaring a set, a list, and a map—EL contains syntaxes to construct sets, lists, and maps dynamically as follows:
#{nr_set = {1,2,3,4,5,6,7,8,9,10}} #{nr_list = [1,2,3,4,5,6,7,8,9,10]} #{nr_map = {"one":1,"two":2,"three":3,"four":4,"five":5,"six":6,"seven":7,"eight":8,"nine":9,"ten":10}}
Now, let's go a step further and sort the list in ascending/descending order. For this, we use the stream
, sorted
(this is like the ORDER BY
statement of SQL), and toList
methods (the latter returns a List
that contains the elements of the source stream), as shown in the following code:
#{nr_list.stream().sorted((i,j)->i-j).toList()} #{ nr_list.stream().sorted((i,j)->j-i).toList()}
Further, let's say that we have the following list in a managed bean named LambdaBean
:
List<Integer> costBeforeVAT = Arrays.asList(34, 2200, 1350, 430, 57, 10000, 23, 15222, 1);
Next, we can apply 24 percent of VAT and compute the total for costs higher than 1,000 using the filter
(this is like SQL's WHERE
and GROUP BY
statements), map
(this is like SQL's SELECT
statement), and reduce
(this is like the aggregate functions) methods. These methods are used as follows:
#{(lambdaBean.costBeforeVAT.stream().filter((cost)-> cost gt 1000).map((cost) -> cost + .24*cost)).reduce((sum, cost) -> sum + cost).get()}
These were just a few examples of using collection objects in EL 3.0. A complete application named ch1_4
is available for download in the code bundle of this chapter. Since, in this application you can see more than 70 examples, I recommend you to take a look at it. Moreover, a nice example can be found on Michael Müller's blog at http://blog.mueller-bruehl.de/web-development/using-lambda-expressions-with-jsf-2-2/.
But, what if we want to take advantage of lambda expressions, but we don't like to write such expressions? Well, a solution can be to write parameterized functions based on lambda expressions, and call them in the JSTL style. For example, the following function is capable of extracting a sublist of a List
:
#{get_sublist = (list, left, right)->list.stream().substream(left, right).toList()}
Now, we can call it as shown in the following code:
<ui:repeat value="#{get_sublist(myList, from, to)}" var="t"> #{t} </ui:repeat>
In the complete application, named ch1_5
, you can see a bunch of 21 parameterized functions that can be used with List
s.
In this chapter, we saw that EL 2.2 expressions can be used to dynamically access data (read and write) stored in JavaBeans components, to call arbitrary static and public methods, and to perform arithmetic and logic operations. Finally, we saw that EL allows us to extend its capabilities with custom resolvers. Starting with EL 3.0, we can take advantage of new operators, lambda expressions, and support when working with collection objects.
While reading this book, you will see many examples of EL expressions in real cases. For example, in the next chapter, you will use EL expressions to explore JSF communication capabilities.
See you in the next chapter, where we will discuss JSF communications.