ONJava.com    
 Published on ONJava.com (http://www.onjava.com/)
 See this if you're having trouble printing code examples


JSP and Servlets

JSP Standard Tag Libraries, Part 2

05/08/2002

This article is the second in a series on JSTL, the JSP Standard Tag Library. If you need a primer as to what JSTL encompasses, check out part one of this series.

In this article, we will cover more of the details of how to use the various tags in the different Tag Library Descriptors (TLDs). We'll go though samples using the conditionals, iteration, and URL, U18N, SQL, and XML tags. The goal of this article is to show the key components of the JSTL, learn how to use the tags, and discover how using the JSTL can improve your JSP development.

Let's quickly review what the JSTL is: a set of standard custom actions that can be used in various functional areas. JSR-52 of the Java Community Process, JSTL provides expression language support, control flow actions, and Tag Library Validators. The latest version of the specification, which is the proposed final draft, can be found on the jcp.org site.

JSTL requires you to run a JSP 1.2 container. The overriding theme of the JSTL is to simplify the development of JSPs and provide easy access and manipulation of application data. Using JSTL should make the page author's life easier.

JSTL consists of multiple Tag Library Descriptors included in one JAR file. These TLDs cover a range of functional areas, and we'll go through each one. But first, let's talk in more detail about the expression language support that is a prominent feature of the JSTL.

The expression language (EL) support is actually owned by the JSR-152 experts group, which, for those of you keeping track, is JSP 1.3. However, the expert groups for both JSR-52 and JST-152 have been working closely together. In fact, it looks like EL will actually become part of the JSP 1.3 specification. The EL (currently SPEL) provides an easy syntax for accessing application data directly. This allows for operators and bean and collection support, as well as automatic type conversion and the definition of default values for attributes.

Using Expressions

Expressions are invoked through the construct ${expression}. Expressions can be used only in attributes. For example:

<c:if test="${product.price >= customer.limit}">
...
</c:if>

In the above example, we are just using an expression to do a comparison, but it's also possible to mix an expression with static text. That might look something like:


<c:forEach var="current">
	<c:out value="Product-${current}"/>
</c:forEach>

In this sample, we are iterating over a collection and using the current item to append to the string product. That might result in an output that looks like:


Product-1
Product-2
Product-3...

As you can see from this example, the manipulation that has to be done when using JSTL is much cleaner than code written previously. Before JSTL, you needed to declare an Object, know the type of that Object, and understand some scripting language to even do a simple manipulation. Having to do all those steps led to some awkward syntax.

Now, with the JSTL, we have direct access to data using a much simpler syntax. The EL support is much better suited for taking care of these types of tasks.

As a simple sample, we can go from:


<jsp:useBean id="customer" type="sample.Customer" scope="request"/> ...
Customer Name: <%=customer.getName()%>
...
<% if (customer.getState().equals("CO")){ %>
...
<%}%>

to:


Customer Name: ${ customer. name}
<c:if test="${customer. state == param. state}">
...
</c:if>

The EL also allows for direct access to data in all supported JSP scopes. For example, we can access foo using ${foo} instead of pageContext.findAttributes("foo"). It's also possible to access beans and their properties using dot or indexed referencing. For example:


${user.address.city} 
${products.[product.id]}
${products.["Part-010"]}

Related Reading

Java Servlet Programming
By Jason Hunter

The expression language has all of the relational operators you would assume: ==, !=, <,>, <=, and >=, &&, ||, ! . Additionally, there are lt, gt, le, ge, eq, and ne operators, to avoid having to use the entity references in XML syntax. There are also the arithmetic operators: +,-,/,*,%, as well as Boolean operators and, or, not, and empty. Another feature of the expression language is that it provides automatic type coercion. For example, int value = "${request.myValue}" would be converted correctly.

It is possible to provide default values. These default values are also type correct. Default values are a useful way to avoid null-pointer exceptions on your page. The following sample shows how to set a var with a default value: <c:set var="city" value="${user.address.city}" default="N/A" />

Now that we've taken a look at some of the features of using an expression language, let's look at the EL supported actions.

Core Actions

The EL is used in the Core tag library. The <c:out> tag outputs EL expression evaluation to the current JspWriter. This is similar in functionality to JSP's <%= scripting exp %>. Using the core actions looks like:


<c:out value="${customer.name}"  default="N/A" />

It's also possible to set and remove scoped variables. The default scope used is Page. For example, we can set a Page scope variable called customer by using <c:set var="customer" value=${customer}" /> and then use <c:remove var="customer" /> to remove it from scope.

With the JSTL we can now use a tag to catch java.lang.Throwable, for example, <c:catch var="myError" />. Using this tag allows for uniform error handling to be declared on a page. This tag isn't meant to replace the existing JSP error page mechanism. By using the <c:catch> tag it becomes possible to have fine-grained error handling; this allows for errors to be handled by the page instead of going to the error page -- not every error that gets thrown really needs to go to the error page. By using the <c:catch> tag, it's possible to design better user interactions because the flow of the page is more user-friendly.

Conditional Actions

Using the expression language in conditional actions can also be a powerful mechanism to simplify JSP code. By using the <c:if> tag, it is possible to construct simple conditional expressions. For example, by accessing an Objects property like so:


<c:if test="${user.visitCount == 1}"
	Welcome back! 

</c:if>

you can see that when there is an if, surely there is an else. Mutually exclusive conditionals are useful when only one of a number of possible alternative actions are evaluated. It is possible to perform "if/then/else" functionality by using the <c:choose>, <c:when>, and <c:otherwise> tags.

Let's look at a sample. If we were processing through some result set, we could use these tags to determine what the correct message to display should be.


<c:choose>
<c:when test="${count == 0}">
	No records matched your selection.
</c:when>
<c:otherwise>
	<c:out value="${count}"/> records matched your selection.
</c:otherwise>
</c:choose>

Iteration Actions

Probably the most useful features of the JSTL are the iteration actions. The actions that support iterations are <c:forEach>, <c:forToken>, and <x:forEach>. There are also XML tags that mimic the core tags for iterations. We'll talk about the XML action tag in a moment, but for now, let's stick with the core actions.

These actions support all of the standard J2SE collection types, including List, LinkedList, ArrayList, Vector, Stack, and Set. This also includes java.util.Map objects like HashMap, Hashtable, Properties, Provider, and Attributes. You can also iterate over an array of Objects or primitive types. When using primitive types, the current item is wrapped with the Java wrapper class. So the current item in an Array of ints would be an Integer. Two objects are exported for each iteration, the current item and the iteration status. Let's look at the sample below:


<table>
<c:forEach var="product" 
              items="${products}" 
              varStatus="status">
<tr>
	<td><c:out value="${status.count}"/></td>
	<td><c:out value="${product.name}"/></td>
</tr>
</c:forEach>
</table>

In this example, the Collection is specified by the EL as products. The current item is contained in the variable product. The current status of the iteration is held in the varStatus object status. Pretty simple.

URL Actions

In addition to the iteration actions, the Core library also offers URL-related actions. This includes support for hyperlinks, resource imports, and redirects. Using the <c:url> tag conveniently handles URL rewriting and encoding automatically. If we look at the example of specifying a URL with a parameter and then using it in a link, it might look like this:


<c:url=http://mysite.com/register var="myUrl">
	<c:param name="name" value="${param.name}"/>
</c:url>
<a href='<c:out value="${myUrl}"/>'>Register</a>

Using resource imports also became more powerful with the JSTL. It is now possible to specify absolute, relative, relative URL with a foreign context, and FTP resources. Let's look at a couple of examples:

From the examples above, it's obvious that <c:import> provides more power than using a <jsp:include>; however, there are also other reasons to use the tags. There are improvements in resource content buffering in the JSTL that eliminate unnecessary buffering. If you used a <jsp:include> inside of a transformation, the resource content would be read and then the body content would be written to the current JspWriter. The content would then be re-read by the transform tag. When using <c:import>, the body content will only be read in once, and then the data will be processed by the transform tag.

It is also possible to include resource content inline or exported as either a String or Reader Object using attributes called var or varReader. The String Object is reusable and has its contents cached. The advantage of using a Reader is that the content can be accessed directly without any buffering. A Reader, however, needs to be nested within a <c:import> to assure that the Reader is properly closed and isn't accidentally left open. We can demonstrate this with the sample below:


<c:import url=http://sample.com/customers varReader="customers">
	<mytag:process in="${customers}"/>
</c:import>

Internationalization

Another important functional area of the JSTL is its international (I18N) and formatting support. Using the actions provided makes it simple to internationalize on a request or context-configuration basis. These actions make use of the standard J2SE ResourceBundle used to hold the strings that are translated. The JSTL tags will use the appropriate ResourceBundle, depending on the specified locale. The <fmt:setLocale> tag can be used to specify a locale like this: <fmt:setLocale value="es_Es"/>, where the value equals that language and country code. It's also possible to specificy a ResourceBundle: <fmt:bundle basename="ApplicationResource_fr"/>.

Once the locale or the bundle is set, then the <fmt:message> tag will automatically use the correct ResourceBundle. Parametric replacement can be performed on strings like so:


<fmt:message key="welcome">
	<fmt:param value="${visitCount}" />
<fmt:message/>

You can also use < fmt:requestEncoding/> to set the request's character encoding.

Getting and displaying strings is only half the international fun. There also must be a way to format and parse numbers and dates; different locales typically have specific ways of doing so. Using <fmt:formatNumber> or <fmt:parseNumber> allows for the formatting of numbers, currencies, and percentages according to the current Locale. Patterns can also be specified by using the pattern attribute. To demonstrate: <fmt:formatNumber value="12.3" pattern=".00"/> would output "12.30."

Dates and times are handled using the <fmt:formatDate>, <fmt:timeZone>, <fmt:setTimeZone>, and <fmt:parseDate>.

SQL Actions

The SQL actions allow for direct access to data sources. That statement alone should set off red flags in your MVC architecture; I myself am thoroughly against using these tags in production applications. While they might serve a purpose for RAD, prototyping, or very simple applications, they certainly should not be used in large-scale application development. It seems like there are a lot of developers out there who really wanted this functionality to be available to them, so it's in the spec; therein lies the beauty of the JCP. With that said, let's look at what the SQL actions can provide.

Using these tags makes it possible to set datasources, query the datasource, have easy access to result sets, and perform updates as well as transactions. All of the SQL tags act upon a datasource. The datasource can be provided in a number of ways: it can be configured via the configuration parameter sql.datasource, there can be an Object that is provided by the application logic, or there can be an Object provided by the <sql:setDataSource> action. For example, if I were using a MySql database with the JDBC driver, I can define the datasource as:


<sql:setDataSource var="datasource"  driver="org.gjt.mm.mysql.driver" url="jdbc:mysql://localhost/db" />

For those familiar with the JDBC DriverManager, <sql:setDataSource> is just a wrapper around that facility. If the datasource attribute is a String, it could either be a relative path to a JNDI resource or a JDBC parameter string. A query can then access the datasource like so: <sql:query datasource="${datasource}" ... />

If we put a whole sample together to execute a query and then display the result set, it might look like:


<sql:query var="customer" datasource="${datasource}" 
SELECT * FROM customers WHERE state = 'CO' ORDER BY city
</sql:query>
<table>
<c:forEach var="row" items="${customers.row}">
	<tr>
	<td><c:out value="${row.custName}" /></td>
	<td><c:out value="${row.address}" /></td>
	</tr>
</c:forEach>
</table>

Performing updates and transactions is just as simple. For example, we can define a transaction and then any number of updates to be performed in that transaction. This is shown in the sample below.


<sql:transaction dataSource="${dataSource}">
<sql:update>
	UPDATE account SET Balance =Balance -? WHERE accountNo = ?
	<sql:param value="${transferAmount}"/>
	<sql:param value="${accountFrom}"/>
</sql:update>
</sql:transaction>

The <sql:dateParam> action can be used to set the values of parameter markers (?) in a SQL statement, for values of type java.util.Date. While not shown in this example, it is possible to specify the isolation level of the transaction. Transaction isolation levels are the ones defined by java.sql.Connection. If no transaction level is specified, the isolation level the datasource has been configured with is used. Any SQLException that might occur in the course of the transaction is caught and rethrown as a JspTagException by the tag.

XML Actions

The last set of actions to look at is the XML actions. The XML actions can be further categorized into core, flow control, and transform actions. The XML set of actions in the JSTL is based on Xpath, which is used as the local expression language for the XML actions. The attribute select is used to specify the XPath expression for all of the XML actions of JSTL. This is a string literal that is evaluated the XPath engine.

The XML core actions are similar to those provided in the Core actions. Actions include <x:out>, <x:set>, and <x:parse>. The main difference between the Core tags and the XML tags is that the XML tags support XPath expressions, while the Core tags don't. The parse tag provides functionality to parse an XML document into a data structure. This data structure can then be processed by the XPath engine. So, for example, if we have an XML file that identifies a book, we can parse it, and then access that data using an XPath expression and print it out:


<c:import url="http://oreilly.com/book?id=1234" var="xml"/>
<x:parse source="${xml}" var="bookInfo"/>
<x:out select="$bookInfo/title"/>
<x:out select="$bookInfo/author"/>

The XML Flow control actions are the same as in Core. They include: if, choose, when, otherwise, and forEach tags. The only difference is that the select attribute is used to specify the XPath expressions. The expression is evaluated, and the resulting object is converted to a boolean according to the semantics of the XPath boolean() function. These semantics are:

The XML transform actions are used to take an XML document and apply an XSL stylesheet to it. The result of the transformation is written to the page, but it's possible to capture the result in an Object specified via the result attribute, or save it in a scope using the var and scope attributes. Performing a transformation is as simple as importing the XML and XSL files and then doing a transform:


<c:import url="/books" var="xml"/>
<c:import url="/WEB-INF/xslt/bookDisplay.xsl" var="xslt"/>
<x:transform source="${xml}" xslt="${xslt}"/>

If you need to specify parameters to the transformation, use the <x:param> action to indicate the parameter name and value.

Summary

You have learned how to use some of the cool tags being provided in the JSTL. Surely, the implementation of your JSP files will become easier and faster using the actions that are provided. Keep up on what's going on with the JSTL; when the final draft is available, we should also see vendors optimizing their JSP containers for handling JSTL tags. If you want to start playing with the reference implementation, download the latest version.

Sue Spielman is an associate editor for ONJava.com, covering JSP and Servlets technologies. She is also President and Senior Consulting Engineer for Switchback Software LLC.


Read more JSP and Servlets columns.

Return to ONJava.com.

Copyright © 2009 O'Reilly Media, Inc.