Chapter 3. Navigation

The Syntax of Value Expressions

In this section, we discuss the syntax for value expressions in gruesome detail. This section is intended for reference. Feel free to skip it at first reading.

We start with an expression of the form a.b. For now, we will assume that we already know the object to which a refers. If a is an array, a list, or a map, then special rules apply (see "Using Brackets" below). If a is any other object, then b must be the name of a property of a. The exact meaning of a.b depends on whether the expression is used in rvalue mode or lvalue mode.

This terminology is used in the theory of programming languages to denote that an expression on the right-hand side of an assignment is treated differently from an expression on the left-hand side.

Consider the assignment

  left = right;

A compiler generates different code for the left and right expressions. The right expression is evaluated in rvalue mode and yields a value. The left expression is evaluated in lvalue mode and stores a value in a location.

The same phenomenon happens when you use a value expression in a user interface component:

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

When the text field is rendered, the expression user.name is evaluated in rvalue mode, and the getName method is called. During decoding, the same expression is evaluated in lvalue mode and the setName method is called.

In general, the expression a.b in rvalue mode is evaluated by calling the property getter, whereas a.b in lvalue mode calls the property setter.

Using Brackets

Just as in JavaScript, you can use brackets instead of the dot notation. That is, the following three expressions all have the same meaning:

  a.b   a["b"]   a['b']

For example, user.password, user["password"], and user['password'] are equivalent expressions.

Why would anyone write user["password"] when user.password is much easier to type? There are a number of reasons:

  • When you access an array or map, the [] notation is more intuitive.

  • You can use the [] notation with strings that contain periods or dashes for example, msgs["error.password"].

  • The [] notation allows you to dynamically compute a property: a[b.propname].

Tip

Use single quotes in value expressions if you delimit attributes with double quotes: value="#{user['password']}". Alternatively, you can switch single and double quotes: value='#{user["password"]}'.


Map and List Expressions

The value expression language goes beyond bean property access. For example, let m be an object of any class that implements the Map interface. Then m["key"] (or the equivalent m.key) is a binding to the associated value. In rvalue mode, the value

  m.get("key")

is fetched. In lvalue mode, the statement

  m.put("key", right);

is executed. Here, right is the right-hand side value that is assigned to m.key.

You can also access a value of any object of a class that implements the List interface (such as an ArrayList). You specify an integer index for the list position. For example, a[i] (or, if you prefer, a.i) binds the ith element of the list a. Here i can be an integer, or a string that can be converted to an integer. The same rule applies for array types. As always, index values start at zero.

Table 2-3 summarizes these evaluation rules.

Table 2-3. Evaluating the Value Expression a.b
Type of a Type of b lvalue Mode rvalue Mode
null any error null
any null error null
Map any a.put(b, right) a.get(b)
List convertible to int a.set(b, right) a.get(b)
array convertible to int a[b] = right a[b]
bean any call setter of property with name b.toString() call getter of property with name b.toString()


Caution

Unfortunately, value expressions do not work for indexed properties. If p is an indexed property of a bean b, and i is an integer, then b.p[i] does not access the ith value of the property. It is simply a syntax error. This deficiency is inherited from the JSP expression language.


Resolving the Initial Term

Now you know how an expression of the form a.b is resolved. The rules can be applied repetitively to expressions such as a.b.c.d (or, of course, a['b'].c["d"]). We still need to discuss the meaning of the initial term a.

In the examples you have seen so far, the initial term referred to a bean that was configured in the faces-config.xml file or to a message bundle map. Those are indeed the most common situations. But it is also possible to specify other names.

There are a number of predefined objects. Table 2-4 shows the complete list. For example,

  header['User-Agent']

is the value of the User-Agent parameter of the HTTP request that identifies the user's browser.

If the initial term is not one of the predefined objects, the JSF implementation looks for it in the request, session, and application scopes, in that order. Those scopes are map objects that are managed by the servlet container. For example, when you define a managed bean, its name and value are added to the appropriate scope map.

