Unified Expression Language

By Ryan Lubke,
Jennifer Ball,
and Pierre Delisle, August 2005
   




webtier-samplehttps://javaserverfaces.dev.java.net/samples/webtier-samplehttps://glassfish.dev.java.net/

Contents

Expression Language Beginnings
A Separate EL for JavaServer Faces Technology
Conflicting Expression Language Syntax
Features of the Unified EL
Migrating to the Unified EL
Now, It's Your Turn

Expression Language Beginnings


The unified expression language started out as the JavaServer Pages Standard Tag Library (JSTL), version 1.0 expression language, originally called SPEL (Simplest Possible Expression Language). True to its name, this expression language made life easier for page authors by providing a simple, easy-to-use way to access external data objects. For example, the expression ${customer.name} is used to look up the customer JavaBeans component and call the getName method to retrieve the value of the name property. This value is then rendered into the page.

By using this expression language, page authors could drastically reduce the amount of scripting in their pages, resulting in greater productivity, easier maintenance, and a flatter learning curve in terms of page development. Over the years, the expression language has evolved to include more advanced functionality, while still maintaining its simplicity.



A Separate EL for JavaServer Faces Technology


During the development of JSP 2.0, JavaServer Faces technology was released. The primary feature of this technology is its flexible and extensible UI component model, which includes: a set of classes that define UI components; a mechanism for handling events generated by the components; and a process for converting and validating component data. It also includes a set of component tags that are used to map directly to individual, stateful, server-side UI component objects. Therefore, this technology needed an expression language that could be used to wire events generated by the components to server-side code, bind the components to server-side data objects, and register data validators and converters with the components.

While the expression language included in JSP 2.0 technology offers many advantages to the web application developer, it clearly didn't satisfy all the needs of those developing with JavaServer Faces technology. From the viewpoint of these developers, the primary limitation of the JSP EL is that its expressions are evaluated immediately, meaning that the JSP container immediately parses and resolves the expression when it processes the page and returns a response.

Immediate evaluation is sufficient when a JavaServer Faces page is rendered for the first time. However, after the user enters values into the UI components and submits the page again, those values are converted, validated, and propagated to server-side data objects, and component events are processed. In order to convert data to the proper type, validate it, store it in an external object, and process events in an orderly fashion, the JavaServer Faces life cycle is split into separate phases to handle each of these tasks. Therefore, it must be possible to evaluate expressions at different phases of the life cycle rather than immediately, as is done in JSP technology.

Another problem with the immediate evaluation of expressions is that it is done in read-only mode. JavaServer Faces components need to be able to get data from server-side objects during the rendering phase and set the data in the server-side objects during postback.

Finally, JavaServer Faces components need a way to invoke methods on server-side objects during various stages of the life cycle 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 TLD file; they cannot be used to dynamically invoke public methods on objects.

For all these reasons, a more powerful expression language was created that included the following new features:

  • Deferred expressions, which can be evaluated at different stages of the page life cycle
  • Expressions that can set data of external objects as well as get that data
  • Method expressions, which can invoke methods that perform event handling, validation, and other functions for the JavaServer Faces UI components

Conflicting Expression Language Syntax


The new expression language worked well for the purposes of JavaServer Faces component tags. When using component tags with JSTL tags, however, page authors would find that the expression language used by the JSTL tags would conflict with that used by the component tags. Consider the following example, which shows a forEach tag containing an inputText tag, which represents a text field component:

   <c:forEach var="book" items="${BooksBean.books}">
            

     ...
            

 <h:inputText id="quantity" value="#{book.quantity}" ... />
            

    ...
            

   </c:forEach>
            

          
itemsvalueinputText
  • As the iteration is processed, the JavaServer Faces implementation tries to create a component object with the same quantity ID every time the inputText component tag is encountered during the iteration. This fails because duplicate component IDs are not allowed.
  • Even if duplicate IDs were allowed, this iteration still has problems because of the fact that the expression referenced by items is evaluated immediately. This results in the book variable being available only when the component is rendered during the render response phase, not during the other phases of the JavaServer Faces life cycle. Therefore, the values entered by the user into the components would not be updated to the external data object.


