Call JavaBean methods from JSP 2.0 pages

Develop custom tags with dynamic attributes

The new JavaServer Pages (JSP) version incorporates the expression language (EL) introduced by the JSP Standard Tag Library (JSTL) to let Web designers produce scriptless JSP pages that don't contain Java code. Since JSP 2.0 provides backward compatibility to JSP 1.x, you may still include Java snippets in your pages, but tag handlers and JavaBean components are much better places for Java-based functionality.

JSP 2.0 provides new features for tag handlers such as dynamic attributes, the Simple Invocation Protocol, and .tag files. You still use the old JSP 1.0 standard actions for creating JavaBean instances and setting their properties, but now you can access bean properties, request parameters, and JSP attributes/variables with the new expression language.

All those JSP technology improvements let you achieve the goal of separating the JSP/HTML markup from the Java code. One thing is missing, however. JSP 2.0 has no syntax for calling a public nonstatic JavaBean method from a scriptless JSP page. This article solves that issue by providing a JSP 2.0 simple tag with dynamic attributes.

Note: You can download this article's source code from Resources.

Expression language needed

Suppose you have a java.util.List instance you must present as an HTML list. Here is a quick solution based on JSP 1.x:

<UL>
<%
    Iterator iterator = list.iterator();
    while (iterator.hasNext()) {
        Object elem = iterator.next();
        if (elem == null)
            elem = "";
%>
        <LI> <%= elem %> </LI>
<%
    }
%>
</UL>

Existing JSP-based Web applications consist of Java code mixed with HTML markup like the above code fragment. Maintaining hundreds of pages like that can be a nightmare if you have separate Java development and Web design teams. The solution is to move the Java code into tag libraries so that developers can do their jobs without pasting Java code within Webpages and designers can edit their Webpages without worrying about breaking the Java code.

However, JSP 1.x has several problems that don't let you easily develop scriptless JSP pages. Until recently, no standard method existed for accessing Java objects from a JSP page without using Java code. In addition, coding tag handler classes wasn't as simple as it could have been.

The following lines of code are based on JSTL 1.0, which can be used with JSP 1.2. The <c:forEach> tag iterates over the elements of the given list and exports the elem variable for each element. Instead of declaring elem as a local variable, the <c:forEach> tag creates a page attribute with pageContext.setAttribute(). This attribute's value is printed with JSTL's <c:out> tag:

<UL>
<c:forEach var="elem" items="${list}">
    <LI> <c:out value="${elem}"/> </LI>
</c:forEach> 
</UL>

JSTL provides standard tags for processing XML documents and accessing relational databases along with formatting tags, internationalization tags, conditional tags, iterator tags, URL-related tags, and other general-purpose tags. JSTL has solved many of JSP 1.x's problems with the help of an expression language that allows you to access Java objects from JSP pages without using Java code. For example, instead of looking for an attribute or accessing a request parameter with:

<%= pageContext.findAttribute("a") %>
<%= request.getParameter("p") %>

you may now use:

${a}
${param.p}

You can access the JSP page context objects, page/request/session/ application attributes (also known as JSP variables), JavaBean properties, collection elements, request parameters, initialization parameters, cookies, and HTTP headers.

With JSP 1.2, the expression language is available only to JSTL-based applications and tag libraries. JSP 2.0 makes the EL available to all JSP applications and all tag libraries (including the old taglibs designed for JSP 1.x). JSP 2.0 also simplifies tag library development, as you'll see later in this article.

Since its first version, JSP has provided standard tags for using JavaBeans in JSP pages. You can create or find JavaBean instances with <jsp:useBean>, and then you can get and set their properties with <jsp:getProperty> and <jsp:setProperty>. With JSP 2.0, you may also get the value of a property with:

${bean.property}

In addition to properties, JavaBean components have public methods that often must be called from JSP pages. The remainder of this article will present three ways for calling JavaBean methods without using Java code. One is based on the JSP 2.0 support for functions, which are EL constructs that allow you to call Java classes' static methods. Another solution uses custom tags that get the method parameters as tag attributes. The third way is based on a generic tag that lets you call any public method of any JavaBean class from a JSP page.

Use functions

The initial JSTL 1.0 EL lacked support for functions. The JSP 2.0 EL lets you call a Java class's public static method using the following syntax:

${prefix:methodName(param1, param2, ...)}

The JSP function must be declared in a tag library descriptor (TLD):

<function>
    <name>methodName</name>
    <function-class>className</function-class>
    <function-signature>
        returnType methodName(param1Type, param2Type, ...)
    </function-signature>
</function>

The Java class doesn't have to implement any special interface. The only requirement is to make the Java method public and static.

The TestBean class

The TestBean class has a public method named testMethod(), which is called from the JSP pages presented in the following sections. The JavaBean has three properties named text, number, and logic. These properties are modified by testMethod(), which returns a string containing the three properties' modified values:

package com.devsphere.articles.calltag;
public class TestBean {
    private String text;
    private int number;
    private boolean logic;
    public TestBean() {
        text = "";
        number = 0;
        logic = false;
    }
    public String getText() {
        return text;
    }
    public void setText(String text) {
        this.text = text;
    }
    public int getNumber() {
        return number;
    }
    public void setNumber(int number) {
        this.number = number;
    }
    public boolean getLogic() {
        return logic;
    }
    public void setLogic(boolean logic) {
        this.logic = logic;
    }
    public String testMethod(String text, int number, boolean logic) {
        setText(getText() + text);
        setNumber(getNumber() + number);
        setLogic(getLogic() || logic);
        StringBuffer buf = new StringBuffer();
        buf.append(getText());
        buf.append(' ');
        buf.append(getNumber());
        buf.append(' ');
        buf.append(getLogic());
        return buf.toString();
    }
}

