Showing posts with label taglib. Show all posts
Showing posts with label taglib. Show all posts

Tuesday, October 27, 2009

Tag Reuse in JSPs

One thing that's always puzzled me about JSP taglibs is the mechanics of tag reuse — what happens when you invoke the same tag twice on a page. The Tag JavaDoc says the following:

After the doEndTag invocation, the tag handler is available for further invocations (and it is expected to have retained its properties).

This statement sent up a bunch of red flags when I first read it. And it's done the same for others: I've seen tag implementations that explicitly reset all attributes in doEndTag(). But if this was the required implementation, I'd expect to see it mentioned in the J2EE tutorial or sample code, and it isn't.

Moreover, the description makes no sense: you can't build a software system on components that will render arbitrary values depending on where they're invoked. My first hint came from examining the Java code generated by Tomcat:

private org.apache.jasper.runtime.TagHandlerPool _jspx_tagPool_prodList_form_visible_userId_operation_name_listName_htmlId_format;
private org.apache.jasper.runtime.TagHandlerPool _jspx_tagPool_prodList_form_visible_userId_timeout_operation_name_listName_htmlId_format;

Those are pretty long names. And interestingly, they include the parameters used in the tags. And they're different. That led me back to the JSP specifications, with a more focused search. And on page 2-51, we see the rules:

The JSP container may reuse classic tag handler instances for multiple occurrences of the corresponding custom action, in the same page or in different pages, but only if the same set of attributes are used for all occurrences.

I'd love to know the rationale behind this — and whether it was intentional or a “retro-specification” to cover decisions made in the reference implementation (Tomcat). To me, it seems like premature optimization: assume that it's expensive to instantiate a tag handler or set its attributes, so go to extra effort to pool those instances. If, instead, the specification required handlers to be explicitly instantiated per use it would drive developers toward lightweight handlers that collaborate with external services. Which in my opinion is a far better way to write them.

Monday, October 12, 2009

Building a Wishlist Service: HTML Forms

Back to the wishlist service, and it's time to look at the client side. In particular, the mechanism that the client uses to submit requests. XML on the browser is, quite simply, a pain in the neck. While E4X is supposed to be a standard, support for it is limited. Microsoft, as usual, provides its own alternative. Since XML is a text format, you could always construct strings yourself, but there are enough quirks that this often results in unparseable XML.

Against the pain of XML, we have HTML forms. They've been around forever, work the same way in all browsers, and don't require JavaScript. They're not, however, very “Web 2.0 friendly”: when you submit a form, it reloads the entire page. Filling this gap, the popular JavaScript libraries provide methods to serialize form contents and turn them into an AJAX request. As long as you're sending simple data (ie, no file uploads), these libraries get the job done.

To simplify form creation, I created some JSP tags. This provides several benefits, not least of which is that I can specify required parameters such as the user ID and wishlist name. I also get to use introspection and intelligent enums to build the form: you specify an “Operation” value in the JSP, and the tag implementation can figure out whether it needs a GET or a POST, what parameters need to go on the URL, and what fields need to go in the body.

One of the more interesting “learning experiences” was the difference between GET and POST forms. With the former, the browser will throw away any query string provided in the form's action attribute, and build a new string from the form's fields. With the latter, the query string is passed untouched. In my initial implementation I punted, and simply emitted everything as input: the server didn't care, because getParameter(), doesn't differentiate between URL and body. This offended my sense of aesthetics however, so I refactored the code into a class that would manage both the action URL and a set of body fields. Doing so had the side benefit that I could write out-of-container unit tests for all of the form generation code.

The other problem came from separating the form's markup from the JavaScript that makes it work. This is current “best practice,” and I understand the rationale behind it, but it makes me uncomfortable. In fact, it makes me think that we're throwing away lessons learned about packaging over the last 30 years. But that's another post.

Tuesday, April 7, 2009

JSP tag handlers can't have an attribute named “class”

Recently I've been implementing some tag handlers that emit HTML. In them, I want to carry through some of the standard HTML attributes such as id and class. And I've discovered that Tomcat is quite happy to accept the following TLD entry, but at runtime complains that it's unable to find a setter method for the attribute:

<attribute>
  <name>class</name>
  <rtexprvalue>true</rtexprvalue>

  <type>java.lang.String</type>
</attribute>

Sun provides a schema definition for the JSP taglib deployment descriptor, and it defines the type tld-attributeType for attribute declarations. Looking at that type definition, we see this:

<xsd:element name="name"
   type="j2ee:java-identifierType"/>

And jumping to the common definitions schema, here's the definition of java-identifierType:

<xsd:complexType name="java-identifierType">
  <xsd:annotation>
    <xsd:documentation>

        The java-identifierType defines a Java identifier.
        The users of this type should further verify that
        the content does not contain Java reserved keywords.

    </xsd:documentation>
  </xsd:annotation>

  <xsd:simpleContent>
    <xsd:restriction base="j2ee:string">
      <xsd:pattern value="($|_|\p{L})(\p{L}|\p{Nd}|_|$)*"/>
    </xsd:restriction>
  </xsd:simpleContent>

</xsd:complexType>

Did you read the comment? That users of the type should perform keyword validation?!? I couldn't believe it, until I turned to the XML Schema docs and discovered that there's no way to exclude values: the enumeration facet enumerates legal values only.

So, two lessons to draw from this: first, XML schema is not only complex but incomplete, and second, you can't use class as a JSP tag attribute. Or any other Java keyword for that matter. At least not in a servlet container developed by people who have read the schema docs, because this restriction is not mentioned in the JSP specification text.

My solution? The ugly but descriptive htmlClass.

(originally posted on my website 19 Nov 08)