Features of the Unified EL


The new unified EL essentially represents a union of the JSP and JavaServer Faces expression languages and largely benefits JavaServer Faces technology. Other Java-based web component technologies benefit too because the unified EL is more pluggable and flexible as a result of unifying the expression languages. In addition to the expression language features that were already available in the JSP EL, 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
  • A pluggable API for resolving expressions

Immediate vs. Deferred Evaluation of Expressions

${expr}

valuecart
   <fmt:formatNumber value="${cart.total}"/>

${cart.total}



#{expr}

inputTextinputTextvaluequantitybook
   <h:inputText id="quantity" value="#{book.quantity}" />
#{book.quantity}quantitybook

book

Value and Method Expressions

Value expressionsMethod expressions

Rvalue expressionsLvalue expressions
   ${book.quantity}
            

    #{book.quantity}
            

          
quantity

quantity






   ...
            

   <h:inputText id="quantity"
            

     value="#{book.quantity}"
            

    validator="#{book.validateQuantity}"/>
            

   ...
            

   <h:commandButton id="update"action="#{book.submit}" />
            

   ...
            

          
validatorinputTextvalidateQuantitybookinputTextvalidatorbook.submitactioncommandButtonsubmitcommandButton

validateQuantitysubmit



Compatibility of Deferred Expressions in Iteration Tags

Conflicting Expression Language SyntaxforEachforEachwebtier-sample.jsp
   <c:forEach var="book" items="#{BooksBean.books}">
            

     ...
            

 <h:inputText id="quantity" value="#{book.quantity}" ... />
            

    ...
            

   </c:forEach>
            

          
itemsforEachbooksforEach

forEach

webtiersample.jspforEach

Pluggable Resolver Mechanism

${customer.name}namecustomer

ELResolverELResolver

ELResolver
  • Connections to resources such as JNDI and JDBC resources
  • Implicit objects
  • Methods that don't follow JavaBeans conventions

  • Writing an implementation of ELResolver
  • Registering the ELResolver implementation with the application
  • Using expressions in the page

Writing an ELResolver Implementation

ELResolverColorELResolverColorImplicitObject

   ${Color.LightGrey.hex}

ELResolverColorELResolver
  • 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)
getValue#{books.quantity}booksquantitybooksquantity

webtiersample.jspColorImplicitObject
   <style type="text/css">
            

       ...
            

        .oddRow {background-color: ${Color.LightGrey.hex};}
            

 ...
            

   </style>
            

          

forEachclasstr

    <tr class="${(stat.index % 2) == 0 ? "evenRow" : "oddRow"}">

oddRowevenRowColorImplicitObject
webtier-sample.jsp


table of books displayed on webtier-sample.jsp page
Figure 1: Table of Books Displayed on webtier-sample.jsp Page


When the expression "${Color.LightGrey.hex}" is encountered, the following happens:

  1. The getValue method of ColorELResolver is called to resolve the base object, Color, to the ColorImplicitObject instance.
  2. The getValue method is called again to resolve the second part of the expression, LightGrey. It resolves this part of the expression by invoking the fromName method of ColorImplicitObject with the argument LightGrey in order to locate the color LightGrey in a text file that lists all the available colors.
  3. The fromName method creates a map of the names of the colors and associated ColorRGB objects, which encapsulate the red, green, and blue values of each color.
  4. From the map it creates, fromName finds the LightGrey color and returns its ColorRGB 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, hex, causing the getHex method of ColorRGB to be called. This method returns the hexadecimal value of LightGrey.
getValuepropertyResolvedELContexttrue

ColorELResolver.javagetValue

getTypesetValue

isReadOnlyfalsetrue

