Bug 163807 - JDT fails to compile legal Java source files
Summary: JDT fails to compile legal Java source files
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 3.2   Edit
Hardware: PC Windows XP
: P3 major (vote)
Target Milestone: 3.3 M4   Edit
Assignee: Kent Johnson CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2006-11-08 09:15 EST by Kohsuke Kawaguchi CLA
Modified: 2006-12-12 10:37 EST (History)
1 user (show)

See Also:


Attachments
Small java project to reproduce this problem (4.14 KB, application/octet-stream)
2006-11-08 09:17 EST, Kohsuke Kawaguchi CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Kohsuke Kawaguchi CLA 2006-11-08 09:15:48 EST
When I have a class called 'foo.Bar' and perhaps a resource file called 'foo/Bar/messages.properties', Eclipse fails to compile those files by reporting the following errors:

- Bar cannot be resolved to a type
- The type Bar collides with a package

It looks like the compiler is confused by having the class and the package in the same name, yet there's no such prohibition in JLS. Sun's javac accepts the same source code happily.

I'll attach the test case.
Comment 1 Kohsuke Kawaguchi CLA 2006-11-08 09:17:01 EST
Created attachment 53463 [details]
Small java project to reproduce this problem

Import this into Eclipse to see the problem. Also run the build.xml in it to see that javac takes it fine.
Comment 2 Kent Johnson CLA 2006-11-08 11:32:08 EST
But what happens when you define your first class in the package foo.Bar ?

javac complains about a collision for these types:

package foo;
public class Bar {}

package foo.Bar;
public class X {}

-> foo/Bar/X.java:1: package foo.Bar clashes with class of same name package foo.Bar;

Since JDT is an incremental development environment, we report type/package collisions once they occur.
Comment 3 Kohsuke Kawaguchi CLA 2006-11-08 11:57:50 EST
Ah, but I'm not defining classes in "foo.Bar". They are really just for housing resource files.

If having a class in the "foo.Bar" package is a necessary condition for a collision, then I think JDT is still wrong in reporting an error before that condition is met.
Comment 4 Kent Johnson CLA 2006-11-08 14:45:18 EST
But JDT is an incremental development environment, so creating a package means you want the package to appear in the namespace used to resolve types/packages, and before the first type is created.

Why do you need to place the resource files in this specific package?
Comment 5 Kohsuke Kawaguchi CLA 2006-11-08 20:42:50 EST
I'm not sure why being an incremental development environment would have anything to do with this. Assuming that the javac behavior is correct, it looks like the expected behavior is that a package must not "appear in the namespace used to resolve types/packages" until the first type is created in it.

If what you are saying is that this is a Sun's javac bug and not JDT's bug, that would make sense. But I don't quite understand your reasoning so far.


As for the reason why we want to place the resource files in this specific package, it was simply just because that's how it's done, and I can't change it without breaking a backward compatibility.

This issue has been brought to my attention relatively recently by one of a new developer to my project who uses Eclipse. Before that, no one was using Eclipse, so we didn't notice this problem.
Comment 6 Philipe Mulet CLA 2006-11-09 04:14:56 EST
Kohsuke - what does your command line looks like when compiling ?

>javac Bar.java Bar\X.java
Bar.java:2: foo.Bar clashes with package of same name
public class Bar {}
       ^
Bar\X.java:1: package foo.Bar clashes with class of same name
package foo.Bar;
^
2 errors

If you only compile Bar.java, it would work fine, but if you try to compile both at once, you will see the problem you get in Eclipse as well (since by default it will compile both files). You may configure exclusion rules to selectively exclude some files from your source folder.
Comment 7 Kent Johnson CLA 2006-11-09 10:37:56 EST
The JLS does not specify when a package must appear, so there is no right or wrong in this case.

But because JDT is an incremental development environment, we do not postpone reporting errors until another type is added to an empty package. We expect you to add types to packages that you've created, so we treat the new package as a package from the start.

Here is another example if you define an empty package foo.Bar :

package test;
// Can I refer to foo.Bar.Member? What happens when foo/Bar/X.java is created?
import foo.Bar.*;
public class Test {...}

package foo;
public class Bar {
   public class Member {}
}
Comment 8 Kohsuke Kawaguchi CLA 2006-11-09 13:58:39 EST
Philippe - thank you for chiming in, but please take a look at the attached workspace. I do not define any class in the Bar package. There's only a resource file. If I were defining classes, that would have been an error in both JDT and Sun javac. I opened this issue only because my project that compiles with javac (and IntelliJ) doesn't work with JDT.



Kent - I'm not really an JLS expert, but it seems like a package is considered a package only when there's a source file in it. IOW, JLS operates on a set of source files and not a directory tree, and therefore empty directories (or directories that do not have source files) do not affect the compiler behavior. Because of that, I don't agree with "there is no right or wrong in this case."

I'll check with javac guys as they are much more familiar with JLS than I am.


As with your example, javac is quite consistent. If there's no "foo/Bar/*.java", then "import foo.Bar.*" refers to the inner Member class. If there's any "foo/Bar/*.java", then it's a compilation error, presumably for the exact reason you cited in the comment.

I still don't think just because JDT is an incremental environment does not make it impossible to handle this correctly. I think the bug that I'm pointing out is that just because I created a source folder does not immediately mean there's a new Java package. There needs to be one bit flag on each directory in the source tree that says whether that is a "package" in the JLS sense (and AFAICT, Eclipse already seems to have such information, as the package icon renders differently.)

In various other places, JDT already needs to deal with a situation where a change in one part of the source tree affects how another part of the source tree is interpreted. Isn't this just one more of those?


If I were working on a fresh project, I wouldn't try this potentially risky convention, but I'm really hoping to have some of my developers use Eclipse, and this bug is preventing us from doing that.
Comment 9 Kent Johnson CLA 2006-11-09 15:22:58 EST
Just so we're clear: javac != JLS.

So "a package is considered a package only when there's a source file in it" is a consequence of javac's current implementation and NOT a requirement specified by the JLS.
Comment 10 Kohsuke Kawaguchi CLA 2006-11-10 12:28:07 EST
From JLS 7.2:

  Each host determines how packages, compilation units,
  and subpackages are created and stored, and which
  compilation units are observable (ยง7.3) in a
  particular compilation.

  The observability of compilation units in turn determines
  which packages are observable, and which packages are
  in scope.

I think this is saying that JDT as a "host" can stochoose to decide how to manage packages, but it says the observability of the package is determined by the observability of compilation units.

This is further reinforced by the following section:

From JLS 7.4.3:

  A package is observable if and only if either:

    * A compilation unit containing a declaration of
      the package is observable.
    * A subpackage of the package is observable.

So I think it's clear enough that a package which does not contain any compilation unit is not observable.
Comment 11 Kent Johnson CLA 2006-11-17 14:50:44 EST
Released for 3.3 M4 in HEAD stream.

Changed testcase in FromPRsTest.test1FYYKRJ() to expect a warning instead of an error when a type collides with a package.

There's nothing like changing the spec to match an implementation.
Comment 12 Kohsuke Kawaguchi CLA 2006-11-17 17:10:51 EST
Thank you for a quick turn around!
Much appreciated.
Comment 13 David Audel CLA 2006-12-12 10:37:39 EST
Verified for 3.3M4 with I20061212-0010.