The JSTL expression language is one of JSTL's most exciting features. If you implement JSP custom actions, you may be wondering how you can use the expression language for your own action attributes. You can incorporate the expression language into your custom actions, but for JSTL 1.0, you cannot do it portably. Here's why: The JSP expert group is ultimately responsible for the expression language, which will be incorporated into JSP 2.0. When JSTL 1.0 was finalized ”well before JSP 2.0 ”the JSP expert group had not yet defined a portable API for accessing the expression language. Because of that scheduling mismatch, until JSP 2.0 you will have to make do with writing code specific to the JSTL Reference Implementation. [15] JSP 2.0 will define a portable mechanism for accessing the expression language. [16]
This section shows you how to implement a custom action that permits EL expressions for an attribute using the JSTL 1.0 Reference Implementation.
Figure 2-14 shows a JSP page that uses a custom action to display values contained in a map. The maps shown in Figure 2-14 are accessed through some of the JSTL implicit objects discussed in "Implicit Objects" on page 64. Figure 2-14. A Custom Action That Processes EL Expressions for Its Attribute
The JSP page shown in Figure 2-14 is listed in Listing 2.27. Listing 2.27 index.jsp<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head> <title>Using the EL for Custom Action Attributes</title> </head> <body> <%@ taglib uri='WEB-INF/core-jstl.tld' prefix='core-jstl' %> <font size='5'>Request Parameters:</font> <p> <core-jstl:showMap map='${param}'/> <p><font size='5'>Request Headers:</font> <p> <core-jstl:showMap map='${header}'/> <p><font size='5'>Cookies:</font> <p> <core-jstl:showMap map='${cookie}'/> </body> </html> The preceding JSP page uses a custom action ”<core-jstl:showMap> ”that displays values stored in a map. That custom action is unspectacular except for one feature: you can use the expression language to specify the action's map attribute. Let's see how that custom action is implemented. First, we must specify a tag library descriptor (TLD) that defines the library and its lone action. That TLD, specified in WEB-INF/core-jstl.tld , is listed in Listing 2.28. Listing 2.28 WEB-INF/core-jstl.tld<?xml version="1.0" encoding="ISO-8859-1" ?> <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "http://java.sun.com/dtds/web-jsptaglibrary_1_2.dtd"> <taglib> <tlib-version>1.0</tlib-version> <jsp-version>1.2</jsp-version> <short-name>JSTL Examples</short-name> <description> A custom action that shows how to incorporate the JSTL expression language for custom action attributes </description> <tag> <name>showMap</name> <tag-class>tags.ShowMapAction</tag-class> <body-content>JSP</body-content> <description> This action shows the values stored in a map </description> <attribute> <name>map</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute> </tag> </taglib> The preceding TLD specifies the name of the action ” showMap ”and the action's one required attribute, named map . The TLD also specifies the action's tag handler: tags.ShowMapAction , which is listed in Listing 2.29. The preceding tag handler for the <core-jstl:showMap> action uses the Apache expression evaluator manager to evaluate the value specified for the map attribute with the setMap method. You pass the ExpressionEvaluatorManager . evaluate method the attribute's name, the expression specified for that attribute, the type that you expect the attribute to be, a reference to the tag handler and its page context. That method evaluates the expression and returns the appropriate object. Listing 2.29 WEB-INF/classes/tags/ShowMapAction.javapackage tags; import java.util.*; import javax.servlet.jsp.*; import javax.servlet.jsp.tagext.*; // WARNING: non-standard class import org.apache.taglibs.standard.lang.support.Expression EvaluatorManager; public class ShowMapAction extends TagSupport { private String mapName; private Map map; public void setMap(String mapName) { this.mapName = mapName; } public int doStartTag() throws JspException { // EL expressions must be evaluated in doStartTag() // and not in attribute setter methods, because servlet // containers can reuse tags, and if an attribute takes a // string literal, the setter method might not be called // every time the tag is encountered. map = (Map)ExpressionEvaluatorManager.evaluate( "map", // attribute name mapName, // expression java.util.Map.class, // expected type this, // this tag handler pageContext); // the page context if(map == null) return SKIP_BODY; Iterator it = map.keySet().iterator(); JspWriter out = pageContext.getOut(); while(it.hasNext()) { Object key = it.next(), value = map.get(key); try { if(value instanceof String[]) { String[] strings = (String[])value; for(int i=0; i < strings.length; ++i) { out.println(strings[i]); } } else { out.println(key + "=" + value); } } catch(java.io.IOException ex) { throw new JspException(ex); } } return SKIP_BODY; } } |