views:

638

answers:

4

i just introduced a bug into my code because i seem to have misunderstood the jsp tag lifecycle. The tag worked like this before the bug: i pass the tag some collection as an attribute, and it displays it as a table. The collection was passed into the JSP from the controller.

after the bug: a removed the attribute which set the collection. instead, in the tag i check if the collection is null, and then grab it by name from the request (using a naming convention).

the thing that i didnt expect: after the collection was initially set in the tag, it would never become null on subsequent executions! it was still defined as an non-requred attribute in the TLD.

I expected the tag to not hold on to previous values between executions.

+1  A: 

so the answer is: the tag gets pooled into magical pool land, and is reused between executions. the tag spec says:

"Unspecified attributes/properties should not be set (using a setter method)."

mkoryak
+1  A: 

You answered the question yourself - it's pooled. See the tag tutorial for what to implement in java implementations, together with the page linked from there, containing the invocation sequence:

ATag t = new ATag();
t.setPageContext(...);
t.setParent(...);
t.setAttribute1(value1);
t.setAttribute2(value2);
t.doStartTag();
t.doEndTag();
t.release();

That is, re-initialize your tag instance in release()

Note that pooling probably is container dependent.

Olaf
A: 

Observation of Tomcat 6 suggests release() is only invoked when the container is shutting down. Tag handler instance members should clear instance state in doEndTag(). From the api doc:

"All instance state associated with this instance must be reset."

see TagSupport.doEndTag()

A: 

The short answer: You are not supposed to write to attribute properties yourself. By doing so, you make cleaning the state your responsibility.

For a longer answer, the JSP 2.0 Spec dictates the following (page 2-51):

  • Setters get called for all specified attributes of a specific occurrence of a tag
  • Setters are not called for omitted attributes (leaving default values intact and, in your case, an illegal value in the internal state)
  • Tag handlers may only be reused by occurrences with the same set of specified attributes

These three points together guarantee that attribute properties are always correctly initialized, while still retaining default values (defined in a constructor or a properties' declaration). In return, it only works on the assumption that only the container manipulates attribute properties (by calling the setters).

For the sake of completeness:

  • release() should not be used to reset internal state between calls of a tag handler. It is only guaranteed to be called before GC and should be used to free long-term resources.
  • If you want to initialize instance variables in doStartTag(), be careful not to overwrite attributes, because the setters have already been called by the container at this point.
  • doEndTag() should be safe to use for initialization because tags should never be reused in case of an exception (see page 2-54 [2])