Bug 16209 - Support declared packages that are different from directory location
Summary: Support declared packages that are different from directory location
Status: RESOLVED WONTFIX
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 2.0   Edit
Hardware: PC All
: P3 enhancement with 2 votes (vote)
Target Milestone: 2.0 F2   Edit
Assignee: Kent Johnson CLA
QA Contact:
URL:
Whiteboard:
Keywords:
: 48407 328398 (view as bug list)
Depends on:
Blocks:
 
Reported: 2002-05-16 18:44 EDT by Jeff Linwood CLA
Modified: 2021-02-03 19:06 EST (History)
5 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Jeff Linwood CLA 2002-05-16 18:44:34 EDT
Error I get when compiling: The declared package does not match the expected 
package com.mycompany.package.subpackage

I inherited some Java code from a company whose Java developers used reflection 
to load classes at run time that implemented an interface.  These classes all 
had to be in the same package (com.mycompany.package).  Because there were 
hundreds of these classes, they were organized in sub-directories such as 
com/mycompany/package/guitoolkit.  Both JavaC and Jikes don't complain about 
this behavior - they compile the java classes to the com/mycompany.package 
directory.  The Java Language Specification leaves this behavior up to the 
implementor of the compiler. 

I consider this to be a feature request, not a specific bug, although it forces 
me to not use Eclipse for compilation of this project.
Comment 1 Jeff Linwood CLA 2002-05-20 16:59:44 EDT
Affected Source file is CompilationUnitScope.java in 
org.eclipse.jdt.internal.compiler.lookup

Jeff
Comment 2 Philipe Mulet CLA 2002-05-21 12:21:01 EDT
Batch compilers, like the Eclipse batch compiler, can take files located 
anywhere since there are all fed at once for batch compiling.

However, in the case of an incremental compiler which will lazily discover 
files as it compiles, available files must be located in appropriate folders.

You can try to compile your code with javac and not put your sources on the 
list of files to compile but rather directly on the classpath where they will 
be looked up. Your setup will cause necessary types to be not found.

If you could reorganize these sources, I would suggest you use several source 
folders, like 'guitoolkit' so as to contain the various fragments of the same 
package.

Comment 3 Philipe Mulet CLA 2002-05-22 04:55:02 EDT
You could use Ant scripts to compile your sources with a batch compiler.
Closing
Comment 4 Kent Johnson CLA 2002-06-03 11:58:23 EDT
Incorrectly marked for verification.
Comment 5 Gregg Wonderly CLA 2003-09-22 15:49:33 EDT
This misfeature is a really ugly sore on eclipse.  Deriving package name from 
directory structure is not part of the spec for filesystem based 
implementations.  Please fix this
Comment 6 Kent Johnson CLA 2003-09-22 16:26:33 EDT
Well needless to say, we disagree.

Gregg: How do you currently build/compile your source files?
Comment 7 Gregg Wonderly CLA 2003-09-23 11:51:08 EDT
I use Kawa as my IDE because it lets me add source files from anywhere and 
compile all of them into a single tree using 'javac -d'.  This means that when 
I am using an old jar file in a new application, and I need to investigate a 
stack back trace, I can quickly add that source tree, and see it with my other 
files.  When I compile it, the output goes into my classes directory, which is 
first in the classpath.  If I need to make changes to those files, my SCM 
(perforce) will be used to check out the file.  I make my changes, test them, 
and then submit the changes.  Then, I can use that jar files Ant built to 
build the new version for production.

The Java Language spec dictates that the package statement provides the 
package of the class. 

i.e.

7.3 Compilation Units
CompilationUnit is the goal symbol (§2.1) for the syntactic grammar (§2.3) of 
Java programs. It is defined by the following productions:

CompilationUnit:
	PackageDeclarationopt ImportDeclarationsopt TypeDeclarationsopt

ImportDeclarations:
	ImportDeclaration
	ImportDeclarations ImportDeclaration

TypeDeclarations:
	TypeDeclaration
	TypeDeclarations TypeDeclaration

Types declared in different compilation units can depend on each other, 
circularly. A Java compiler must arrange to compile all such types at the same 
time.
A compilation unit consists of three parts, each of which is optional:


A package declaration (§7.4), giving the fully qualified name (§6.7) of the 
package to which the compilation unit belongs. A compilation unit that has no 
package declaration is part of an unnamed package (§7.4.2). 
import declarations (§7.5) that allow types from other packages to be referred 
to using their simple names 
Top level type declarations (§7.6) of class and interface types 
Which compilation units are observable is determined by the host system. 
However, all the compilation units of the package java and its subpackages 
lang and io must always be observable. The observability of a compilation unit 
influences the observability of its package (§7.4.3).
Every compilation unit automatically and implicitly imports every public type 
name declared by the predefined package java.lang, so that the names of all 
those types are available as simple names, as described in §7.5.3.

And then in 7.4

7.4 Package Declarations
A package declaration appears within a compilation unit to indicate the 
package to which the compilation unit belongs.

7.4.1 Named Packages
A package declaration in a compilation unit specifies the name (§6.2) of the 
package to which the compilation unit belongs.

PackageDeclaration:
	package PackageName ;

The package name mentioned in a package declaration must be the fully 
qualified name (§6.7) of the package.

I don't see any allowance for the compiler/platform to arbitrarily choose the 
package.  What is in the package statement is what is to be used.
Comment 8 Philipe Mulet CLA 2003-09-23 13:22:39 EDT
No action planned. This isn't a bug but rather a standard rule for organizing 
sources and predictabily find them (without scanning directories all the time).

There was numerous debate on that topic a long time ago, and we reached some 
consensus. 
Comment 9 Gregg Wonderly CLA 2003-10-07 23:02:32 EDT
The spec says that the package statement must be used to control what package a
source file compiles into, plain and simple.  This needs to be fixed so that
this is the behavior of the compiler.  If other parts of the IDE don't work due
to directory structure assumptions, then I would say that those pieces of the
IDE are broken too.

But, I can see that this is about your opinion and mantra for source file and
directory organization.  What other developers need to make use of eclipse
doesn't seem to matter.

Seems like this is just more of the IBM way of thinking.  Our way or the
highway...  So much for open source...
Comment 10 Kent Johnson CLA 2003-10-08 09:51:24 EDT
Gregg: Insulting people is not going to win you anything.

As was already mentioned, this discussion has already happened WITHIN the 
Eclipse Open Source Community. Look at the date on this PR, it was over a year 
ago & your the first person to voice a dissenting opinion in the last 16 months.

So keep your insults to yourself.
Comment 11 Gregg Wonderly CLA 2003-10-13 10:00:56 EDT
I am sorry that you feel insulted.  I feel like I am talking to a brick wall.  I
know many well seasoned java programmers that have tried eclipse, and just
deleted it at the sight of this issue and other issues. 

Regarding the time frame that you last visited this issue, perhaps the
interested people already had an IDE that worked for them at that point and
weren't flocking to eclipse to give it a whirl just because it was the lastest
thing to hit the streets.

This is strickly a language support issue.  The spec says that the compiler must
honor the package statement.  The Eclipse built-in compiler does not.

I'm not trying to be hateful or insulting. I do not do that casually.  I am
using the words I am using because I don't understand your position on this issue.

The language spec says you are wrong.  Like it or not, that's the truth!
Comment 12 Philipe Mulet CLA 2003-10-15 10:28:07 EDT
Email from Gregg Wonderly:
I found this draft sitting around and am not sure that I sent it to you.
Please excuse the duplicate if so.  This issue is important to me and I
want to make sure that I have conveyed my concerns.

>Note that on a batch compiler command line, one can specify source folders
>on the classpath, and these have to be at locations exactly matching their
>package declarations. We simply generalized this approach and made it the
>default law, so that our tool could pick arbitrary sources on the
classpath
>without needing the help for external maps from type to files etc...

Okay, so you want to optimize how the IDE works.  But, the problem is you
are
still violating the language spec.  The package statement is part of the
language requirements.  If the compiler is reading the source file, it is
seeing the package statement.  As it is compiling, it must use the package
statement to control what package it puts the compiled class file output
into.
 If the rest of the IDE breaks, then it, also is ignoring the language
specification.  Optimizations are great, right up to the point that they
create more compromises in the design of the software then the apparent
optimizations that are being attempted.

I guess I'd think that if this one issue makes a world of difference in the

performance of the IDE, then there is a lot more speed to be gained
elsewhere,
and fixing this issue is only the first thing that needs to be done.

What you could do is provide a factory, static method for source file
location
tracking.  When the compiler sees the package statement, and finds it to be

different from the directory structure, then it should put an entry into
the
map.  The factory method should do a get out of the map, and if there is no

entry, it should return the package name passed.  This way, those that have

the ability to choose where their source files are, can put them into a
directory structure that matches the package. They would not have 100's or
1000's of entries in the map. If one doesn't have that choice, then the
compiler still meets the language spec, and the other parts of the IDE can
still function with a disjoint source set.  The size of the map will me
purportional to the size of the total number of class files.  If the
compiler
can recompile all source files at once, then the map can fit in memory too,

with a proportionally small requirement for more RAM...

It really is a big issue for many people that I have talked to.  But, I
suppose that it is possible that I've been doing Java development
successfully
just using 'javac -d ... -classpath ...' for 7 years and the directory
trees
that I've been using really don't work, and I really am not more productive

when I don't have to navigate through 5 levels of directory trees when I am

browsing with Windows Explorer, or using CD to move around in a source tree

while recompiling on linux machines via SSH...  But, I am not convinced
it's
just a dream yet...

Your ideas and thoughts are not without merit regarding directory structure

