Custom for loop tag

[nobr]Hi all,

I am trying to implement a custom "for loop tag". But it seems to me that there is a type conversion problem. I've tried many ways to fixed it but I still cannot get it to work. I've dug through my books, searched the internet and this forum but I can't found anythig useful. I am really lost now! Can anyone help me with this? Many many many thanks!!

loopTag.jsp

<%@ taglib prefix="myTag" uri="/WEB-INF/myTag.tld" %>

<%int num=5; %>

<myTag:loop index="i" count="<%=num%>">

body1here: i expr: <%=i%> i property: <jsp:getProperty name="i" property="value"/> <br>

</myTag:loop>

myTag.tld

<?xml version="1.0" encoding="ISO-8859-1" ?>

<!DOCTYPE taglib PUBLIC"-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN""http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">

<taglib>

<tlibversion>1.0</tlibversion>

<jspversion>1.1</jspversion>

<shortname>simple</shortname>

<tag>

<name>loop</name>

<tagclass>myTag.LoopTag</tagclass>

<bodycontent>JSP</bodycontent>

<info>for loop</info>

<attribute>

<name>index</name>

<required>true</required>

</attribute>

<attribute>

<name>count</name>

<required>true</required>

<rtexprvalue>true</rtexprvalue>

</attribute>

</tag>

</taglib>

LoopTag.java

package myTag;

import javax.servlet.jsp.*;

import javax.servlet.jsp.tagext.*;

import java.util.Hashtable;

import java.io.Writer;

import java.io.IOException;

publicclass LoopTagextends BodyTagSupport{

String index;

int count;

int i=0;

publicvoid setIndex(String index){

this.index=index;

}

publicvoid setCount(String count){

this.count=Integer.parseInt(count);

}

publicint doStartTag()throws JspException{

return EVAL_BODY_TAG;

}

publicvoid doInitBody()throws JspException{

pageContext.setAttribute(index, i);

i++;

}

publicint doAfterBody()throws JspException{

try{

if (i >= count){

bodyContent.writeOut(bodyContent.getEnclosingWriter());

return SKIP_BODY;

}

else{

pageContext.setAttribute(index, i);

}

i++;

return EVAL_BODY_TAG;

}

catch (IOException ex){

thrownew JspTagException(ex.toString());

}

}

}

Error message:

type Exception report

message

description The server encountered an internal error () that prevented it from fulfillingthis request.

exception

org.apache.jasper.JasperException: Unable to compileclassfor JSP

An error occurred at line: 4 in the jsp file: /loopTag.jsp

Generated servlet error:

The method setCount(String) in the type LoopTag is not applicablefor the arguments (int)

An error occurred at line: 5 in the jsp file: /loopTag.jsp

Generated servlet error:

i cannot be resolved

org.apache.jasper.compiler.DefaultErrorHandler.javacError(DefaultErrorHandler.java:84)

org.apache.jasper.compiler.ErrorDispatcher.javacError(ErrorDispatcher.java:328)

org.apache.jasper.compiler.JDTCompiler.generateClass(JDTCompiler.java:409)

org.apache.jasper.compiler.Compiler.compile(Compiler.java:288)

org.apache.jasper.compiler.Compiler.compile(Compiler.java:267)

org.apache.jasper.compiler.Compiler.compile(Compiler.java:255)

org.apache.jasper.JspCompilationContext.compile(JspCompilationContext.java:556)

org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:293)

org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:314)

org.apache.jasper.servlet.JspServlet.service(JspServlet.java:264)

javax.servlet.http.HttpServlet.service(HttpServlet.java:802)

note The full stack trace of the root cause is available in the Apache Tomcat/5.5.11 logs.

[/nobr]

[6404 byte] By [Welles@Vancouvera] at [2007-10-2 5:39:54]
# 1

Your tag needs to expose a variable.

[url http://java.sun.com/j2ee/1.4/docs/tutorial/doc/JSPTags6.html#wp90424]Declaring Tag Variables for Tag Handlers [/url]

[url http://java.sun.com/j2ee/1.4/docs/tutorial/doc/JSPTags7.html#wp90587]Tag Handlers for Tags That Define Variables [/url]

You need to add something like the following to the tld:

<variable>

<name-from-attribute>index</name-from-attribute>

<variable-class>java.lang.Integer</variable-class>

<declare>true</declare>

<scope>NESTED</scope>

</variable>

evnafetsa at 2007-7-16 1:50:15 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 2

Oh, it is complaining that <%= num%> does not evaluate to a String.

So either make the variable an Integer, or the expression something like <%= "" + num %> (cheap way out)

Maybe this is unwarranted, but why re-invent the wheel? JSTL includes a very useful forEach loop. Take a look at theirs, and see how they do it ;-)

evnafetsa at 2007-7-16 1:50:15 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 3

[nobr]> So either make the variable an Integer, or the

> wheel? JSTL includes a very useful forEach loop.

Thanks for replying me! I fixed the type conversion problem. And I am very close to finishing this tag except that I have problem accessing the index variable of the loop inside the loop.

Another problem is that the loop print out 5 times on the first execution, but only print out 1 time in the following executions. I can't figure out why it would do that.

Can any Custom Tag Expert/Genius help me with this "For-Loop" tag? This should be a piece of cake for you guys, but it is very confusing for a newbie like me. Many Thanks!!!

loopTag.jsp

<%@ taglib prefix="myTag" uri="/WEB-INF/myTag.tld" %>

<% int num=5; %>

<myTag:loop index="i" count="<%= num %>">

index : <myTag:printIndex></myTag:printIndex> <br>

</myTag:loop>

myTag.tld

<?xml version="1.0" encoding="ISO-8859-1" ?>

<!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN" "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">

<taglib>

<tlibversion>1.0</tlibversion>

<jspversion>1.1</jspversion>

<shortname>simple</shortname>

<tag>

<name>loop</name>

<tagclass>myTag.LoopTag</tagclass>

<bodycontent>JSP</bodycontent>

<info>for loop</info>

<attribute>

<name>index</name>

<required>true</required>

<rtexprvalue>true</rtexprvalue>

</attribute>

<attribute>

<name>count</name>

<required>true</required>

<rtexprvalue>true</rtexprvalue>

</attribute>

</tag>

<tag>

<name>printIndex</name>

<tagclass>myTag.LoopPrintTag</tagclass>

<bodycontent>JSP</bodycontent>

<info>for loop print</info>

</tag>

</taglib>

LoopTag.java

package myTag;

import javax.servlet.jsp.*;

import javax.servlet.jsp.tagext.*;

import java.util.Hashtable;

import java.io.Writer;

import java.io.IOException;

public class LoopTag extends BodyTagSupport {

String index;

int count;

int i=0;

public void setIndex(String index){

this.index=index;

}

public String getIndex(){

return String.valueOf(pageContext.getAttribute(index));

}

public void setCount(int count){

this.count=count;

}

public int doStartTag() throws JspException {

return EVAL_BODY_TAG;

}

public void doInitBody() throws JspException {

pageContext.setAttribute(index, i);

i++;

}

public int doAfterBody() throws JspException {

try {

if (i >= count) {

bodyContent.writeOut(bodyContent.getEnclosingWriter());

return SKIP_BODY;

}

else{

pageContext.setAttribute(index, i);

}

i++;

return EVAL_BODY_TAG;

}

catch (IOException ex) {

throw new JspTagException(ex.toString());

}

}

}

LoopPrintTag.java

package myTag;

import javax.servlet.jsp.*;

import javax.servlet.jsp.tagext.*;

import java.io.*;

import javax.servlet.*;

public class LoopPrintTag extends BodyTagSupport {

public int doStartTag() throws JspTagException {

LoopTag parent = (LoopTag)findAncestorWithClass(this, LoopTag.class);

if (parent == null) {

throw new JspTagException("print not inside loop");

}

return(EVAL_BODY_TAG);

}

public int doAfterBody() {

LoopTag parent = (LoopTag)findAncestorWithClass(this, LoopTag.class);

try {

JspWriter out = pageContext.getOut();

out.print(" i = " + parent.getIndex());

} catch(IOException ioe) {

System.out.println("Error in printTag: " + ioe);

}

return(SKIP_BODY);

}

}

Output: (first execution)

index :

index :

index :

index :

index :

Output: (following execution)

index :[/nobr]

Welles@Vancouvera at 2007-7-16 1:50:15 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 4
> > wheel? JSTL includes a very useful forEach loop.By the way, I looked at the JSTL forEach loop, it is very nice. But unfortunately, I am not allowed to use JSTL in this project, because the client server doesn't have JSTL installed.
Welles@Vancouvera at 2007-7-16 1:50:15 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 5
you need to reset your variable "i" in the doStartTag: i = 0;
evnafetsa at 2007-7-16 1:50:15 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 6
> you need to reset your variable "i" > in the doStartTag: i = 0;Nice, it works!!! Thank you so much!!But I am still struggling to access the "loop index " inside the loop. Can anyone give me some directions?
Welles@Vancouvera at 2007-7-16 1:50:15 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 7

> But I am still struggling to access the "loop index "

> inside the loop. Can anyone give me some directions?

Thank God! I finally figured out what I did wrong!

My print statement should be placed in the doStartTag() method.

Hope this can help somebody who encounters the same problem. :)

LoopPrintTag.java

package myTag;

import javax.servlet.jsp.*;

import javax.servlet.jsp.tagext.*;

import java.io.*;

import javax.servlet.*;

public class LoopPrintTag extends BodyTagSupport {

public int doStartTag() throws JspTagException {

LoopTag parent = (LoopTag)findAncestorWithClass(this, LoopTag.class);

if (parent == null) {

throw new JspTagException("print not inside loop");

}

else{

try {

JspWriter out = pageContext.getOut();

out.print(" i = " + parent.getIndex());

} catch(IOException ioe) {

System.out.println("Error in printTag: " + ioe);

}

}

return(SKIP_BODY);

}

}

Output:

index : i = 0

index : i = 1

index : i = 2

index : i = 3

index : i = 4

Welles@Vancouvera at 2007-7-16 1:50:15 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 8

[nobr]I took the custom for-loop one step further and now it can be nested with in other for-loop.

Hope this is the last time I have to reinvent the wheel. Now I REALLY apprecate JSTL!!

loopTag.jsp

<%@ taglib prefix="myTag" uri="/WEB-INF/myTag.tld" %>

<% int row = 5; %>

<% int col = 5; %>

<table border=0>

<myTag:loop index="i" count="<%= row %>">

<tr>

<myTag:loop index="j" count="<%= col %>">

<td>index: i=<myTag:printIndex parentLevel="2" /> j=<myTag:printIndex parentLevel="1" />, <br></td>

</myTag:loop>

</tr>

</myTag:loop>

</table>

myTag.tld

<?xml version="1.0" encoding="ISO-8859-1" ?>

<!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN" "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">

<taglib>

<tlibversion>1.0</tlibversion>

<jspversion>1.1</jspversion>

<shortname>simple</shortname>

<tag>

<name>loop</name>

<tagclass>myTag.LoopTag</tagclass>

<bodycontent>JSP</bodycontent>

<info>for loop</info>

<attribute>

<name>index</name>

<required>true</required>

<rtexprvalue>true</rtexprvalue>

</attribute>

<attribute>

<name>count</name>

<required>true</required>

<rtexprvalue>true</rtexprvalue>

</attribute>

</tag>

<tag>

<name>printIndex</name>

<tagclass>myTag.LoopPrintTag</tagclass>

<bodycontent>JSP</bodycontent>

<info>for loop print</info>

<attribute>

<name>parentLevel</name>

<required>true</required>

<rtexprvalue>true</rtexprvalue>

</attribute>

</tag>

</taglib>

LoopTag.java

package myTag;

import javax.servlet.jsp.*;

import javax.servlet.jsp.tagext.*;

import java.util.Hashtable;

import java.io.Writer;

import java.io.IOException;

public class LoopTag extends BodyTagSupport {

String index;

int count;

int i=0;

public void setIndex(String index){

this.index=index;

}

public String getIndex(){

return String.valueOf(pageContext.getAttribute(index));

}

public void setCount(int count){

this.count=count;

}

public int doStartTag() throws JspException {

i = 0;

return EVAL_BODY_TAG;

}

public void doInitBody() throws JspException {

pageContext.setAttribute(index, i);

i++;

}

public int doAfterBody() throws JspException {

try {

if (i >= count) {

bodyContent.writeOut(bodyContent.getEnclosingWriter());

return SKIP_BODY;

}

else{

pageContext.setAttribute(index, i);

}

i++;

return EVAL_BODY_TAG;

}

catch (IOException ex) {

throw new JspTagException(ex.toString());

}

}

}

LoopPrintTag.java

package myTag;

import javax.servlet.jsp.*;

import javax.servlet.jsp.tagext.*;

import java.io.*;

import javax.servlet.*;

public class LoopPrintTag extends BodyTagSupport {

private int parentLevel = 1;

public int doStartTag() throws JspTagException {

LoopTag parent = (LoopTag)findAncestorWithClass(this, LoopTag.class);

for(int i=1; i<parentLevel; i++){

parent = (LoopTag)findAncestorWithClass(parent, LoopTag.class);

}

if (parent == null) {

throw new JspTagException("print not inside loop");

}

else{

try {

JspWriter out = pageContext.getOut();

out.print(parent.getIndex());

} catch(IOException ioe) {

System.out.println("Error in printTag: " + ioe);

}

}

return(SKIP_BODY);

}

public void setParentLevel(int _parentLevel){

if(_parentLevel > 0){

parentLevel = _parentLevel;

}

}

}

Output:

index: i=0 j=0, index: i=0 j=1, index: i=0 j=2, index: i=0 j=3, index: i=0 j=4,

index: i=1 j=0, index: i=1 j=1, index: i=1 j=2, index: i=1 j=3, index: i=1 j=4,

index: i=2 j=0, index: i=2 j=1, index: i=2 j=2, index: i=2 j=3, index: i=2 j=4,

index: i=3 j=0, index: i=3 j=1, index: i=3 j=2, index: i=3 j=3, index: i=3 j=4,

index: i=4 j=0, index: i=4 j=1, index: i=4 j=2, index: i=4 j=3, index: i=4 j=4,[/nobr]

Welles@Vancouvera at 2007-7-16 1:50:15 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...