setValue

ColorELResolversetValuePropertyNotWritableExceptionColorImplicitObjectColorRGBColor

setValuesetSubmittedValueValueExpressionValueExpressionValueExpressionsetValuesetValueELResolver

getCommonPropertyTypegetFeatureDescriptors

getFeatureDescriptorsnullgetCommonPropertyType

getFeatureDescriptorsFeatureDescriptorgetFeatureDescriptorsColorResolverFeatureDescriptor

FeatureDescriptor
  • The ELResolver.RESOLVABLE_AT_DESIGN_TIME flag must be set to true or false
  • The ELResolver.TYPE flag must be set to the return type of the method in question
RESOLVABLE_AT_DESIGN_TIME

getCommonPropertyTypeObject.classnull

Registering the Resolver

faces-config.xml

If you are using the resolver with a JSP application that does not use any JavaServer Faces tags, you use a context listener to register the resolver.  If your application contains a mixture of JSP tags and JavaServer Faces tags, both of which might use expressions that your resolver will handle, you should register the resolver using the application configuration file.  Because the JavaServer Faces technology-specific resolvers are added to the JSP container, the JSP tags have access to the resolver registered by way of the configuration file. Let's go over using the context listener first.

Registering the Resolver Using a Context Listener
contextInitializedServletContextListenerJspApplicationContextcontextInitializedColorELResolver

   public void contextInitialized(ServletContextEvent servletContextEvent) {
            

  ServletContext context = servletContextEvent.getServletContext();
          
        JspApplicationContext jspContext =
            

            JspFactory.getDefaultFactory().getJspApplicationContext(context);
            

   jspContext.addELResolver(new ColorELResolver());
            

    servletContextEvent.
            

                getServletContext().log("ColorELResolver registered");
            

   }
          
CompositeELResolverImplicitObjectELResolver

Registering the Resolver Using a JavaServer Faces Application Configuration File
el-resolver

   
                 <el-resolver>         webtier-sample.ColorELResolver    </el-resolver>
          

Faces EL Resolver for JSPCompositeELResolverImplicitObjectELResolver

Using the Expression in the Page

webtiersample.jspColorELResolver

   ...
            

   <style type="text/css">
            

      ...
            

      .oddRow {
            

          background-color: ${Color.LightGrey.hex};
            

      }
            

      ...
            

   </style>
            

   ...
            

   <table>
            

      ...
            

      <c:forEach items="#{BooksBean.books}" var="book"
            

         varStatus="stat">
            

         <tr class="${(stat.index % 2) == 0 ? "evenRow" : "oddRow"}">
            

            <td>
            

                <h:outputText id="title" value="#{book.title}"/>
            

            </td>
            

            ...
            

      </c:forEach>
            

   </table>
            

   ...
            

          

Migrating to the Unified EL


For those of you who already have JSP and JavaServer Faces applications that use the previous versions of the EL, you can be assured that your applications are completely backward compatible, except for a couple rare corner cases. Aside from these cases, you don't need to make any changes to run your applications with the latest versions.

If you plan to modify your current applications to use the new EL, however, there are some things you need to do, which this section explains. These changes primarily affect those developing JavaServer Faces applications.  The good news is, though, that the page author and application developer don't need to do anything differently in JavaServer Faces 1.2 applications vs. version 1.1 or earlier applications. The component writer and the application architect do have some changes to make, which include:

  • Updating the TLD defining the custom component tags with the new version number and the new deferred-value or deferred-method elements
  • Editing custom component tag handlers to use the new APIs
  • Editing custom component classes to use the new APIs



Making Changes to a Custom Tag TLD

jsp-version

 

