views:

594

answers:

1

This test was prompted by reading a question on the Sun java forums and thought I would try it out. The JSP2.0 specification section JSP.13.8 contains an "Example Simple Tag Handler Scenario". I copy and pasted the code fragments and attempted to run it.

Environment: Apache Tomcat version 5.5.26 and 6.0.14 (tested on both) Java: 1.5

Code I am testing with: Jsp page:

<%@ taglib prefix="my" tagdir="/WEB-INF/tags" %>
<my:simpletag x="10">
<jsp:attribute name="y">20</jsp:attribute>
<jsp:attribute name="nonfragment">
Nonfragment Template Text
</jsp:attribute>
<jsp:attribute name="frag">
Fragment Template Text ${var1}
</jsp:attribute>
<jsp:body>
Body of tag that defines an AT_BEGIN
scripting variable ${var1}.
</jsp:body>
</my:simpletag>

And the tag file:

<%-- /WEB-INF/tags/simpleTag.tag --%>
<%@ attribute name="x" %>
<%@ attribute name="y" %>
<%@ attribute name="nonfragment" %>
<%@ attribute name="frag" fragment="true" %>
<%@ variable name-given="var1" scope="AT_BEGIN" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
Some template text.
<c:set var="var1" value="${x+y}"/>
<jsp:invoke fragment="frag" varReader="var1"/>
Invoke the body:
<jsp:doBody/>

This code is directly copied from the PDF copy of the JSP2.0 specification.
It is also available as part of the JSP-API here Minor change made - I changed the name of the tagfile from simpletag.tag to simpleTag.tag to match the invocation of it in the JSP.
I also tried copying from the PDF of the spec (adjusting quotes as necessary) - same result.

When I execute the page I end up with a standard 500 error Root cause: java.lang.ClassCastException: java.io.StringReader org.apache.jsp.tagVariableTest_jsp._jspService(tagVariableTest_jsp.java:62)

Line62 of the generated JSP turns out to be: var1 = (java.lang.String) _jspx_page_context.findAttribute("var1");

Ok, I can understand ClassCastException - it thinks that var1 should be a String, and the actual attribute is a StringReader. But why is it a StringReader? Where did the variable get created? And why is it attempting to do this assignment at all?

Can someone please point me in the right direction? What is wrong with the code/setup? Is this a known issue? I googled for it but couldn't seem to find anything.

Thanks, evnafets


Editing with resolution: The ClassCastException was being caused by the line in the tag:

<jsp:invoke fragment="frag" varReader="var1"/>

As mentioned here the varReader attribute specifies the attribute to store the evaluation result as a StringReader. The exception was caused by Tomcat generated code trying to retrieve the value of "var1" and cast it to a String. As a String is not a StringReader so, it raised an exception at that point.

I'm not sure if the coding error is they should have used the "var" instead of the "varReader" attribute, or they shouldn't have used either and just evaluated it as is. Removing that attribute completely prints out the fragment, and then the body both with the value of "var1":

Fragment Template Text 30. Invoke the body: Body of tag that defines an AT_BEGIN scripting variable 30

Making the attribute var="var1" executes the fragment, and stores the result to var1. The body is then evaluated with this new value of var1 resulting in:

Invoke the body: Body of tag that defines an AT_BEGIN scripting variable Fragment Template Text 30

Personally I think the first case makes more sense, but this code is presented as an example of the innerworkings, not best practice.
I still would have expected the example to compile/run in any case. I was fairly surprised when it didn't.

+2  A: 

From the syntax reference you can see that either var or varReader is

The name of a scoped attribute to store the result of the fragment invocation in

So I am afraid the sample code contains an error. If you need to write the result of jsp:invoke directly to the page you do not need to assign it to a var.

Can you try leaving out the "varReader" attribute?

Kees de Kooter
100% correct. Leaving out the varReader attribute resolved that issue.The code then threw a ClassCastException: java.lang.Long.That one is more easily traced/fixed as the addition in the EL expression resulted in a Long. Converting that to a string worked.
evnafets