Skip to main content

Unified Expression Language for JSP and JSF

March 7, 2006

{cs.r.title}







This article looks at the unified expression language (EL), which has been added to the JavaServer Pages Standard Tag Library (JSTL) specification in order to overcome problems when integrating the JavaServer Pages (JSP) EL with the JavaServer Faces (JSF) EL.

What Is the Expression Language?

The expression language provides a way to simplify expressions in JSP. It is a simple language used for accessing implicit objects and Java classes, and for manipulating collections in an elegant manner. EL provides the ability to use run-time expressions outside of JSP scripting elements.

Why a "Unified" Expression Language?

JavaServer Faces and JavaServer Pages each has its own expression language. The expression language included in JSP provides greater flexibility to the web application developer. But those who are working with JSF have found themselves unsatisfied by the JSP expression language. The reason for the problem is that JSF is used for rendering GUI components, and needs run-time evaluation of expressions. Deferred evaluation means that the technology using the unified EL takes over the responsibility of evaluating the expression from the JSP engine and evaluates the expression at the appropriate time during the page lifecycle. But the JSP EL is designed for immediate evaluation of expressions.

Another problem is that JSF components need a way to invoke methods on server-side objects during various stages of the lifecycle in order to validate data and handle component events. JSP functions are not sufficient because they can only be used to call static methods defined in a Tag Library Descriptor (TLD) file; they cannot be used to dynamically invoke public methods on objects.

For all of these reasons, we need a powerful expression language to work for both JSP and JSF. The new unified EL essentially represents a union of the JSP and JSF expression languages and largely benefits JSF technology. The unified EL has the following features:

  • Deferred evaluation of expressions.
  • Support for expressions that can set values and expressions that can invoke methods.
  • Support for using JSTL iteration tags with deferred expressions.

Evaluation of EL

Evaluation of EL is categorized as immediate evaluation and deferred evaluation. Immediate evaluation means a JSP page evaluates the expression when the page is rendered. With immediate evaluation, all values are always read-only. JSP EL expressions take the form of ${imExpr}. JSP expressions are evaluated immediately.

Deferred evaluation means that the technology using the unified EL takes over the responsibility of evaluating the expression from the JSP engine and evaluates the expression at the appropriate time during the page lifecycle. The EL takes control from the JSP container to evaluate the expression at the appropriate time. JSF EL expressions take the form of #{defExpr}. JSF expressions work in this way.

The following example shows a JSF inputText tag, which represents a text field component into which a user enters a value. The inputText tag's value attribute references an expression that points to the name property of the book bean.

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

For an initial request of the page containing this tag, the JSF implementation evaluates the #{student.name} expression during the "render response" phase of the lifecycle. During this phase, the expression merely accesses the value of quantity from the book bean, as is done in immediate evaluation.

For a postback, the implementation evaluates the expression during the "apply request values," "process validations," and "update model" phases, during which the value is retrieved from the request, validated, and propagated to the book bean.

Value Expressions

The unified EL provides two types of expressions: value expressions and method expressions. Value expressions can be further categorized into rvalue and lvalue expressions. Rvalue expressions are those that can read data, but cannot write it. Lvalue expressions can both read and write data. Expressions that use immediate evaluation syntax are always rvalue expressions. Value expressions that use deferred evaluation syntax can act as both rvalue and lvalue expressions. Consider these two value expressions:

    ${student.name}
    #{student.name}

The first one uses immediate evaluation syntax, whereas the second one uses deferred evaluation syntax. The first expression accesses the quantity property and gets its value, and the value is added to the response and rendered on the page. The same thing happens with the second expression if it is evaluated during an initial request. In this case, both expressions are rvalue expressions.

During a postback, however, the second expression can be used to set the value of the quantity property with user input. In this case, the expression is an lvalue expression. One of the salient features of creating the JSF EL was the need for support of lvalue expressions because of the multi-phase lifecycle. Now, the unified EL also supports these expressions. Lvalue expressions use deferred evaluation syntax because they can be evaluated at different stages in a page's lifecycle, depending on where the expression is used.

Method Expressions

One important feature of the JSF EL is its support for method expressions. These expressions also supported by the unified EL. A JSF component tag uses method expressions to invoke methods that perform some processing for the component that the tag is representing on the page. For the standard components, these methods are necessary for handling events that the components generate and validating component data. Look at the following example:

    <prefix:inputText id="id" value="#{student.id}"
        validator="#{student.validateId}"/>

The validator attribute of the inputText component tag references a method called validateId in the bean called student. The TLD that defines the inputText tag specifies what signature the method referred to by the validator attribute must have. The validateId method is invoked during the process validation phase of the lifecycle.

What Is a Resolver?