If your custom tags are only JSP custom tags, however, there really isn't anything further you need to do unless you want to modify your tag attribute definitions to accept deferred expressions.  If you want a tag attribute to accept a deferred expression instead of a dynamic one (one that uses ${} syntax), simply replace the rtexprvalue element with either the deferred-value or deferred-method element as explained in this section.  If you want the tag attribute to accept both deferred and dynamic expressions, keep the rtexprvalue element and add either the deferred-value or deferred-method element.  Most likely, you won't find a use for deferred expressions in a straight JSP application; these kinds of expressions mainly benefit JavaServer Faces technology because of its multi-phase life cycle.

For JavaServer Faces custom tags, you must replace the rtexprvalue element with either deferred-value or deferred-method, depending on whether the corresponding property accepts value expressions or method expressions.

The following TLD defines a custom component tag based on version 1.1:

<taglib>
            

<!-- ============== Tag Library Description Elements ============= -->
            

   <tlib-version>1.0</tlib-version>
            

   <jsp-version>1.2</jsp-version>
            

   <short-name>DemoTaglib</short-name>
            

   <tag>
            

      <name>simple</name>
            

      <tag-class>example.SimpleComponentTag</tag-class>
            

      <body-content>JSP</body-content>
            

      <attribute>
            

         <name>someProperty</name>
            

         <required>true</required>
            

         <rtexprvalue>false</rtexprvalue>
            

      </attribute>
            

      <attribute>
            

         <name>validator</name>
            

         <required>false</required>
            

         <rtexprvalue>false</rtexprvalue>
            

    </tag>
            

 </taglib>
            

          

The following TLD defines the same custom component tag for JavaServer Faces technology 1.2 and JSP 2.1:

 

 <taglib><!--============== Tag Library Description Elements ============= -->
            

    <tlib-version>1.1</tlib-version>
            

    <jsp-version>2.1</jsp-version>
            

    <short-name>DemoTaglib</short-name>
            

                <tag>
            

       <name>simple</name>
            

       <tag-class>example.SimpleComponentTag</tag-class>
            

       <body-content>JSP</body-content>
            

       <attribute>
            

          <name>someProperty</name>
            

          <required>true</required>
            

          <deferred-value>
            

             <type>java.lang.String</type>
            

          </deferred-value>
            

       </attribute>
            

       <attribute>
            

          <name>validator</name>
            

          <required>false</required>
            

          <deferred-method>
            

             <method-signature>
            

                void validate(javax.faces.context.FacesContext, javax.faces.component.UIComponent, java.lang.Object)
            

             </method-signature>
            

          </deferred-method>
            

                         </attribute>
            

    </tag>
            

 </taglib>
            

          
jsp-versionValueExpressionMethodExpression

rtexprvaluesomePropertydeferred-methodvalidatordeferred-valuedeferred-methodvalidatorValueExpressionsomePropertyMethodExpressionvalidatortypedeferred-valuemethod-signature

