Sometime in the recent past someone noticed that the mapping of a jsp file's name to a class name is not one-to-one -- the filename needs mangling to conform to java identifiers and to make sure that classes aren't named after keywords.
Whoever did this missed the fact that the same mangling needs to happen to the intermediate directories that are used to create the package name. I've attached a patch that liberally grabs the mangling code from org.apache.jasper.compiler.CommandLineCompiler and drops it into org.apache.jasper.CommandLineContext to do that work. As a heads-up, there's another problem that may need addressing in the class name mangling -- if a file is named, for instance, "com.jsp" or "org.jsp", the classname shadows any imports from the "com" or "org" packages respectively (this is a general problem, these are just examples). I'm not really sure how to get around this -- the simple way would be to prepend each class name with some likely-never-to-be-used character sequence; the intelligent way would require actually parsing the generated .java to make sure that no top-level package name is being shadowed. This requires a little more intelligence than what I was willing to put in for this patch. :) - a.
--- org/apache/jasper/CommandLineContext.java.old Thu Mar 21 17:01:27 2002 +++ org/apache/jasper/CommandLineContext.java Thu Mar 21 17:07:48 2002 @@ -77,6 +77,8 @@ import java.net.URLClassLoader; import java.net.MalformedURLException; +import java.util.StringTokenizer; + /** * Holds data used on a per-page compilation context that would otherwise spill * over to other pages being compiled. Things like the taglib classloaders @@ -236,12 +238,72 @@ } else { packageName += pathName.replace('/', '.'); } + + // mangle package if necessary + StringTokenizer st = new StringTokenizer(packageName, "."); + StringBuffer mangledPackageName = new StringBuffer(); + while (st.hasMoreTokens()) { + if (mangledPackageName.length() > 0) + mangledPackageName.append("."); + String tok = st.nextToken(); + + for (int i = 0; i < keywords.length; i++) { + if (tok.equals(keywords[i])) { + tok += "%"; + }; + }; + + if (Character.isJavaIdentifierStart(tok.charAt(0))) + mangledPackageName.append(tok.charAt(0)); + else + mangledPackageName.append(mangleChar(tok.charAt(0))); + for (int i = 1; i < tok.length(); i++) { + if (Character.isJavaIdentifierPart(tok.charAt(i))) + mangledPackageName.append(tok.charAt(i)); + else + mangledPackageName.append(mangleChar(tok.charAt(i))); + } + } + packageName = mangledPackageName.toString(); + //strip off any leading '.' in the package name if (!packageName.equals("") && packageName.charAt(0) == '.') { packageName = packageName.substring(1); } return packageName; } + + public static String [] keywords = { + "abstract", "boolean", "break", "byte", + "case", "catch", "char", "class", + "const", "continue", "default", "do", + "double", "else", "extends", "final", + "finally", "float", "for", "goto", + "if", "implements", "import", + "instanceof", "int", "interface", + "long", "native", "new", "package", + "private", "protected", "public", + "return", "short", "static", "super", + "switch", "synchronized", "this", + "throw", "throws", "transient", + "try", "void", "volatile", "while" + }; + + private static final String mangleChar(char ch) { + + if(ch == File.separatorChar) { + ch = '/'; + } + String s = Integer.toHexString(ch); + int nzeros = 5 - s.length(); + char[] result = new char[6]; + result[0] = '_'; + for (int i = 1; i <= nzeros; i++) + result[i] = '0'; + for (int i = nzeros+1, j = 0; i < 6; i++, j++) + result[i] = s.charAt(j); + return new String(result); + } /** * Full path name of the Java file into which the servlet is being
-- To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>