Phillpe.  However, they are not universal, nor is it a reality that such
order
can exist always...
Comment 13 Philipe Mulet CLA 2003-10-15 10:29:55 EDT
Thanks for your comment, I agree that we somewhat dictate a little too much 
what is good practice vs. what is not. For this very topic, the package clause 
in the source file will always be used to generate the file properly. 
If it doesn't match the directory location, we will also flag it.

However, we will lookup a type based on the directory structure, rather
than considering every single file and parsing them to figure which package
they sit in. As I said, other compiler vendors do the same when performing
source lookup, we are not different.

We could indeed build a map (then need to refresh, etc...) and lookup
through this map, this would require extra work, but is doable. At the
moment, we don't think this would be cost effective.

Also, one clarification. The compiler is never compiling all files in
memory at once. It would blow up almost immediately unless your memory
limit is super high. We only preserve in memory the signatures we need to
compile files against each other, but only process one unit at a time in
memory.
Comment 14 Gregg Wonderly CLA 2003-10-15 17:18:54 EDT
>For this very topic, the package clause in the source file will always be
>used to generate the file properly. If it doesn't match the directory
>location, we will also insist on it.
>However, we will lookup a type based on the directory structure, rather
>than considering every single file and parsing them to figure which
package
>they sit in. As I said, other compiler vendors do the same when performing
>source lookup, we are no different.

Javac does not appear to do this, as I can compile all of my class files
with it on the command line.  But, I suspect that it might.

>We could indeed build a map (then need to refresh, etc...) and lookup
>through this map, this would require extra work, but is doable.

Here's how I see this issue being resolved.

1)  The IDE has to initially know what files it knows about.  When the IDE
    is made aware of a source file, it should find the package statement
    (the parse can stop at the first keyword that is not 'package') and
    update the map.
2)  When the user edits a source file, the IDE can inspect the file on a
    Save or SaveAs request to make note of any change in the 'package'.
3)  When an incremental compile is done, any to-be-compiled files are already
    being parsed, the 'package' can be updated at that time.
4)  When the IDE first starts up, each time, I am assuming that the IDE
    must look for new files because it knows about files based to directory
    trees, not individual lists of files.  This would also be the time to
    find package statements and update the map.

You have already taken the time and effort to have the compiler be aware of
this exact issue and have it issue a warning about the directory not
matching the package statement.  At that moment, the map should be updated and 
the warning changed to tell the user that the package has been set to the
package statement and that there might be extraneous class files visible from 
the old package perhaps.

I am just not convinced that this is a hard problem.  The MAP is a very
remedial piece of memory compared to the signature information that the
compiler must track for each file.  So, I am not convinced that there is a
memory issue.  Certainly, maintaining the map might be a bit of a pain, but
if you make it an option, then those that have trees that are package
structured can turn this off, and not encounter any measurable performance 
difference.

Those who have source trees that aren't perfect, can still make use of the
hard work of the eclipse team and not have to go off and create competing
IDEs just to get work done...
Comment 15 Philipe Mulet CLA 2003-12-11 00:52:36 EST
*** Bug 48407 has been marked as a duplicate of this bug. ***
Comment 16 Cagatay Kavukcuoglu CLA 2005-07-13 12:29:31 EDT
For what it's worth, I've always wanted to have my sources in a flat folder
structure where all package folders are siblings and use the actual dot
spearated package names as folder names. The hierarchic folder structure that is
common in all tools (and not just Eclipse) does not reflect the logical
organization of the software. I also find the flat structure much easier to
browse and work with.
Comment 17 Srikanth Sankaran CLA 2010-10-25 03:23:06 EDT
*** Bug 328398 has been marked as a duplicate of this bug. ***
Comment 18 Petr Janeček CLA 2021-02-03 19:06:16 EST
We're now 10 years in the future, and this is something I've come across in three different projects in three different companies (and I've only seen three) over the last year. The unifying theme: Before me the developers on the projects were predominantly using IntelliJ, and IntelliJ doesn't care and compiles the classes in "wrong" packages.

Some of them were the result of wild refactorings after whose the classes ended up with incorrect package declarations. I fixed those, but it's a big pain to explain to all the affected teams why I'm touching "their" code and proposing changes for them when they can't even see a warning.

Some of the classes were generated by source-generating tools, in my case ANTLR (two different companies). Again, fixable, but annoying, and seems to be coming up fairly often.


In the world where there are teams made of only IntelliJ devs who didn't even make their projects against the spec - maven and javac are still working fine - it's a problem to come and say "Hello, I'm your new dev and because I use a different, non-compliant tool, we need to touch dozens of classes mostly in a non-meaningful way". And that world is here, where I live I'm a minority as an eclipser.

Oh, and this came up lately here: https://twitter.com/nipafx/status/1356535487515807744

Is eclipse after 10 years in a place where a change of this behaviour is no longer that costly / hard to do? If nothing changed, I assume this will not be reopened, but if at some point somebody refactored and/or consolidated package-recognizing logic, maybe it's time to alleviate this little limitation of ours and make the check an optional warning?