There are some common misconceptions on how tag handlers work, and what methods get called at what time and when. This document contains a collection of pitfalls you can encounter when writing tag libraries.
release()
Misconception: release() gets called at the end of a page. This is not true! Some idiot writing JSP 1.2 decided that release should only be called just before the tag handler is released to the garbage collector! This means that when a tag handler gets cached by a container (like Tomcat's Jasper engine does by default) the release() method gets called at most once(!) even if the tag gets reused many times on several pages! There is currently NO failsafe way to clean up your tag handler between invocations. The best you can do is to cleanup at your own known exit points. This clearly sucks, but what can you do..
BodyTag's setBodyContent()
Misconception: setBodyContent() always gets called for a tag. This is not true: some braindead idiot specified that it can be skipped when the contents of the tag is actually empty. The rationale was that the container could generate better code if this was true. That the tags needs to work like shit to work around this problem didn't enter their tiny minds: if a tag is bodyless but does generate content you need to find a workaround making the BodyTag interface useless for this kind of tag.
Tag sharing rules
Tag instances can be shared according to a rather odd set of rules. One of the most misunderstood rules is that a given tag handler is only ever used to implement another tag instance with the exact same set of attribute setters. Only the attribute name is part of this equation; the value is not! So if you have the tag instances:
<t:grub a="10" b="20"/>
<t:grub a="90" c="10" />
<t:grub a="90" b="20"/>
this uses at least two separate Tag instances: the first one for line 1 and 3 (same set of attributes) and the second one for line 2. In addition you need to remember that it is not guaranteed that the setter for an attribute is called again if a tag handler is reused! Because the value of attribute "b" has not changed for line 1 and 3 a container is free to call the setter only once: at line 1!
Do's and dont's in Tag handlers
Never clear or change an attribute setter's value from within the tag handler!!! If the tag handler gets reused by a tag that has the same value as the previous time the tag was used then the container may decide not to call the setter again! Moronic but true.
Don't use release()! It hardly ever does what you want! There is one and only one use for release: if you allocate a resource that must be freed when the server exits but which stays the same over all pages the tag gets used in *then* you can use release() to release the object at server quit time (or cache clear time). Do not assume that release() gets called when the page exits - it does not!
If you really need to release a resource when the tag is no longer used use the TryCatchFinally interface.