When working with expression language, you might wonder how the expressions are resolved by the JSP engine or by JSF. The unified EL specification defines a generic ELResolver class and a set of ELResolver implementations that define how to resolve various kinds of expressions. An ELResolver identifies the expressions and evaluates the Java bean components or collections.

This feature also allows us to write our own resolve mechanism to include our own expression tags. It's no more complicated to write a custom resolver; in fact, it's quite simple.

Writing our own resolver involves the following steps:

  1. Writing the resolver mechanism.
  2. Registering the resolver with the application.
  3. Using the expressions.

Writing ELResolver Implementation

To know how to implement ELResolver, we will look at a resolver implementation called PrintELResolver. This ELResolver references the custom implicit objects PrintImplicitObjects. The custom implicit objects are user-defined objects available in the JSP page. PrintELResolver is an custom implicit object that implements the abstract methods from the generic ELResolver. This object does a lot of work to print a value to the screen. The ELResolver class defines five abstract methods, which are implemented by the custom resolvers. The following are the methods defined by ELResolver:

  • getValue (ELContext context, Object base, Object property)
  • getType (ELContext context, Object base, Object property)
  • isReadOnly (ELContext context, Object base, Object property)
  • setValue (ELContext context, Object base, Object property, Object value)
  • getCommonPropertyType (ELContext context, Object base)
  • getFeatureDescriptors (ELContext context, Object base)

The purpose of the getValue method is to resolve the specified property object on the specified base object and return the result of the resolution. For example, in the expression #{student.name}, student is the base object (a bean, in this case) and name is a property of the student bean. The returned value is the value of the name property.

When the expression "${ Print.Student.name}" is encountered, the following happens:

  1. The getValue method of PrintELResolver is called to resolve the base object, Print, to the PrintImplicitObject instance.
  2. The getValue method is called again to resolve the second part of the expression, Student. It resolves this part of the expression by invoking the fromName method of PrintImplicitObject with the argument Student in order to get the student name.
  3. The fromName method creates a map of the names of the students and associated Student objects.
  4. From the map it creates, fromName finds the student and returns its Student object.
  5. Finally, the standard BeanELResolver implementation (which is part of the unified EL API) is called to resolve the last part of the expression, name, causing the getName method of Student to be called. This method returns the name.

Registering ELResolver

Once you've created your ELResolver, you have to register your resolver with the application. If you are going to be using the resolver in a JSF application, you use its application configuration file (usually called faces-config.xml) to register the resolver. If you are using the resolver with a JSP application that does not use any JSF tags, you use a context listener to register the resolver. If your are using mixture of both JSP and JSF, then you have to register with the application configuration file.

Registering with the Context Listener

If you want to register with JSP, you have to implement the contextInitialized() method from the ServletContextListener and add to the JspApplicationContext. The following contextInitialized method registers the PrintELResolver class:

public void contextInitialized (ServletContextEvent
                                  servletContextEvent) {

    ServletContext context =
        servletContextEvent.getServletContext();

    JspApplicationContext jspContext =
        JspFactory.getDefaultFactory().
           getJspApplicationContext(context);
    jspContext.addELResolver(new PrintELResolver());
    servletContextEvent.
        getServletContext().log("PrintELResolver registered");

}
Registering with JSF Configuration File

To register an EL resolver with a JSF application, you merely need to specify its fully qualified class name with an el-resolver element in the application's configuration file, as shown here:

    <el-resolver>
         fullPathName.PrintELResolver
    </el-resolver>

Backwards Compatibility

Prior to JSP 2.1, the #{} syntax was not reserved. Therefore, there might exist JSP pages based on earlier versions of JSP technology that use the #{ characters where they are not allowed, according to the JSP 2.1 specification. These pages, when used in a JSP 2.1 application, will generate a translation error. The following are the two cases in which the use of #{ will produce an error when the page is translated by a JSP 2.1 container:

  • If #{ is used in template text as a String literal.
  • If #{ is used as a String literal for a tag attribute value when the tag's TLD specifies a jsp-version of 2.1 or greater.

Configure your application to allow the #{} characters as a String literal by adding the deferred-syntax-allowed-as-literal sub-element to the jsp-property-group element and setting it to true:

<jsp-property-group>
  <deferred-syntax-allowed-as-literal>
    true
  </deferred-syntax-allowed-as-literal>
</jsp-property-group>

Configure the page to accept the #{ characters as String literals with the deferredSyntaxAllowedAsLiteral attribute of the page directive:

<%@page ... deferredSyntaxAllowedAsLiteral="true" %>

Conclusion

As you have seen, the unified EL provides more features like a pluggable, extensible resolver machinery, and a way to set data and invoke methods from the page. This should reduce the burdens on JSP developers and provide more flexibility to work in both JSP and JSF environments.

Resources

width="1" height="1" border="0" alt=" " />
Krishna Srinivasan is a software engineer working in Chennai, India.
Related Topics >> JSP   |   Programming   |