JSP 2.0

JSP 2.0

By Dan Troesser, OCI Principal Software Engineer

September 2003


Introduction

Java web development has come a long way. We have been introduced to applets, servlets, JavaServer Pages, WAR files, servlet filters, JSTL, JavaServer Faces (see last month's SETT article), and the list goes on. These technologies have aimed to make web development easier, more portable, more powerful, and more maintainable. The coming release of JSP 2.0 and Servlet 2.4 continues that tradition. Both specifications are currently in proposed final draft version 3 stage and the final versions will likely be released soon. This month's Java News Brief discusses the most notable new features of JSP 2.0.

"Easier to use" was the main goal for JSP 2.0. The main features added include integrated support for JavaServer Pages Standard Tag Library (JSTL) expression language, easier use and development of custom tags, and new dynamic attributes.

Scriptlets and Expressions ... "the old days"

Scriptlets and expressions are snippets of Java code that you embed in a JSP. Many consider them undesirable because they clutter the presentation layer (HTML) with ugly Java code and cause grief for HTML authors. Below is an example JSP that finds a customer based on a userName request parameter and shows data about that customer. It uses scriptlets and expressions to perform its task.

Note: The complete examples used in this article are available in customer_example.war. Place customer_example.war in Tomcat 5.0's webapps directory. Start Tomcat and enter http://localhost:8080/customer_example in the browser. Port 8080 assumes you're using the defaults. Feel free to modify the examples and experiment.

  1. <%@ page import="com.ociweb.customer.*"%>
  2. <html>
  3. <!--The following is a scriptlet. You can put any arbitrary Java code here. -->
  4. <%
  5. String userName = request.getParameter("userName");
  6. Customer customer = new Customer();
  7. CustomerDAO.populateCustomer(userName, customer);
  8. %>
  9. <head><title>Customer Profile for <%= userName %></title></head>
  10. <body>
  11. <h1>Customer Profile for <%= userName %></h1>
  12. <table>
  13. <!-- The following lines contain expressions. The result of the code within them
  14. is evaluated to a String and inserted into the HTML. -->
  15. <tr><td>First Name:</td><td><%= customer.getFirstName() %></td></tr>
  16. <tr><td>Last Name:</td><td><%= customer.getLastName() %></td></tr>
  17. <tr><td>Birth Date:</td><td><%= customer.getBirthDate() %></td></tr>
  18. <tr><td>Phone:</td><td><%= customer.getPhone() %></td></tr>
  19. <tr><td>Email:</td><td><%= customer.getEmail() %></td></tr>
  20. </table>
  21. </body>
  22. </html>

Example browser view

Customer Profile for Bugs


As we see above the request is processed and the Customer object is populated in the JSP. An experienced web developer would probably say "tisk tisk" to that. In a robust web application, a servlet would handle request processing and any calls to a data access layer. The servlet would then forward to a JSP. Nevertheless, for learning's sake, we will proceed with this design (or lack thereof) and see what new features of JSP 2.0 will help us remove the scriptlets and expressions.

JSTL Expression Language Support

Expression language (EL) is a syntax that allows easy access to objects and properties of objects (JavaBeans) in a JSP without using scriptlets or traditional JSP expressions. It was inspired by ECMAScript and XPath and introduced in JSTL 1.0. See the September 2002 Java News Brief for a more complete discussion of JSTL. The JSTL expression language was integrated into JSP 2.0. It was also updated with new features including support for functions and the ability to output expressions into template text. Integrating JSTL EL into the JSP specification removes the need for scriplets in a JSP page.

Here is a version of our customer profile JSP that uses expression language.

  1. <%@ page import="com.ociweb.customer.*"%>
  2. <html>
  3. <jsp:useBean id="customer" class="com.ociweb.customer.Customer"></jsp:useBean>
  4. <%
  5. String userName = request.getParameter("userName");
  6. CustomerDAO.populateCustomer(userName, customer);
  7. %>
  8. <head><title>Customer Profile for ${param["userName"]}</title></head>
  9. <body>
  10. <h1>Customer Profile for ${param["userName"]}</h1>
  11. <table>
  12. <tr><td>First Name:</td><td>${customer.firstName}</td></tr>
  13. <tr><td>Last Name:</td><td>${customer.lastName}</td></tr>
  14. <tr><td>Birth Date:</td><td>${customer.birthDate}</td></tr>
  15. <tr><td>Phone:</td><td>${customer.phone}</td></tr>
  16. <tr><td>Email:</td><td>${customer.email}</td></tr>
  17. </table>
  18. </body>
  19. </html>

EL expressions begin with ${ and end with }. Notice they are included inline with template text. In JSTL 1.0 this wasn't possible; you had to use c:out tags. EL allows access to:

EL Functions

JSP 2.0 added the ability to call public static methods in EL expressions. To illustrate their use, we will replace the remaining scriptlet in our customer profile example with an EL function. In other words, we want to replace

  1. <%
  2. String userName = request.getParameter("userName");
  3. CustomerDAO.populateCustomer(userName, customer);
  4. %>

with

  1. <%@ taglib prefix="cu"
  2. uri="http://www.ociweb.com/jnb/customer_example-taglib" %>
  3. ${cu:populateCustomer(param["userName"], customer)}
  4.  

The populateCustomer method we've been using all along looks like this.

  1. public static void populateCustomer(String userName,
  2. Customer customer) {
  3. if (customer == null) {
  4. customer = new Customer();
  5. }
  6. Customer tempCustomer = (Customer) customers.get(userName);
  7. if (tempCustomer != null) {
  8. customer.setUserName(tempCustomer.getUserName());
  9. customer.setFirstName(tempCustomer.getFirstName());
  10. customer.setLastName(tempCustomer.getLastName());
  11. customer.setBirthDate(tempCustomer.getBirthDate());
  12. customer.setEmail(tempCustomer.getEmail());
  13. customer.setPhone(tempCustomer.getPhone());
  14. }
  15. }

In order to use this method we have to add a function element to our tag library descriptor (TLD). You'll have to create a TLD file if it doesn't already exist. A tag library descriptor defines and configures tags in a tag library.

Download customer_example.war to see the full TLD used in our example.

  1. <function>
  2. <description>Finds the customer for the given username
  3. and populates the customer's properties</description>
  4. <name>populateCustomer</name>
  5. <function-class>com.ociweb.customer.CustomerDAO</function-class>
  6. <function-signature>void populateCustomer(java.lang.String,
  7. com.ociweb.customer.Customer)</function-signature>
  8. </function>

We also added a taglib element to the deployment descriptor (web.xml).

  1. <taglib>
  2. <taglib-uri>http://www.ociweb.com/jnb/customer_example-taglib</taglib-uri>
  3. <taglib-location>/WEB-INF/customer_example-taglib.tld</taglib-location>
  4. </taglib>

Notice the taglib-location specifies the location of the TLD. The taglib-uri is, for the most part, an arbitrary name given to the tag library. The name you give it can't conflict with other tag libraries in your deployment descriptor.

That's it. In fact, adding the taglib element to the deployment descriptor is actually optional. You could instead reference the TLD directly in the taglib directive.

<%@ taglib prefix="cu" uri="/WEB-INF/customer_example-taglib.tld" %>

This isn't recommended because it reduces flexibility if you ever choose to rename or move the TLD. The uri would have to be changed in every JSP that used it.

The new customer profile JSP looks like the following.

  1. <%@ taglib prefix="cu" uri="http://www.ociweb.com/jnb/customer_example-taglib" %>
  2. <html>
  3. <jsp:useBean id="customer" class="com.ociweb.customer.Customer"></jsp:useBean>
  4. ${cu:populateCustomer(param["userName"], customer)}
  5. <head><title>Customer Profile for ${param.userName}</title></head>
  6. <body>
  7. <h1>Customer Profile for ${param.userName}</h1>
  8. <table>
  9. <tr><td>First Name:</td><td>${customer.firstName}</td></tr>
  10. <tr><td>Last Name:</td><td>${customer.lastName}</td></tr>
  11. <tr><td>Birth Date:</td><td>${customer.birthDate}</td></tr>
  12. <tr><td>Phone:</td><td>${customer.phone}</td></tr>
  13. <tr><td>Email:</td><td>${customer.email}</td></tr>
  14. </table>
  15. </body>
  16. </html>

The prefix given in the taglib directive is whatever you choose to distinguish it from tags and functions in other tag libraries used in the JSP.

EL Conclusions

Yes, you could remove scriptlets in JSP 1.2 with creative use of JavaBeans or custom tags. You could also use JSTL and its expression language to help remove those nasty scriptlets. However, that required downloading and installing JSTL for your one or more web applications. Unfortunately, the tag libraries in JSTL were not integrated into JSP 2.0, just the expression language. Therefore, if you want to use JSTL tags you still need to do a little extra legwork. Nevertheless, expression language support is a step in the right direction especially with its added support for functions and inclusion in template text.

Simpler Custom Tag Development

Tag development in JSP 2.0 is easier and more powerful. The new features include:

Simple Tag Handler and Dynamic Attributes

The next version of the customer profile example illustrates the use of the simple tag handler anddynamic attributes. We will replace the populateCustomer EL function with a simple tag. First we create our tag class.

  1. package com.ociweb.customer;
  2.  
  3. import javax.servlet.jsp.*;
  4. import javax.servlet.jsp.tagext.*;
  5. import java.util.*;
  6. import java.io.*;
  7.  
  8. public class CustomerDAOTag extends SimpleTagSupport implements DynamicAttributes
  9. {
  10. private Map attributes = new HashMap();
  11.  
  12. public void doTag() throws JspException, IOException {
  13. String userName = (String) attributes.get("userName");
  14. Customer customer = (Customer) attributes.get("customer");
  15. if (userName == null || customer == null) {
  16. throw new JspException("Both userName and customer attributes "
  17. + "must exist and be non-null");
  18. }
  19. CustomerDAO.populateCustomer(userName, customer);
  20. }
  21.  
  22. public void setDynamicAttribute(String uri, String localName,
  23. Object value) throws JspException {
  24. attributes.put(localName, value);
  25. }
  26. }

To use dynamic attributes we simply implement the DynamicAttributes interface and provide a setDynamicAttribute method. We also need to make an entry in the TLD for our new tag. Note that dynamic-attributes are set to true.

  1. <tag>
  2. <description>Finds the customer for the given username and populates the customer's properties</description>
  3. <name>populateCustomer</name>
  4. <tag-class>com.ociweb.customer.CustomerDAOTag</tag-class>
  5. <body-content>empty</body-content>
  6. <dynamic-attributes>true</dynamic-attributes>
  7. </tag>

If we wanted to output HTML in the doTag method we could insert

getJspContext().getOut().write("some HTML");

Using dynamic attributes for our simple example is probably overkill. We could very easily provide setUserName and setCustomer methods instead and do away with our Map. If we did that, we would also need to add attribute elements to the tag element in our TLD.

The new version of our customer profile JSP using our custom tag is shown below.

  1. <%@ taglib prefix="cu" uri="http://www.ociweb.com/jnb/customer_example-taglib" %>
  2. <html>
  3. <jsp:useBean id="customer" class="com.ociweb.customer.Customer"></jsp:useBean>
  4. <cu:populateCustomer userName="${param.userName}" customer="${customer}"></cu:populateCustomer>
  5. <head><title>Customer Profile for ${param.userName}</title></head>
  6. <body>
  7. <h1>Customer Profile for ${param.userName}</h1>
  8. <table>
  9. <tr><td>First Name:</td><td>${customer.firstName}</td></tr>
  10. <tr><td>Last Name:</td><td>${customer.lastName}</td></tr>
  11. <tr><td>Birth Date:</td><td>${customer.birthDate}</td></tr>
  12. <tr><td>Phone:</td><td>${customer.phone}</td></tr>
  13. <tr><td>Email:</td><td>${customer.email}</td></tr>
  14. </table>
  15. </body>
  16. </html>

.tag Files

Our next example illustrates the use of a .tag file to create a custom tag. This is probably the easiest way to create a custom tag. No TLDs or deployment descriptors need to be modified. Just create a file with a .tag extension and place it in the /WEB-INF/tags directory. You might have to create the tags directory if it doesn't exist. A .tag file uses JSP syntax so it's very simple to write. Shown below is customerDetailTable.tag. It will assume responsibility for looking up a customer and displaying his or her detail in an HTML table.

  1. <%@ taglib prefix="cu" uri="http://www.ociweb.com/jnb/customer_example-taglib" %>
  2. <%@ attribute name="userName" %>
  3. <jsp:useBean id="customer" class="com.ociweb.customer.Customer"></jsp:useBean>
  4. <cu:populateCustomer userName="${userName}" customer="${customer}"></cu:populateCustomer>
  5. <table>
  6. <tr><td>First Name:</td><td>${customer.firstName}</td></tr>
  7. <tr><td>Last Name:</td><td>${customer.lastName}</td></tr>
  8. <tr><td>Birth Date:</td><td>${customer.birthDate}</td></tr>
  9. <tr><td>Phone:</td><td>${customer.phone}</td></tr>
  10. <tr><td>Email:</td><td>${customer.email}</td></tr>
  11. </table>

The attribute directive tells the JSP container what attributes the tag should accept. It takes userName as an attribute and passes that into the populateCustomer tag we created earlier. The customer profile JSP becomes even simpler.

  1. <%@ taglib prefix="cu" tagdir="/WEB-INF/tags" %>
  2. <html>
  3. <head><title>Customer Profile for ${param.userName}</title></head>
  4. <body>
  5. <h1>Customer Profile for ${param.userName}</h1>
  6. <cu:customerDetailTable userName="${param.userName}"></cu:customerDetailTable>
  7. </body>
  8. </html>

To use our newly created tag we used the taglib directive and the tagdir attribute to specify where the .tag file is located. It's that easy.

Other New Features

JSP 2.0 provides some other new features including:

Servlet 2.4

Accompanying JSP 2.0 will be the release of Servlet 2.4, which JSP 2.0 depends on. It's most notable changes are:

Relationship to JavaServer Faces

JavaServer Faces (JSF) relies on JSP 1.2 and thus does not take advantage of JSP 2.0's features. JSF should work with JSP 2.0 as it is backward compatible with JSP 1.2. Future versions of JSF will likely use at least some of JSP 2.0's new features.

Summary

This SETT article illustrated some of JSP 2.0's new features using a simple customer profile example. With EL, EL functions, simple tag handlers, and .tag files, we have shown various new ways to remove annoying scriptlets and expressions from JSPs. Remember, the goal is to make web developer's lives easier. If you don't think it's easier, hopefully you have learned about at least one new feature you like. Whatever your impressions, you can't argue we have even more options available to us and more decisions to make as we pursue web development.

References



Software Engineering Tech Trends (SETT) is a regular publication featuring emerging trends in software engineering.