Table 2-4. Predefined Objects in the Value Expression Language
Variable Name Meaning
header A Map of HTTP header parameters, containing only the first value for each name.
headerValues A Map of HTTP header parameters, yielding a String[]array of all values for a given name.
param A Map of HTTP request parameters, containing only the first value for each name.
paramValues A Map of HTTP request parameters, yielding a String[]array of all values for a given name.
cookie A Map of the cookie names and values of the current request.
initParam A Map of the initialization parameters of this web application. Initialization parameters are discussed in Chapter 10.
requestScope A Map of all request scope attributes.
sessionScope A Map of all session scope attributes.
applicationScope A Map of all application scope attributes.
facesContext The FacesContext instance of this request. This class is discussed in Chapter 6.
view The UIViewRoot instance of this request. This class is discussed in Chapter 7.


Finally, if the name is still not found, it is passed to the VariableResolver of the JSF application. The default variable resolver looks up managed-bean elements in a configuration resource, typically the faces-config.xml file.

Consider, for example, the expression

  #{user.password}

The term user is not one of the predefined objects. When it is encountered for the first time, it is not an attribute name in request, session, or application scope.

Therefore, the variable resolver processes the faces-config.xml entry:

  <managed-bean>       <managed-bean-name>user</managed-bean-name>      <managed-bean-class>com.corejsf.UserBean</managed-bean-class>      <managed-bean-scope>session</managed-bean-scope>    </managed-bean>

The variable resolver calls the default constructor of the class com.corejsf.User-Bean. Next, it adds an association to the sessionScope map. Finally, it returns the object as the result of the lookup.

When the term user needs to be resolved again in the same session, it is located in the session scope.

Composite Expressions

You can use a limited set of operators inside value expressions:

  • Arithmetic operators + - * / %. The last two operators have alphabetic variants div and mod.

  • Relational operators < <= > >= == != and their alphabetic variants lt le gt ge eq ne. The first four variants are required for XML safety.

  • Logical operators && || ! and their alphabetic variants and or not. The first variant is required for XML safety.

  • The empty operator. The expression empty a is true if a is null, an array or String of length 0, or a Collection or Map of size 0.

  • The ternary ?: selection operator.

Operator precedence follows the same rules as in Java. The empty operator has the same precedence as the unary - and ! operators.

Generally, you do not want to do a lot of expression computation in web pages that would violate the separation of presentation and business logic. However, occasionally, the presentation layer can benefit from operators. For example, suppose you want to hide a component when the hide property of a bean is true. To hide a component, you set its rendered attribute to false. Inverting the bean value requires the ! (or not) operator:

  <h:inputText rendered="#{!bean.hide}" ... />

Finally, you can concatenate plain strings and value expressions by placing them next to each other. Consider, for example,

  <h:outputText value="#{messages.greeting}, #{user.name}!"/>

The statement concatenates four strings: the string returned from #{messages. greeting}, the string consisting of a comma and a space, the string returned from #{user.name}, and the string consisting of an exclamation mark.

You have now seen all the rules that are applied to resolve value expressions. Of course, in practice, most expressions are of the form #{bean.property}. Just come back to this section when you need to tackle a more complex expression.

Method Expressions

A method expression denotes an object, together with a method that can be applied to it.

For example, here is a typical use of a method expression:

  <h:commandButton action="#{user.checkPassword}"/>

We assume that user is a value of type UserBean and checkPassword is a method of that class. The method expression is a convenient way of describing a method invocation that needs to be carried out at some future time.

When the expression is evaluated, the method is applied to the object.

In our example, the command button component will call user.checkPassword() and pass the returned string to the navigation handler.

Syntax rules for method expressions are similar to those of value expressions. All but the last component are used to determine an object. The last component must be the name of a method that can be applied to that object.

Four component attributes can take a method expression:

  • action (see "Dynamic Navigation" on page 73 of Chapter 3)

  • validator (see "Validating with Bean Methods" on page 259 of Chapter 6)

  • valueChangeListener ("Value Change Events" on page 269 of see Chapter 7)

  • actionListener (see "Action Events" on page 275 of Chapter 7)

The parameter and return types of the method depend on the context in which the method expression is used. For example, an action must be bound to a method with no parameters and return type String, whereas an actionListener is bound to a method with one parameter of type ActionEvent and return type void. The code that invokes the method expression is responsible for supplying parameter values and processing the return value.



Core JavaServerT Faces
Core JavaServer(TM) Faces (2nd Edition)
ISBN: 0131738860
EAN: 2147483647
Year: 2004
Pages: 84

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net