The Java EE 5 Tutorial

Tag Handlers for Tags with Attributes

This section describes how to define attributes for a tag handler and how to validate attribute values.

Defining Attributes in a Tag Handler

For each tag attribute, you must define a set method in the tag handler that conforms to the JavaBeans architecture conventions. For example, consider the tag handler for the JSTL c:if tag:

<c:if test="${Clear}">

This tag handler contains the following method:

public void setTest(boolean test) {
    this.test = test;
}

As shown by the preceding example, the name of the attribute must match the name of the set method.

Attribute Validation

The documentation for a tag library should describe valid values for tag attributes. When a JSP page is translated, a web container will enforce any constraints contained in the TLD element for each attribute.

The attributes passed to a tag can also be validated at translation time using the validate method of a class derived from TagExtraInfo. This class is also used to provide information about variables defined by the tag (see TagExtraInfo Class).

The validate method is passed the attribute information in a TagData object, which contains attribute-value tuples for each of the tag’s attributes. Because the validation occurs at translation time, the value of an attribute that is computed at request time will be set to TagData.REQUEST_TIME_VALUE.

The tag <tt:twa attr1="value1"/> has the following TLD attribute element:

<attribute>
    <name>attr1</name>
    <required>true</required>
    <rtexprvalue>true</rtexprvalue>
</attribute>

This declaration indicates that the value of attr1 can be determined at runtime.

The following validate method checks whether the value of attr1 is a valid Boolean value. Note that because the value of attr1 can be computed at runtime, validate must check whether the tag user has chosen to provide a runtime value.

public class TwaTEI extends TagExtraInfo {
    public ValidationMessage[] validate(TagData data) {
        Object o = data.getAttribute("attr1");
        if (o != null && o != TagData.REQUEST_TIME_VALUE) {
            if (((String)o).toLowerCase().equals("true") ||
                 ((String)o).toLowerCase().equals("false") )
                 return null;
            else
                return new ValidationMessage(data.getId(),
                    "Invalid boolean value.");
        }
        else
            return null;
    }
}

Setting Dynamic Attributes

Simple tag handlers that support dynamic attributes must declare that they do so in the tag element of the TLD (see Declaring Tag Handlers). In addition, your tag handler must implement the setDynamicAttribute method of the DynamicAttributes interface. For each attribute specified in the tag invocation that does not have a corresponding attribute element in the TLD, the web container calls setDynamicAttribute, passing in the namespace of the attribute (or null if in the default namespace), the name of the attribute, and the value of the attribute. You must implement the setDynamicAttribute method to remember the names and values of the dynamic attributes so that they can be used later when doTag is executed. If the setDynamicAttribute method throws an exception, the doTag method is not invoked for the tag, and the exception must be treated in the same manner as if it came from an attribute setter method.

The following implementation of setDynamicAttribute saves the attribute names and values in lists. Then, in the doTag method, the names and values are echoed to the response in an HTML list.

private ArrayList keys = new ArrayList();
private ArrayList values = new ArrayList();

public void setDynamicAttribute(String uri,
     String localName, Object value ) throws JspException {
    keys.add( localName );
    values.add( value );
}

public void doTag() throws JspException, IOException {
    JspWriter out = getJspContext().getOut();
    for( int i = 0; i < keys.size(); i++ ) {
        String key = (String)keys.get( i );
        Object value = values.get( i );
        out.println( "<li>" + key + " = " + value + "</li>" );
    }
}

Setting Deferred Value Attributes and Deferred Method Attributes

For each tag attribute that accepts a deferred value expression or a deferred method expression, the tag handler must have a method to access the value of the attribute.

The methods that access the value of a deferred value attribute method must accept a ValueExpression object. The methods that access the value of a deferred method attribute must accept a MethodExpression object. These methods take the form setXXX, where XXX is the name of the attribute.

The following example shows a method that can be used to access the value of a deferred value attribute called attributeName:

private javax.el.ValueExpression attributeName = null;

public void setAttributeName(
    javax.el.ValueExpression attributeName)
 {
    this.attributeName = attributeName;
}

Deferred value attributes and deferred method attributes are primarily used by JavaServer Faces technology. See Getting the Attribute Values for an example of creating a tag handler that processes these attributes for a JavaServer Faces application.

If you have an attribute that is both dynamic and deferred (meaning that the tag attribute definition accepts a deferred expression and has rtexprvalue set to true), then the setX method that accesses this value must accept an Object instance and test if the Object instance is a deferred value expression, as shown in this pseudocode:

public void setAttr(Object obj) {
    if (obj instance of ValueExpression) {
        // this is a deferred expression
    else {
        // this is an rtexpression
    }
}