Developer

An introduction to JSP 2.0's tag files

JSP custom tags used to be quite difficult to write, but with the arrival of tag files in JSP 2.0 there is a better, faster and easier way to build custom tags. We'll show you the basics to get you started with this powerful new feature.

Need to get up to speed on JSP basics? Then download our free quick start guide to JavaServer Pages. Free registration required.

ColdFusion developers have been using custom tags extensively for quite a long time. There is a very simple reason for this—in CFML, they are extremely easy to write! JSP custom tags were not quite so easy to write and took considerably longer to develop. But now, with the arrival of Tag Files in JSP 2.0, there is a better, faster, and easier way to build custom tags. You'll need some familiarity with basic JSP syntax, and you have access to Tomcat 5 or some other JSP 2.0 capable server.

Your first JSP tag file

A tag file is simply a plain text file with a file extension of .tag. Other than the JSP page directive, all the usual JSP elements can be used within this file. Let's start off really simple: Create a file called tagDemo.tag and put the following text inside:

<%
 String whoAmI = "I am a String within a scriptlet";
%>

Hello There,  <%= whoAmI %>

That's it; your first tag file is finished! Of course, you haven't yet made use of the tag from inside a jsp. Before you can do that, make sure you save the newly created tagDemo.tag file in a folder called tags inside your Web application's WEB-INF directory. The next step is to create your test jsp page and add the following line:

<%@ taglib prefix="tags" tagdir="/WEB-INF/tags" %>

The taglib directive above simply tells the jsp container where to find your tag (the tagdir attribute) and what prefix you will be using to identify your tag (the prefix attribute). To use the tag requires a combination of the prefix and the tag file name in the following form:

<tags:tagDemo/>

This simply prints the value of the whoAmI variable at the location that the tag appears in the page.

It is worth mentioning that you can create subfolders off the tags directory to organize your tag files into tag libraries. For example; WEB-INF/tags/shoppingCart/ or WEB-INF/tags/StringUtilities. Just include the proper path when specifying the tagdir attribute.

What makes tag files so cool is this simplicity—you did not need to implement any interfaces, compile any java source code, write any tag library descriptors or do any of the usual things you had to do in versions of JSP to get a custom tag up and running. You get all the benefits of a custom tag without the tedium of the traditional class-based custom tag API.

Using doBody to access body content

One of the more useful things about custom tags is the fact that you can access the tag's body content and manipulate or make use of it. For example, let's create a functional implementation for the following:

<tags:uppercase>
I want to be in capital letters.
</tags:uppercase>

This is where the <jsp:doBody/> action comes in to play. <jsp:doBody/> is an example of a jsp action that can only be used inside a tag file. (You will see another such action shortly). This time your tag file will be called uppercase.tag:

<jsp:doBody var="theBody"/>

<%
String bc = (String) pageContext.getAttribute("theBody");
%>

<%= bc.toUpperCase() %>

The first line is the <jsp:doBody/> declaration. What is important here is the var attribute, which places a String variable into the pageContext of the tag file. This variable contains the actual body content of the doBody tag. In the next line, you retrieve this value using pageContext.getAttribute("theBody"), and finally you use Java's toUpperCase() function to print out the all-uppercase value.

While the example is trivial, it hopefully demonstrates that tag files have the potential to shift a lot of that messy scriptlet code into nice reusable tags. Sure, you could do that prior to JSP 2.0 but now it's almost a pleasure instead of a pain.

The <jsp:doBody/> tag has a couple other features you may find interesting.

<%@ tag body-content="scriptless"  %>

<jsp:doBody var="theBody" scope="page"/>

<%
String bc = (String) pageContext.getAttribute("theBody");
%>

<%= bc.toUpperCase() %>

The code above does exactly the same thing as the previous code. But this time I included the tag directive—another tag-file-only element—and explicitly set its body-content attribute to 'scriptless'. As it happens, this is the default value. When using 'scriptless' you are allowed to put template text, standard actions and custom actions within your tag's body – but not Java code. When set to 'empty' your tag must not have a body at all, and finally, when set to 'tagdependant', the tag's body content is treated as pure text.

Notice that the <jsp:doBody/> tag now has a scope attribute; you can use this to export the variable to any of the usual JSP scopes. The default is 'page'.

You should also know about the varReader attribute—you can use this instead of the var attribute to have the variable stored as a java.io.Reader instead of a String. In some circumstances this may be more efficient when processing large amounts of body content.

doBody without any attributes

What happens if you use <jsp:doBody/> without any attributes at all? In this case the body content is printed directly back to the page. Check out our next example, box.tag:

<%@attribute name="color" required="true"%>

<%
String theColor = (String) pageContext.getAttribute("color");
%>

<table width="400" cellpadding='5' bgcolor='<%=theColor%>'>
    <tr>
        <td>
            <jsp:doBody/>
        </td>
    </tr>
</table>

This tag file simply wraps an HTML table tag around the body content. (Making it appear to be inside a colored box) I simply used an invocation of <jsp:doBody/> to reproduce the tag's original body content inside the table's <td> tag.

Adding attributes

Attributes are the mechanism that custom tags use to allow you, or the users of your tags, to customize the way that the tag behaves.

Let's go back to the previous example, the box.tag file. Clearly, the color of the box (HTML table) is something that should be determined on a case-by-case basis. This is where the attribute directive comes in. (This directive is another example of an element that can only occur inside a tag file.) The box.tag file has the following line at the top:

<%@attribute name="color" required="true" %>

This lets your tag file know that you are expecting an attribute called 'color' to be passed along. I set the required attribute to true in this case; therefore not supplying it would create an error in your jsp. Be aware that if you omit the 'required' attribute, or set it to 'false', it is up to you to ensure that your tag is still usable should the attribute not be supplied.

Here is how the box tag is used in a jsp:

<tags:box color="yellow" >
I want to be inside a colored box!
</tags:box>

Supplying the attribute is straightforward, but how do you access the value from inside our tag file? The answer is that it shows up in the page scope. In the example you see that I have used the following line to access the page scope and grab the color attribute:

<%
String theColor = (String) pageContext.getAttribute("color");
%>

Keep in mind that this page scope we are talking about here is the tag file's own page scope, not the page scope of the calling page. So you don't need to worry about conflicts; such as the calling page and the tag file using the same names for page-scoped variables.

For those of you who are fans of the JSP 2.0 expression language, here's a little leaner version of the box.tag file:

<%@attribute name="color" required="true"  %>

<table width='400" cellpadding="5"  bgcolor="${pageScope.color}" >
    <tr>
        <td>
            <jsp:doBody/>
        </td>
    </tr>
</table>

Thanks to ${pageScope.color}, you have a tidier looking tag file. If you like using the expression language and the JSTL, there is nothing to stop you doing so from within your tag files.

The values you supply to tag file attributes can be dynamic in nature—you are not limited to static string values. Having said that, there is an attribute you can use with the attribute action called rtexprvalue—set this to false if you want to turn off this feature and use just static values.

Editor's Picks