Easy Custom Tags with Tag Files, Part 1 Blog

Version 2


    Two new features in JSP 2.0 deal with custom tag libraries. The first is the new javax.servlet.j sp.tagext.SimpleTaginterface, which simplifies the life-cycle of a tag handler. The second feature simplifies the whole process of writing tag extensions entirely. The latter is a radical change, I would say. For the first time, you don't need a tag library descriptor for your custom tags. Nor do you have to compile your tag handlers. Now, even those who don't understand Java can write custom tags. This article discusses tag files in detail. The first part of this article introduces tag files and presents a few examples. Part two will deal with the more advanced aspects of tag files and will discuss the packaging of tag handlers based on tag files. The sample application that is covered in this article can be downloaded here. To run the application, you need a JSP-2.0-compliant JSP container, such as Tomcat 5. You need to be familiar with JSP and tag extensions to understand this article well.

    Tag extensions are great. They allow you to write completely script-free JSP pages, thus promoting the separation of labor: page authors and Java programmers can work simultaneously, on the tasks that best suit them. However, writing custom tags is a tedious chore, involving writing and compiling a tag handler and defining a tag in the tag library descriptor. JSP 2.0 adds thejavax.servlet.jsp.tagext.SimpleTag interface, which you can use to write simple tag handlers. However,SimpleTag does not make the whole process simpler.

    Introduction to Tag Files

    Writing a traditional custom tag requires two steps:

    1. Writing and compiling a tag handler.
    2. Defining the tag that is associated with the tag handler.

    Tag files simplify the process. First, tag files don't need to be compiled. They are compiled as they are invoked. Also, tag files allow tag extensions to be written using only JSP syntax. This means someone who does not know Java can also write tag extensions!

    Secondly, a tag element in a tag library descriptor describes the name to be used in a JSP page to reference the custom action. Using tag files, the name of a custom action is the same as the tag file representing the action. Therefore, you don't need a tag library descriptor at all.

    Note: JSP containers may choose to compile tag files into Java tag handlers, or interpret the tag files. For example, Tomcat 5 translates tag files into simple tag handlers whose classes implement thejavax.servlet.jsp.tagext.SimpleTag interface.

    A tag file looks like a JSP page. It can have directives, scripts, EL expressions, and standard and custom tags. A tag file has the .tag or .tagx extension and can also include other files that contain a common resource. An include file for a tag file has a .tagf extension.

    To work, tag files must be placed in the WEB-INF/tagsdirectory under your application directory or a subdirectory under it. Just like tag handlers, tag files can also be packaged.

    A number of implicit objects are available from inside of a tag file. You can access these objects from a script or an EL expression. Table 1 lists all of the implicit objects available in a tag file.

    Table 1. The implicit objects


    Note that these implicit objects are similar to those available in a JSP page.

    Your First Tag File

    This section shows how easy it is to write a tag file and use it. The example consists of one tag file and one JSP page that uses the tag file. The directory structure of the application is depicted in Figure 1.

    Figure 1
    Figure 1. The directory structure

    The tag file is called firstTag.tag and looks like this:

    <%@ tag import="java.util.Date" import="java.text.DateFormat"%> <% DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.LONG); Date now = new Date(System.currentTimeMillis()); out.println(dateFormat.format(now)); %>

    As you can see in the above listing, a tag file looks similar to a JSP page. The firstTag.tag file has a tag directive with two import attributes and some script. The output of this tag file is the current date in long format. To use this tag file as a tag extension, all you need to do is save it in the WEB-INF/tagsdirectory of your application. The tag file name is important because it indicates the tag name. Therefore, for the tag file with the name firstTag.tag, the tag name will befirstTag.

    Here's the firstTagTest.jsp page that uses thefirstTag.tag file.

    <%@ taglib prefix="easy" tagdir="/WEB-INF/tags" %> Today is <easy:firstTag/>

    You can invoke the firstTagTest.jsp page using this URL (assuming you use Tomcat 5 on port 8080):


    The result is shown in Figure 2.

    Figure 2
    Figure 2. Tag file in action

    Tag File Directives

    Just like JSP pages, tag files can use directives to control how the JSP container will compile or interpret the tag files. Tag file directives have the same syntax as the directives you can use in JSP pages:

    <%@ directive (attribute="value")* %>

    The asterisk (*) means that what is enclosed in the brackets can be repeated zero or more times. The syntax can be rewritten in a more informal way, as follows:

    <%@ directive attribute1="value1" attribute2="value2" ... %>

    Attributes must be enclosed by single quotes or double quotes. White space after the opening <%@ and before the closing %> is not required, but can improve readability.

    Some of the directives you can use in a tag file are the same as those for JSP pages, except that you don't have a page directive. Instead of the page directive, you have the tagdirective. Also, in tag files, there are two more directives:attribute and variable. Table 2 lists all of the directives that can appear in a tag file.

    Table 2. Tag file directives

    tagThis directive is similar to the page directive for JSP pages.
    includeUse this directive to include other resources from the tag file.
    taglibUse this directive to use a custom tag library from inside of the tag file.
    attributeUse this directive to declare an attribute in a tag file.
    variableUse this directive to define a variable that you can expose to the calling JSP page.

    Each of the directives is given below.

    The tag Directive

    The tag directive is similar to thepage directive you can use in a JSP page. Here is the syntax of the tag directive:

    <%@ tag (attribute="value")* %>

    The syntax can be expressed in the following more informal form:

    <%@ tag attribute1="value1" attribute2="value2" ... %>

    The list of attributes for the tag directive is given in Table 3. Note that all tag directive attributes are optional.

    Table 3. The tag directive's attributes

    display-nameA short name to be displayed by an XML tool. The default value is the tag filename, without the .tag extension.
    body-contentThe information about the body content of this tag. The value can be empty, tagdependent, orscriptless (default).
    dynamic-attributesIndicates support for dynamic attributes. The value identifies a scoped attribute in which to place a Map containing the names and values of the dynamic attributes passed during this invocation.
    small-iconA context-relative path (or a path relative to the tag source file) of a small image file to be used by XML tools. You don't normally use this attribute.
    large-iconA context-relative path, or a path relative to the tag source file, of an image containing a large icon to be used by XML tools. You don't normally use this attribute, either.
    descriptionA string describing this tag.
    exampleAn informal description of an example of a use of this action.
    languageThe scripting language used in the tag file. The value for this attribute for the current version of JSP must be"java".
    importUsed to import a class or an interface or all members of a package. The same as the import attribute in the page directive.
    pageEncodingDescribes the character encoding for this tag file. The value is of the form CHARSET, which must be the IANA name for a character encoding. This attribute is the same as thepageEncoding attribute of the page directive.
    isELIgnoredIndicates whether EL expressions are ignored or evaluated. The default value for this attribute is false, which means EL expressions are evaluated. This attribute is the same as theisELIgnored attribute of the page directive.

    Except for the import attribute, all other attributes can only appear once within a tag directive or in multiple tag directives of the same tag file. For example, the following tag file is invalid because the body-contentattributes appear more than once in multiple tag directives:

    <%@ tag display-name="Your first tag file" body-content="scriptless" %> <%@ tag body-content="empty" %>

    The following is a valid tag directive because theimport attribute can appear as many times as desired.

    <%@ tag import="java.util.Enumeration" import="java.util.Iterator" %>

    The following is also valid:

    <%@ tag body-content="empty" import="java.util.Enumeration" %> <%@ tag import="java.sql.*" %>

    The include Directive

    The include directive for a tag file is the same as the include directive for a JSP page. You use this directive to include the contents of other files in the current tag file. It is useful when you have a common source that will be used by more than one tag file. The included source can be static (such as an HTML file) or dynamic (another tag file). As an example, theincludeDemoTag.tag page below shows a tag file that includes one static resource (included.html) and one dynamic resource (included.tagf).

    This tag file shows the use of the include directive. The first include directive demonstrates how you can include a static resource called included.html. <br/> Here is the content of included.html: <%@ include file="included.html" %> <br/> <br/> The second include directive includes another dynamic resource: included.tagf. <br/> <%@ include file="included.tagf" %>

    The included.html file looks like this:

    <table> <tr>   <td><b>Menu</b></td> </tr> <tr>   <td>CDs</td> </tr> <tr>   <td>DVDs</td> </tr> <tr>   <td>Others</td> </tr> </table>

    The included.tagf file looks like this (note that the recommended extension for a tag file is.tagf):

    <% out.print("Hello from included.tagf"); %>

    To test the includeDemoTag.tag file, use theincludeDemoTagTest.jsp page:

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

    You can invoke the includeDemoTagTest.jsp page with the following URL:


    The result is shown in Figure 3.

    Figure 3
    Figure 3. Including other resources from a tag file

    The taglib Directive

    You can use other custom actions from your tag file using thetaglib directive. The taglib directive has the following syntax:

    <%@ taglib uri="tagLibraryURI" prefix="tagPrefix" %>

    The uri attribute specifies an absolute or relative URI that uniquely identifies the tag library descriptor associated with this prefix.

    The prefix attribute defines a string that will become the prefix to distinguish a custom action.

    With a taglib directive, you then can use a custom tag of the following format for a custom tag that does not have a content body:


    Or, you can use the following format for a custom tag that has a content body:


    As an example, consider the taglibDemo.tag file:

    <%@ taglib prefix="simple" tagdir="/WEB-INF/tags" %> The server's date: <simple:firstTag/>

    It uses the firstTag.tag file from the first example to display the server's date. The taglibDemo.tag file is used in the taglibDemoTest.jsp page:

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

    You can invoke this JSP page using the following URL:


    The result is shown in Figure 4.

    Figure 4
    Figure 4. Using the taglib directive in a tag file

    The taglib directive in a tag file is the same as the taglib directive in a JSP page.

    The attribute Directive

    The attribute directive supports the use of attributes in a tag file. It is equivalent to theattribute element in a tag library descriptor. Here is the syntax of the attribute directive:

    <%@ attribute (attribute="value")* %>

    The syntax can be expressed in the following more informal form:

    <%@ attribute attribute1="value1" attribute2="value2" ... %>

    The list of attributes for the attribute directive is given in Table 4. Note: The only required attribute for theattribute directive is the name attribute.

    Table 4. The attributes for the attributedirective

    nameThe name for the attribute that this tag file accepts. The value for the name attribute must be unique throughout the current tag file.
    requiredIndicates whether this attribute is required. The value can be true or false (default).
    fragmentIndicates whether this attribute is a fragment to be evaluated by the tag handler, or a normal attribute to be evaluated by the container prior to being passed to the tag handler. The value is either true or false (default). The value is true if this attribute is to be evaluated by the tag handler.
    rtexprvalueSpecifies whether the attribute's value may be dynamically calculated at runtime by a scriplet expression. The value is either true (default) or false.
    typeThe type of the attribute value. The default isjava.lang.String.
    descriptionThe description of this attribute.

    As an example, consider the encode.tag file below, which can be used to HTML encode a String. This encode tag defines one attribute, input, which is of typejava.lang.String.

    <%@ attribute name="input" required="true" %> <%! private String encodeHtmlTag(String tag) { if (tag==null) return null; int length = tag.length(); StringBuffer encodedTag = new StringBuffer(2 * length); for (int i=0; i<length; i++) { char c = tag.charAt(i); if (c=='>') encodedTag.append("<"); else if (c=='>') encodedTag.append(">"); else if (c=='&') encodedTag.append("&"); else if (c=='"') encodedTag.append("""); else if (c==' ') encodedTag.append(" "); else encodedTag.append(c); } return encodedTag.toString(); } %> <%=encodeHtmlTag(input)%>

    To test the encode.tag file, use theencodeTagTest.jsp page:

    <%@ taglib prefix="easy" tagdir="/WEB-INF/tags" %> <easy:encode input="<br/> means changing line"/>

    You can invoke the encodeTagTest.jsp page using the following URL:


    The result is shown in Figure 5.

    Figure 5
    Figure 5. Using attributes in a tag file


    In this first part of the series, you have seen how tag files alleviate the problem of writing tag extensions. In fact, writing tag files is easy, because you don't need a tag library descriptor or compile the tag handler. Deployment is also simple: you just need to copy the tag files under the WEB-INF/tags directory of your application. Part two of this article will discuss the more advanced aspects of tag files, including the<jsp:doBody> and <jsp:invoke>standard actions that are new to JSP 2.0.