The TestFunction class

Because the JSP 2.0 EL allows only calls to static methods, TestBean's testMethod() must be wrapped in a static method. The TestFunction class provides such a static wrapper that takes the same parameters as the bean method plus the bean object whose method must be called:

package com.devsphere.articles.calltag;
public class TestFunction {
    public static String testMethod(TestBean object,
            String text, int number, boolean logic) {
        return object.testMethod(text, number, logic);
    }
}

The compiled TestFunction.class file must be placed together with TestBean.class into the Web application's /WEB-INF/classes directory. As an alternative, the two classfiles can be packed in a jar file and stored in /WEB-INF/lib.

The TestFunction JSP

Before calling the testMethod() function, the TestFunction.jsp page must specify the function's prefix and the library's Uniform Resource Identifier (URI):

<%@ taglib prefix="tf" uri="http://devsphere.com/articles/calltag/TestFunction.tld"%>

The <jsp:useBean> tag creates an instance of the TestBean class:

<jsp:useBean id="obj" class="com.devsphere.articles.calltag.TestBean"/>

The testMethod() function is called twice. The first call gets some constant parameters, while the second call gets the values of the bean properties as parameters:

<HTML>
<BODY>
${tf:testMethod(obj, "abc", 123, true)}
<HR>
${tf:testMethod(obj, obj.text, obj.number, obj.logic)}
</BODY>
</HTML>

The TestFunction.jsp page produces the following HTML output:

<HTML>
<BODY>
abc 123 true
<HR>
abcabc 246 true
</BODY>
</HTML>

The TestFunction TLD

As mentioned earlier, the JSP function must be declared in a tag library descriptor. The TestFunction.tld file defines some version number, the tf short name used in JSP pages as prefix for testMethod(), the library's URI, the function's name, the name of the class containing the static method, and the method's signature. The URI doesn't have to point to an existing Web resource, but it must be unique. You may not use the same URI for two different tag libraries.

Here is the TestFunction.tld file's content:

<?xml version="1.0" encoding="UTF-8" ?>
<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee web-jsptaglibrary_2_0.xsd"
    version="2.0">
    <tlib-version>1.0</tlib-version>
    <short-name>tf</short-name>
    <uri>http://devsphere.com/articles/calltag/TestFunction.tld</uri>
    <function>
        <name>testMethod</name>
        <function-class>
            com.devsphere.articles.calltag.TestFunction
        </function-class>
        <function-signature>
            java.lang.String testMethod(
                com.devsphere.articles.calltag.TestBean,
                java.lang.String, int, boolean)
        </function-signature>
    </function>
</taglib>

The TestFunction.tld file must be placed into the Web application's /WEB-INF directory. The same directory also contains the web.xml application descriptor, which declares the library within a <taglib> element. The URI that identifies the library in JSP pages and the TLD file's location are specified within two separate XML elements, <taglib-uri> and <taglib-location>:

<taglib>
    <taglib-uri>
        http://devsphere.com/articles/calltag/TestFunction.tld
    </taglib-uri>
    <taglib-location>
        /WEB-INF/TestFunction.tld
    </taglib-location>
</taglib>

Use custom tags

Tag libraries were introduced by JSP 1.1, which defined the Tag and BodyTag interfaces. JSP 1.2 added IterationTag and support for catching exceptions. These interfaces have handler methods such as doStartTag(), doInitBody(), doAfterBody(), and doEndTag(). Once you understand how these methods should be implemented, it's easy to build tag libraries. However, many developers viewed JSP 1.x's tag-handling mechanism as unnecessarily complex.

JSP 2.0 introduced a much simpler tag-handling protocol. If you extend the SimpleTagSupport class, you just have to implement the doTag() method for handling a JSP tag.

The TestMethodTag class

The TestMethodTag.jsp page calls the testMethod() JavaBean method using the following syntax:

<tm:testMethod object="..." text="..." number="..." logic="..."/>

When the application server translates the JSP page into a servlet, the above tag is replaced with a Java code fragment that calls the methods of a TestMethodTag instance created for handling the tag.

The tag handler extends the JSP 2.0 API's SimpleTagSupport class and defines one field for each attribute. These fields will maintain the tag attributes' values:

package com.devsphere.articles.calltag;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.SimpleTagSupport;
import java.io.IOException;
public class TestMethodTag extends SimpleTagSupport {
    private TestBean object;
    private String text;
    private int number;
    private boolean logic;

For each tag attribute, there must be a set method, which gets the attribute value and stores it in a field so that the tag handler can use it later:

    public void setObject(TestBean object) {
        this.object = object;
    }
    public void setText(String text) {
        this.text = text;
    }
    public void setNumber(int number) {
        this.number = number;
    }
    public void setLogic(boolean logic) {
        this.logic = logic;
    }

After setting the tag handler's attributes, the Java fragment (resulting from the JSP tag) invokes the tag handler's doTag() method, which calls the bean method. The doTag() method prints the string value returned by testMethod(). Therefore, the JSP output contains the returned value:

    public void doTag() throws JspException, IOException {
        String ret = object.testMethod(text, number, logic);
        JspWriter out = getJspContext().getOut();
        out.println(ret);
    }
}

The TestMethodTag2 class

Suppose you want to use the value returned by the bean method in a JSP. For example, you might have to pass it as an attribute value to another tag. Or, you might want to control its output in the JSP page:

<tm:testMethod2 object="..." text="..." number="..." logic="...">
... ${ret} ...
</tm:testMethod2>
1 2 3 Page
Recommended
Join the discussion
Be the first to comment on this article. Our Commenting Policies
See more