Mastering JavaServer Faces 2.2
上QQ阅读APP看书,第一时间看更新

EL value expressions

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

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.

Referencing a managed bean's properties

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 isXXX).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"]}'/>

Referencing a managed bean's nested properties

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).

Referencing Java SE enumerated types

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

Referencing collections

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"]}

EL implicit objects

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: