Our jsp pages are compiled at build time. If I turn on genStringAsCharArray optimization switch, in some cases there will be longer lines in the generated java code than the javac compiler can process. It provides the following error message: [javac] Compiling 1609 source files to d:\...\jspc\classes [javac] d:\...\jspc\src\org\apache\jsp\WEB_002dINF\..._005fAPP\pages\termsconditions\TermsAndConditions_005fms_005fMY_jsp.java:96: constant string too long
The genStringAsCharArray option affects the o.a.jasper.compiler.Generator.GenerateVisitor#visit(Node.TemplateText) method. It generates char array fields in the JSP page class initialized as field = "string".toCharArray(); The "string" constants have 64K limit on string length. It is not run-time limitation, but a limitation of the Java Class File format, see [1]. Apparently it is what is being hit here. [1] http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html#88659
(In reply to comment #1) > The genStringAsCharArray option affects the > o.a.jasper.compiler.Generator.GenerateVisitor#visit(Node.TemplateText) method. > > It generates char array fields in the JSP page class initialized as > field = "string".toCharArray(); > > The "string" constants have 64K limit on string length. It is not run-time > limitation, but a limitation of the Java Class File format, see [1]. Apparently > it is what is being hit here. > > [1] > http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html#88659 Thank you, it's clear for me now. Is it be possible to provide an official workaround like this? field = (new String("longstring_part1") + new String("longstring_part2") + ... new String("longstring_partn")).toCharArray();
> field = (new String("longstring_part1") + > new String("longstring_part2") + > ... > new String("longstring_partn")).toCharArray(); I think that wouldn't work. What will work is to generate several arrays and call out.write() with each one in turn. Note that the 64K limit is not the char count aka str.length(), but the count of bytes in UTF-8 encoding. So, either that count should be calculated (better without String.toBytes() call) or the threshold should be like (64K / (max count of bytes in char in UTF-8)). I wonder also whether initializing the array as = {'s', 't', 'r', 'i', 'n', 'g'} performs worse or better than the existing code. Anyway, a test case is needed. BTW, using mappedFile=false will probably hit the same limit. (That is when the "breakAtLF" variable is false in that visit(Node.TemplateText) method).
For info, it appears the the Eclipse compiler does not enforce this limit. Dynamic compilation works whereas pre-compilation fails.
I have fixed this in 7.0.x and it will be included in 7.0.9 onwards. I have also proposed the fix for 6.0.x
(In reply to comment #4) > For info, it appears the the Eclipse compiler does not enforce this limit. > Dynamic compilation works whereas pre-compilation fails. That would be strange. It is class format limitation: the text will be broken if the length counter overflows. There is caveat with this setting: the init-param is named "genStrAsCharArray" (see comment in web.xml), not genStringAsCharArray as the property in the Options interface, or as said in the title of this bug report. The mapping between names is done inside the EmbeddedServletOptions class constructor.
Answering my own questions (In reply to comment #3) > I wonder also whether initializing the array as = {'s', 't', 'r', 'i', 'n', > 'g'} performs worse or better than the existing code. It works, but generates a lot of code, like the following (for an array of 11 chars): 0: bipush 11 2: newarray char 4: dup 5: iconst_0 6: bipush 72 8: castore 9: dup 10: iconst_1 11: bipush 101 13: castore 14: dup (...) 59: bipush 10 61: bipush 100 63: castore 64: putstatic 67: return I have not measured whether it works considerably slow or not. > BTW, using mappedFile=false will probably hit the same limit. > (That is when the "breakAtLF" variable is false in that > visit(Node.TemplateText) method). The mappedFile=false will not experience this issue under usual circumstances. There is a constant JspUtil.CHUNKSIZE and thus strings longer than 1024 will be split at LF regardless of breakAtLF flag. If the JSP has lines of 64K bytes without any LF in them, this issue will be observed regardless of mappedFile setting. But such JSPs are very unlikely.
Fixed in 6.0.x and will be included in 6.0.33 onwards.