Bug 47323 - Name clash: o.a.c.Manager class vs. o.a.c.manager package when compiling JSP
Summary: Name clash: o.a.c.Manager class vs. o.a.c.manager package when compiling JSP
Status: RESOLVED WONTFIX
Alias: None
Product: Tomcat 6
Classification: Unclassified
Component: Jasper (show other bugs)
Version: 6.0.20
Hardware: PC Windows XP
: P2 minor (vote)
Target Milestone: ----
Assignee: Tomcat Developers Mailing List
URL:
Keywords:
: 39093 (view as bug list)
Depends on:
Blocks:
 
Reported: 2009-06-06 09:56 UTC by Konstantin Kolinko
Modified: 2014-05-06 17:13 UTC (History)
2 users (show)



Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Konstantin Kolinko 2009-06-06 09:56:08 UTC
The following issue is specific to MS Windows, where file system is case-insensitive, and it does not occur when the classes are inside a jar file (catalina.jar).

I observed it in development environment, when trying to run Tomcat from its compiled sources without building a distributive.

Steps to reproduce this issue with TC 6.0.20:
----------------------------------------------
1. Get and unpack apache-tomcat-6.0.20.zip
2. In ${catalina.home}/lib folder unpack all classes from catalina.jar.
Remove catalina.jar or rename it e.g. to catalina.ja_.

3. In ${catalina.home}/conf/tomcat-users.xml add a user with role "manager"
4. Launch Tomcat and login to the Manager application
5. On the page that lists the web applications, click on the count of sessions for the manager webapp, i.e. access the following URL:
http://localhost:8080/manager/html/sessions?path=/manager

6. Expected result: Showing a list of sessions for the web app.
Actual result:
---------
FAIL - Encountered exception org.apache.jasper.JasperException: Unable to compile class for JSP: 

An error occurred at line: 8 in the generated java file
The import org.apache.catalina.manager cannot be resolved
---------

The issue is reproducible if the compiler is replaced with the latest one from eclipse-JDT-SDK-3.5RC3.zip of 200905282000.

I cannot reproduce the issue independently when editing files in Eclipse IDE, so it is like it does not affect Eclipse users.

I was looking in the code where Jasper calls the JDT compiler, and found the following, in method generateClass(String[]) of o.a.j.compiler.JDTCompiler:

  final INameEnvironment env = new INameEnvironment() {
    (..)
                private boolean isPackage(String result) {
                    if (result.equals(targetClassName)) {
                        return false;
                    }
                    String resourceName = result.replace('.', '/') + ".class";
                    InputStream is = 
                        classLoader.getResourceAsStream(resourceName);
                    return is == null;
                }
  }

The isPackage() method will provide false negative for "o.a.c.manager" package, because an attempt to read "o.a.c.manager.class" file will result in reading the "Manager.class" file and will be successful.

I thought of proposing to rename either the class or the package, but it is not feasible, as there are a lot of other subpackages with similar name clashes in o.a.catalina: authenticator, realm, loader, session. :/

The workaround for this issue is to pack clashing classes into a jar file, or to use a different OS.
Comment 1 Konstantin Kolinko 2009-06-06 10:08:37 UTC
*** Bug 39093 has been marked as a duplicate of this bug. ***
Comment 2 Mark Thomas 2009-09-12 09:51:34 UTC
Can't see an easy way to fix this.
Comment 3 Mark Thomas 2009-09-12 09:51:59 UTC
Correct the resolution - sorry for the noise.
Comment 4 Konstantin Kolinko 2014-05-02 14:25:21 UTC
*** Bug 56481 has been marked as a duplicate of this bug. ***
Comment 5 Christopher Schultz 2014-05-05 13:56:54 UTC
Would it impact performance too much to request the resource as a URI and then examining the "file" in some way? Perhaps we could look for the possible package name as a directory first instead of looking only for a matching .class file.

We could also perform a list() to see if we get a zero-length resource list, but of course that takes longer.
Comment 6 Konstantin Kolinko 2014-05-05 23:43:13 UTC
> request the resource as a URI

classLoader.getResource(packageName)

I suspect that it can break compilation for JARs that contain only files and do not have zip entries for directories. I mean, it will return null, a false negative. (It needs testing though whether my suspicion is true).


BTW,
the strings arithmetics in org.apache.jasper.compiler.JDTCompiler$(new INameEnvironment).isPackage(char[][],char[]) is awful.

It uses += concatenating strings in a loop.
Comment 7 Christopher Schultz 2014-05-06 17:13:35 UTC
(In reply to Konstantin Kolinko from comment #6)
> > request the resource as a URI
> 
> classLoader.getResource(packageName)
> 
> I suspect that it can break compilation for JARs that contain only files and
> do not have zip entries for directories. I mean, it will return null, a
> false negative. (It needs testing though whether my suspicion is true).

Agreed. In the JARs we control, we could make sure that directories are included, but that won't help user code and 3rd-party libraries.

> BTW,
> the strings arithmetics in org.apache.jasper.compiler.JDTCompiler$(new
> INameEnvironment).isPackage(char[][],char[]) is awful.
> 
> It uses += concatenating strings in a loop.

Yikes. It's used all over the place in the "new INameEnvironment" construct. Also creating String objects out of char[] just to then concatenate with the ever-expanding String value.