Making Changes to the Custom Component Tag Handlers


  • Make the class extend UIComponentELTag instead of UIComponentTag
  • Change ValueBinding to ValueExpression and MethodBinding to MethodExpression
  • Simplify the setProperties method by removing the condition that checks if the expressions is value-binding enabled.  By default, all JavaServer Faces tag attributes can take either value or method expressions.
   public class SimpleComponentTag extends UIComponentTag {
            

             

      String someProperty;
            

      String validator;
            

             

      public void setSomeProperty(String someProperty) {
            

             

        this.someProperty = someProperty;
            

      
            

      }
            

             

      public void setValidator(String validator) {
            

             

        this.validator = validator;
            

      }
            

                
            

      ...
            

        
            

      protected void setProperties(UIComponent component) {
            

       
            

        super.setProperties(component);
            

        if (someProperty != null) {
            

          if (isValueReference(someProperty)) {
            

            ValueBinding vb = FacesContext.getCurrentInstance().
            

              getApplication().createValueBinding(someProperty);
            

            component.setValueBinding("someProperty", vb);
            

          } else {
            

            component.setProperty(Boolean.valueOf(someProperty));
            

          }
            

        }
            

        if(validator != null) {
            

          if (isValueReference(validator)) {
            

            Class args[] = { FacesContext.class, UIComponent.class,
            

             Object.class };
            

            MethodBinding vb = FacesContext.getCurrentInstance().
            

             getApplication().createMethodBinding(validator, args);
            

            input.setValidator(vb);
            

          } else {
            

           throw new FacesException("Invalid Expression");
            

          }
            

        }
            

      }
            

   }
            

          


   public class SimpleComponentTag extends UIComponentELTag {
            

      ValueExpression someProperty;
            

      MethodExpression validator;
            

                    
            

      public void setSomeProperty(ValueExpression someProperty) {
            

         this.someProperty = someProperty;
            

      }
            

                                                    
            

      public void setValidator(MethodExpression validator) {
            

         this.validator = validator;
            

      }             
            

      ...
            

      protected void setProperties(UIComponent component) {
            

         super.setProperties(component);
            

         if (someProperty != null) {
            

            if (!someProperty.isLiteralText()) {
            

               component.setValueExpression("someProperty", someProperty);
            

            } else {
            

               component.setSomeProperty(Boolean.valueOf(someProperty.getExpressionString()));
            

            }
            

         }
            

         if(validator != null) {
            

            component.addValidator(new MethodExpressionValidator(validator));
            

         }
            

      }
            

   }
            

          

Notice that the new setProperties method does not have to do the work of getting the expression from the Application instance and converting a String to a value binding or method binding. Instead, the JSP container manages the ValueExpression and MethodExpression objects and passes them to the tag handler. Also, setProperties does not have to check if the property is enabled to accept a value expression or method expression because this information is already in the TLD, which is shown in the previous section.

Making Changes to the Custom Component Classes

ValueBindingMethodBinding

ValueBindingValueExpressionMethodBindingMethodExpressionValueExpressionMethodExpression

public boolean someProperty() {
            

             

   if (this.someProperty) {
            

         return (this.someProperty);
            

      }
            

   ValueBinding vb = getValueBinding("someProperty");
            

  
            

    if (vb != null) {
            

      Boolean value = (Boolean) vb.getValue(getFacesContext());
            

           if (value != null) {
            

            return (value.booleanValue());
            

            } else {
            

              return false;
            

           }
            

        } else {
            

       return (this.someProperty);
            

      }
            

}
          


public boolean someProperty() {
            

             

   if (this.someProperty) {
            

      return (this.someProperty);
            

   }
            

   ValueExpression ve = getValueExpression("someProperty");
            

   if (ve != null) {
            

      Boolean value = (Boolean)
            

         ve.getValue(getFacesContext().getELContext());
            

      if (value !- null) {
            

         return (value.booleanValue());
            

      } else {
            

         return false;
            

      }
            

   } else {
            

      return (this.someProperty);
            

   }
            

}
            

          

Backwards Compatibility Issue for JSP Applications

#{}#{#{
  • 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

  • Escape the #{ characters as follows:

                      some text \#{ some more text
                  

    and
                      <my:tag someAttribute="sometext\#{moretext" />
                  
  • Configure your application to allow the #{} characters as a String literal by adding the deferred-syntax-allowed-as-literal subelement 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" %>
                  

Now It's Your Turn


So, you've seen what the new unified expression language has to offer:  a pluggable, extensible resolver machinery and a way to set data and  invoke methods from the page in addition to all the powerful features the JSP expression language already offered you. And the best part is that it is available now for you to use. All you need to do is go to https://glassfish.dev.java.net/ to get started. If you need help, check out these forums:

Rate and Review
Tell us what you think of the content of this page.
Excellent   Good   Fair   Poor  
Comments:
Your email address (no reply is possible without an address):
Sun Privacy Policy

Note: We are not able to respond to all submitted comments.
Left Curve
Java SDKs and Tools
Right Curve
Left Curve
Java Resources
Right Curve
JavaOne Banner Java 8 banner (182)