blob: b640c72751f55da2a90d807bf281090c71944985 [file] [log] [blame]
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="GENERATOR" content="Mozilla/4.5 [en] (Win98; I) [Netscape]">
<meta name="Author" content="Build">
<title>JDT - Java Output Folder</title>
</head>
<body>
<h2>
Java Output Folder</h2>
Last revised 17:30 Tuesday October 30, 2001 <font color="#3333FF">(recent
changes in blue;</font><font color="#CC0000"> latest in red</font><font color="#3333FF">)</font>
<p>Work item: "Support for dealing with class files generated by external
Java compilers like javac and jikes from an Ant script."</p>
<p>Here's the crux of one problem (from WSAD, via John W.):</p>
<p>In some environments the client has limited flexibility in how they
structure their Java projects. Sources must go here; resource files here;
mixed resource and class files here; etc.</p>
<ul>
<li>
There are situations where the client needs to place additional class files
and resource files in the output directory.</li>
<li>
There are situations where the client needs to generate class files into
an existing folder filled with their class files and resource files (e.g.,
an exploded WAR file).</li>
</ul>
When clients attempts either, they discover that (a) the Java model and
builder ignore any class files in the output folder, and (b) from time
to time these files in the output folder get deleted without warning.
<p>The Java builder was designed under the assumption that it "owns" the
output folder. The work item, therefore, is to change the Java builder
to give clients and users more flexiblility as to where they place their
source, resource, library class, and generated class files.</p>
<h3>
Current Functionality</h3>
Eclipse 1.0 Java builder has the following characteristics (and inconsistencies):
<ul>
<li>
The class files generated by the Java builder go in a single output folder.
Java source files go in one or more source folders. Any other kind of files
can be included in the source folder too; this includes pre-compiled class
files. All these other files will be automatically mirrored to the binary
output directory when a build is done. The mirror is maintained as the
source folder changes; damage made directly to the output folder gets repaired
no later than the next full build.</li>
<li>
The output folder belongs to the Java builder. It summarily deletes files
from the output folder that it does not think belong there. It is not possible
to get away with adding files directly to the output folder. So you cannot
even mate the extra resource files with the class files manually.</li>
<li>
When the project source and output folder coincide (perhaps at the project
itself), the builder behaves differently. It grants that source files belong
there, so it never deletes them. It also grants that non-class files belong
there, so it never deletes them either. But it assumes that all class files
are generated, and so it summarily deletes them on every full build, including
class files that were explicitly put there. This is different from the
way things work out when the output folder and the source folder do not
coincide. And it is not what you want if you need to mate other class files
with the generated ones.</li>
</ul>
<h3>
<font color="#3366FF">WSAD usecase - for the record</font></h3>
<font color="#3366FF">The </font><font color="#CC0000">(proposed)</font><font color="#3366FF">
WSAD scenario is that they have a src/ folder for source code, a classes/
folder for pre-existing class files (extracted from a WAR file), and a
bin/ folder for generated classes.</font>
<ul>
<li>
<font color="#3366FF">The typical case is where the source and output folders
are distinct. In this case, the classes/ folder may or may contain class
files.</font></li>
<li>
<font color="#3366FF">The source code must be compiled against the classes
in classes/ folder.</font></li>
<li>
<font color="#3366FF">The source and output folders may coincide. The classes/
folder is always separate from either.</font></li>
<li>
<font color="#3366FF">In order to be executable, all class files must end
up in the output folder.</font></li>
<li>
<font color="#3366FF">The client would like a way to delete class files
from the classes/ folder for which there is corresponding source.</font></li>
<li>
<font color="#3366FF">The client would like to keep resource files in the
output folder on an ongoing basis.</font></li>
</ul>
<h3>
<font color="#3366FF">Proposal</font></h3>
<font color="#3366FF">The Java builder compiles source files found in the
source folders specified on the build classpath and generates class files
into the output folder. The Java builder also copies "resource" files from
source folders to the output folder (provided that source and output do
not coincide). Once in the output folder, the resource files are available
at runtime because the output folder is always present on the runtime class
path. The proposal is to extend this mechanism.</font><font color="#3366FF"></font>
<p><font color="#3366FF">The following proposal involves:</font></p>
<ul>
<li>
<font color="#3366FF">Clarifying ownership of files in the output folder.</font></li>
<li>
<font color="#FF0000">Clarifying semantics of resource file copying from
source folders to output folder.</font></li>
<li>
<font color="#FF0000">Making resource file copying from source folders
to output folder optional, rather than mandatory.</font></li>
<li>
<font color="#FF0000">Providing class file copying from library folders
to output folder, also on an optional basis.</font></li>
<li>
<font color="#FF0000">Providing and promoting useful alternatives to file
copying.</font></li>
<li>
<font color="#FF0000">Prohibiting cases where expendable copies would end
up mixed with important user data.</font></li>
</ul>
<h4>
<font color="#3366FF">Output folder ownership</font></h4>
<p><font color="#3366FF">When the output folder does not coincide with a source
folder, the Java builder owns the output folder and everything in it. The
output folder is taken to contain only files that are "expendable" - either
generated class files or copies of files that live in a source or library
folder.</font><font color="#3366FF"></font></p>
<p><font color="#3366FF">Users or clients that add, remove, or replace
files in the output folder can expect unpredicatable results. If the user
or client does tamper with files in the output folder, the Java builder
does not attempt to repair the damage. It is the responsibility of the
user or client to clean up their mess (by manually requesting a full build).</font><font color="#3366FF"></font></p>
<p><font color="#3366FF">When the output folder coincides with a source
folder, the Java builder only owns the class files in the output folder.
Only the class files in the output folder are considered expendable. Users
or clients that add, remove, or replace class files in the output folder
can expect unpredictable results.</font><font color="#3366FF"></font></p>
<p><font color="#3366FF">(N.B. This is a restatement of the current behavior.
[Verify that damage to output folder is not triggering builds.])</font></p>
<h4>
<p><font color="#FF0000">Output folder resource file consolidation</font></h4>
<font color="#FF0000">The Java builder provides resource file consolidation,
for resource files stored in source folders.</font><font color="#FF0000"></font></p>
<p><font color="#FF0000">When the output folder does not coincide with
a source folder, the Java builder can also be used to consolidate resources
files needed at runtime in the output folder. In some cases, this consolidation
may be preferred over the alternative of including additional runtime classpath
entries for source folders containing resources files.</font><font color="#FF0000"></font></p>
<p><font color="#FF0000">By flagging a source folder as copied, all non-source,
non-class files become eligible to be copied to the output folder. When
there are multiple entries on the build classpath specifying copying, eligible
files for earlier classpath entries take precedence over ones for later
entries.</font><font color="#FF0000"></font></p>
<p><font color="#FF0000">When the output folder coincides with a source
folder, the Java builder cannot perform any resource file consolidation
(resource files in the output folder belong to the user, not to the Java
builder). It is considered an error to specify copying from other source
folders.</font><font color="#FF0000"></font></p>
<p><font color="#FF0000">(N.B. This is different from current behavior
in a couple of regards:</font></p>
<ul>
<li>
<font color="#FF0000">Resource file copying for source folders is currently
mandatory. It would become optional.</font></li>
<li>
<font color="#FF0000">Class files are currently copied from source folders.
This would stop.</font></li>
</ul>
<font color="#FF0000">)</font>
<h4>
<font color="#FF0000">Output folder class file consolidation</font></h4>
<font color="#FF0000">The Java builder also provides class file consolidation,
for class files stored in library folders.</font><font color="#FF0000"></font>
<p><font color="#FF0000">The Java builder can also be used to consolidate
class in the output folder, regardless of whether the output folder coincides
with a source folder. In some cases, this consolidation may be preferred
over the alternative of including additional runtime classpath entries
for library folders. Note, however, that this works only when the library
folder contains no important resource files needed at runtime (resource
files are not copied from library folders, because resource files in the
output folder belong to the user rather than to the Java builder).</font><font color="#FF0000"></font></p>
<p><font color="#FF0000">By flagging a library folder as copied, all class
files become eligible to be copied to the output folder.
Class files generated
in the output folder always take precedence over class files copied from
library folders.</font><font color="#FF0000"></font></p>
<p><font color="#FF0000">(N.B. This new behavior. Files are not copied
from library folders by the current Java builder.)</font></p>
<h4>
<font color="#3366FF">Semantics</font></h4>
<ul>
<li>
<font color="#3366FF">Add a "copy" flag to source and library (and variable)
classpath entries.</font></li>
<ul>
<li>
<font color="#3366FF">For a source folder, copy flag means that </font><font color="#FF0000">resource
(i.e, non-source, non-class) files </font><font color="#3366FF">in the
source folder are copied to the output folder.</font></li>
<ul>
<li>
<font color="#3366FF">Primary use is to consolidate </font><font color="#FF0000">resource
files</font><font color="#3366FF"> in output folder so that source folder
does not need to be included on runtime classpath.</font></li>
</ul>
<li>
<font color="#3366FF">For a library folder (but not a library JAR), copy
flag means that </font><font color="#FF0000">all class files</font><font color="#3366FF">
in the library folder are copied to the output folder.</font></li>
<ul>
<li>
<font color="#3366FF">Primary use is to consolidate </font><font color="#FF0000">class
files</font><font color="#3366FF"> in output folder so that library folder
does not need to be included on runtime classpath.</font></li>
<li>
<font color="#FF0000">N.B. Resource files in the library folder are not
copied.</font></li>
</ul>
<li>
<font color="#3366FF">The copy flag should be off by default for both types
of folder; i.e., no file copying.</font></li>
<li>
<font color="#3366FF">Source folder copy flag on describes current behavior.</font></li>
<li>
<font color="#3366FF">For backward compatibility, existing projects should
have copying on for source folders that might contain resource files.</font></li>
<li>
<font color="#FF0000">Library folder copy flag off describes current behavior.</font></li>
<li>
<font color="#FF0000">Error if any source folder copying specified when
a source folder and output folder coincide.</font></li>
<li>
<font color="#3366FF">API on JavaCore for creating classpath entries with
copy bit set.</font></li>
<li>
<font color="#3366FF">API on IClasspathEntry for reading copy bit.</font></li>
</ul>
<li>
<font color="#3366FF">Generated class files in the output folder take precedence
over class files copied from library folders.</font></li>
<li>
<font color="#3366FF">Files copied from earlier classpath entries take
precedence over ones for later entries.</font></li>
<li>
<font color="#FF0000">UI provides the user with control over resource file
consolidation.</font></li>
<ul>
<li>
<font color="#FF0000">For source folder: "Copy resource (non-source, non-class)
files to output folder"</font></li>
</ul>
<li>
<font color="#FF0000">UI does not provide the user with control over class
file consolidation.</font></li>
<ul>
<li>
<font color="#FF0000">This feature would be enabled programmatically by
clients that need it.</font></li>
</ul>
<li>
<font color="#3366FF">Consolidation functionality is built in to Java builder.</font></li>
<li>
<font color="#3366FF">Pro: Puts us in a position where resource copying
is no longer mandatory.</font></li>
<li>
<font color="#3366FF">Pro: Gives us an opportunity to improve resource
copying implementation.</font></li>
</ul>
<font color="#FF0000">Summary: Resource files (non-source, non-class) may
be copied from either source folders. Class files may be copied from library
folders, but never override generated files. Source files never get copied.</font><font color="#3366FF"></font>
<p><font color="#3366FF">Output folder invariant:</font></p>
<ul>
<li>
<font color="#3366FF">For a class file X.class in the output folder O</font></li>
<ul>
<li>
<font color="#3366FF">if exists a Y.java in a source folder that compiles
to X.class then the X.class in O is the one that results from compiling
Y.java</font></li>
<li>
<font color="#3366FF">if exists an X.class </font><font color="#FF0000">in
some library folder with copying on </font><font color="#3366FF">then a
copy of the X.class from the earliest such </font><font color="#FF0000">library
folder</font></li>
<li>
<font color="#3366FF">otherwise no X.class should be present</font></li>
</ul>
<li>
<font color="#3366FF">For a </font><font color="#FF0000">resource (i.e.,
non-source, non-class) </font><font color="#3366FF">file X.other in the
output folder O</font></li>
<ul>
<li>
<font color="#3366FF">if O is also a source folder then any X.other that
lives there</font></li>
<li>
<font color="#3366FF">if exists an X.other </font><font color="#FF0000">in
some source folder with copying on</font><font color="#3366FF"> then a
copy of the X.other from the earliest such </font><font color="#FF0000">source
folder</font></li>
<li>
<font color="#3366FF">otherwise no X.other should be present</font></li>
</ul>
<li>
<font color="#3366FF">For a source file X.java in the output folder O</font></li>
<ul>
<li>
<font color="#3366FF">if O is also a source folder then any X.java that
lives there</font></li>
<li>
<font color="#FF0000">otherwise no X.java should be present</font></li>
</ul>
</ul>
<p><font color="#3366FF">A full builds must achieve the output folder invariant
from <i>arbitrary</i> initial conditions. When output and source folders
do not coincide, a full build should scrub all existing files from the
output folder, regardless of how they got there. When output and source
folders do coincide, a full build should scrub all existing class files
from the output folder, but leave all other files alone.</font><font color="#3366FF"></font></p>
<p><font color="#3366FF">Assuming that a user or client is only adding,
removing, or changing files in source or library folders, but not tampering
with any of the files in the output folder that the Java builder owns,
then an incremental build should re-achieve the output folder invariant.</font><font color="#3366FF"></font></p>
<p><font color="#3366FF">Algorithm:</font><font color="#3366FF"></font></p>
<p><font color="#FF0000">Full build:</font>
<br><font color="#FF0000">&nbsp;&nbsp;&nbsp; Scrub all class files from
the output folder.</font>
<br><font color="#FF0000">&nbsp;&nbsp;&nbsp; if performing resource consolidation
(requires output folder != source folder)</font>
<br><font color="#FF0000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Scrub
all resource files from the output folder.</font>
<br><font color="#FF0000">&nbsp;&nbsp;&nbsp; Compile all source files into
class files in the output folder.</font>
<br><font color="#FF0000">&nbsp;&nbsp;&nbsp; Infill/copy eligible class
files from library folders into the output folder (no overwriting).</font>
<br><font color="#FF0000">&nbsp;&nbsp;&nbsp; if performing resource consolidation
(requires output folder != source folder)</font>
<br><font color="#FF0000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Infill/copy
eligible resource files from source folders into the output folder.</font><font color="#FF0000"></font></p>
<p><font color="#FF0000">Incremental build:</font>
<br><font color="#FF0000">&nbsp;&nbsp;&nbsp; (phase 1) process changes
to library folders:</font>
<br><font color="#FF0000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for
add or remove or change file p/x.class in one of the library folders</font>
<br><font color="#FF0000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if p/x.class in the output folder was not generated by compiler then</font>
<br><font color="#FF0000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
scrub p/x.class from the output folder</font>
<br><font color="#FF0000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
remember to compile source files that depend on p/x</font>
<br><font color="#FF0000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
remember to infill p/x.class</font>
<br><font color="#FF0000">&nbsp;&nbsp;&nbsp; (phase 2) process changes
to source folders:</font>
<br><font color="#FF0000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for
add p/y.java in one of the source folders</font>
<br><font color="#FF0000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
remember to compile source file at path p/y.java</font>
<br><font color="#FF0000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for
remove or change p/y.java in one of the source folders</font>
<br><font color="#FF0000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
scrub any class file p/x.class from the output folder that some p/y.java
compiled into last time</font>
<br><font color="#FF0000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
remember to infill p/x.class</font>
<br><font color="#FF0000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
remember to compile source file at path p/y.java</font>
<br><font color="#FF0000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for
add or remove or change resource p/x.other in one of the source folders</font>
<br><font color="#FF0000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if performing resource consolidation (requires output folder != source
folder)</font>
<br><font color="#FF0000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
scrub p/x.other from the output folder</font>
<br><font color="#FF0000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
remember to infill p/x.other</font>
<br><font color="#FF0000">&nbsp;&nbsp;&nbsp; (phase 3) recompile:</font>
<br><font color="#FF0000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; compile
all remembered source files into the output folder (and any dependent source
files)</font>
<br><font color="#FF0000">&nbsp;&nbsp;&nbsp; (phase 4) infill:</font>
<br><font color="#FF0000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for
each hole p/x.class to infill</font>
<br><font color="#FF0000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
copy first-found file p/x.class in a library folder to p/x.class in the
output folder (no overwriting)</font>
<br><font color="#FF0000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if
performing resource consolidation (requires output folder != source folder)</font>
<br><font color="#FF0000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
for each hole p/x.other to infill</font>
<br><font color="#FF0000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
copy first-found file p/x.other in a source folder to p/x.other in the
output folder</font></p>
<h4>
<font color="#3366FF">How These Changes Solve WSAD's Problem</font></h4>
<p><font color="#3366FF">WSAD would include their classes/ folder on the build
classpath as a library folder with class file copying turned on. Doing
so means that the pre-compiled class files in the library are available
to build against, and will be used whenever there is no corresponding source
code in a source folder. </font><font color="#FF0000">By turning class
file copying on for that library folder (programatically - there is no
UI), the class files in the library folder are automatically consolidated
with the generated class files.</font><font color="#3366FF"></font></p>
<p><font color="#FF0000">Resource files can always be kept in the same
folder as the source files. When the source and output folders do not coincide,
the source folder on the classpath could have copying turned on to ensure
that resource files were copied to the output folder. When the source and
output folders do coincide, further resource file consolidation is not
required (or possible) and the source folder on the classpath would have
copying turned off. The resource files that normally live in the source
folder would automatically be included in the output folder (without copying).</font></p>
<h3>
<font color="#3366FF">Minimizing Class Files</font></h3>
<font color="#3366FF">(This problem is not really an output folder issue.)</font><font color="#3366FF"></font>
<p><font color="#3366FF">WSAD has a special problem. They have class files
in a classes/ folder which they obtain from unzipping a WAR file. They
have a folder of source code; some of the source code may be brand new;
some of the source code may correspond to class files in the classes/ folder.
They need to prune from the classes/ directory those class files for which
corresponding source is available. This allows them to save only those
class files which they actually need.</font><font color="#3366FF"></font></p>
<p><font color="#3366FF">The heart of this operation is identifying the
class files which could have come from a given source file. A source file
can be lightly parsed to obtain fully qualified names for all top-level
types declared within; e.g., a source file com/example/acme/app/Foo.java
might contain types named com.example.acme.app.Foo and com.example.acme.app.FooHelper.
Such type names map directly to corresponding class file name patterns;
e.g., com.example.acme.app.FooHelper would compile to com/example/acme/app/FooHelper.class
and possibly other class files matching com/example/acme/app/FooHelper$*.class.</font><font color="#3366FF"></font></p>
<p><font color="#3366FF">This basic operation can be implemented with the
existing JDOM API (or the proposed AST API): simply open the compilation
unit and read off the names from the package declaration and and top-level
type declarations.</font><font color="#3366FF"></font></p>
<p><font color="#3366FF">Given this basic operation, it is straightforward
to walk any set of source files and use it to prune a given set of class
files. Source files in some folder in the workspace can be monitored with
a resource change listener. It is trivial to delete corresponding class
files incrementally as new source files are added.</font><font color="#3366FF"></font></p>
<p><font color="#3366FF">Conclusion: New API is not required.</font></p>
<h2>
Notes Leftover from Earlier Proposals</h2>
The following notes are retained as background material. They include some
of the other approaches we tried, and problems we ran into.
<p>The Java model has 2 primitive kinds of inputs: Java source files, and
Java library class files. The Java builder produces one primary output:
generated Java class files. Each Java project has a build classpath listing
what kinds of inputs it has and where they can be found, and a designated
output folder where generated class files are to be placed. The runtime
classpath is computed from the build classpath by substituting the output
folder in place of the source folders.</p>
<p>Java "resource" files, defined to be files other than Java sources and
class files, are of no particular interest to the Java model for compiling
purposes. However, these resource files are very important to the user,
and to the program when it runs. Resource files are routinely co-located
with library class files. But it is also convenient for the user if resource
files can be either co-located with source code, or segregated in a separate
folder.</p>
<p>Ideally, the Java model should not introduce constraints on where inputs
and outputs are located. This would give clients and users maximum flexibility
with where they locate their files.</p>
<p>The proposal here has 4 separate parts. Taken in conjunction they remove
the current constraints that make it difficult for some clients to place
their files where they need to be.</p>
<ul>
<li>
<a href="#Java Builder Attitude Adjustment">Change the Java builder's attitude
towards the output folder.</a></li>
<li>
<a href="#Allowing Folders to Play Multiple Roles">Allow folders to play
multiple roles on the same build classpath.</a></li>
<li>
<a href="#Completely eliminate resource file copying behavior">Completely
eliminate the resource copying behavior of current Java builder.</a></li>
<li>
<a href="#Minimize the opportunity for obsolete class files to have bad effects">Minimize
the opportunity for obsolete class files to have bad effects.</a></li>
</ul>
[Revised proposal: Rather than write a completely new proposal, I've added
a note like to the end of each subsequent section describing a revised
proposal.]
<h3>
<a NAME="Java Builder Attitude Adjustment"></a>Java Builder Attitude Adjustment</h3>
To appreciate the difficulties inherent with the Java builder sharing its
output folder with other folk, consider the following workspace containing
a Java project. Assume that this project has not been built in quite a
while, and the user has been manually inserting and deleting class files
in the project's output folder.
<p>Java project p1/
<br>&nbsp;&nbsp;&nbsp; src/com/example/&nbsp; (source folder on build classpath)
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Bar.java
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Foo.java
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Quux.java
<br>&nbsp;&nbsp;&nbsp; bin/com/example/ (output folder)
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Bar.class {SourceFile="Bar.java"}
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Foo.class {SourceFile="Foo.java"}
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Foo$1.class {SourceFile="Foo.java"}
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Internal.class {SourceFile="Foo.java"}
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Main.class {SourceFile="Main.java"}</p>
<p>From this arrangement of files (and looking at the SourceFile attributed
embedded in class files), we can infer that:
<ul>
<li>
Bar.class came from compiling a source file named "Bar.java".</li>
<li>
Foo.class, Foo$1.class, and Internal.class all came from compiling a "Foo.java".
(A single source file will compile to multiple separate class files if
it has nested classes or secondary non-public classes.)</li>
<li>
There are no existing class files corresponding to "Quux.java".</li>
<li>
Main.class came from compiling a source file named "Main.java", which the
workspace does't have.</li>
</ul>
<h4>
Java Builder - Obsolete Class File Deletion</h4>
If the user was to request a full build of this project, how would the
Java builder proceed? Before it compile any source files, it begins by
deleting existing class files that correspond to source files it is about
to recompile. Why? Because obsolete class files left around (a) waste storage
and (b) would be available at runtime where they could cause the program
to run incorrectly.</p>
<p>In this situation, the Java builder deletes the class files corresponding
to Bar.java (i.e., Bar.class), to Foo.java (i.e., Foo.class, Foo$1.class,
and Internal.class), and to Quux.java (none, in this case). The remaining
class files (Main.class) must be retained because it is irreplaceable.</p>
<p>The Java builder takes responsibility for deleting obsolete class files
in order to support automated incremental recompilation of entire folders
of source files. Note that standard Java compilers like javac never ever
delete class files; they simply write (or overwrite) class files to the
output folder for the source files that they are given to compile. Standard
Java compilers do not support incremental recompilation: the user is responsible
for deleting any obsolete class files that they bring about.</p>
<p>If the Java builder is free to assume that all class files in the output
folder are ones that correspond to source files, then it can simply delete
all class files in the output folder at the start of a full build. If it
cannot assume this, the builder is forced to look at class files in the
output folder to determine whether it has source code for them. This is
clearly more expensive that not having to do so. By declaring that it "owns"
the output folder, the current builder is able to makes this simplifying
assumption. Allowing users and clients to place additional class files
in the output folder requires throwing out this assumption.</p>
<p>If the user or client is free to manipulate class files in the output
folder without the Java builder's involvement, then the builder cannot
perform full or incremental builds without looking at and deleting the
obsolete class files from the output folder corresponding to source files
being compiling.</p>
<p>Under the proposed change, the Java builder would need to look at the
class files in the output folder to determine whether it should delete
them. <i>The only files in the output folder that the Java builder would
be entitled to overwrite or delete are class files which the Java builder
would reasonably generate, or did generate, while compiling that project.</i></p>
<ul>
<li>
The Java builder is entitled to overwrite class files in the output folder
that correspond to current source files. Any class file at such a path
is the Java builder's. Even when the actual contents of the class file
came from elsewhere, the builder is always entitled to delete them or overwrite
them with its contents.</li>
<li>
The only files in the output folder that the Java model/builder would be
entitled to delete outright are ones that had been generated by the Java
builder when compiling this project but which no longer correspond to a
current source file. This permits the Java builder to clean up obsolete
class files that it knows it generated, or would have generated, on an
earlier build. It does not have the right to delete other class files,
even ones which do not correspond to a current source file. (Otherwise
the Java builder could justify deleting any class file that it does not
have corresponding source for.) Even for a full build, the Java builder
is not allowed to scrub all class files from the output folder (unless
it happens to know for a fact that the only class files in there ones it
generated).</li>
<li>
The source file is an optional attribute of class files that is not generated
when debug info is suppressed (javac -g:none). Class files in the output
folder without the SourceFile attribute should be treated as if there was
no corresponding source file. This means they never get deleted outright,
although they may still be overwritten as required.</li>
<li>
Note: changing a project to give it a different output folder should absolve
the Java builder of responsibility for any generated class files in the
former output folder. This means the Java builder does not need to perform
cleanup or track anything outside the current output folder.</li>
<li>
Note: adding a source entry to the build classpath causes a bunch of new
source files to enter the frame. Some of the existing class files in the
output folder might now map to these source files, possibly in preference
to where they mapped before. Removing a source entry from the build classpath
causes a bunch of source files to leave the picture. Some of the existing
class files in the output folder might now map to other source files, or
not map to any soure file at all. [We need to decide whether obsolete class
files need to be tracked across the additional and/or removal of source
entries from the build classpath.]</li>
</ul>
This change is not a breaking API change. The old spec said that the Java
model/builder owned the output folder, but didn't further specify what
all that entailed. The new spec will modify this position to allow clients
to store files in the output folder; it will promise that these files are
perfectly safe unless they are in the Java builder's direct line of fire.
<h4>
Java Model - Obsolete Class File Deletion</h4>
<p>There is another facet of the obsolete class file problem that the Java
builder is not in a position to help with.</p>
<p>If the source file Foo.java were to be deleted, its three class files
become obsolete and need to be deleted <i>immediately</i>. Why immediately?
Consider what happens if the class files are not deleted immediately. If
the user requests a full build, the Java builder is presented with the
following workspace:</p>
<p>Java project p1/
<br>&nbsp;&nbsp;&nbsp; src/com/example/&nbsp; (source folder on build classpath)
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Bar.java
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Quux.java
<br>&nbsp;&nbsp;&nbsp; bin/com/example/ (output folder)
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Bar.class {SourceFile="Bar.java"}
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Foo.class {SourceFile="Foo.java"}
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Foo$1.class {SourceFile="Foo.java"}
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Internal.class {SourceFile="Foo.java"}
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Main.class {SourceFile="Main.java"}</p>
<p>Since a full build is requested, the Java builder is not passed a resource
delta tree for the project. This means that the Java builder has no way
of knowing that Foo.java was just deleted. The Java builder has no choice
but to retain the three class files Foo.class, Foo$1.class, and Internal.class,
just as it retains Main.class. This too is a consequence of allowing the
Java builder to share the output folder with the user's class files.</p>
<p>If the obsolete class files are not deleted in response to the deletion
of a source file, these class files will linger around. The Java builder
will be unable to get rid of them.</p>
<p>The proposal is to have the Java model monitor source file deletions
on an ongoing basis and identify and delete any corresponding obsolete
class files in the output folder. This clean up activity must handle the
case of source files that disappear while the Java Core plug-in is not
activated (this entails registering a Core save participant).</p>
<p>Since deleting (including renaming and moving) a source file is a relatively
uncommon thing for a developer to do, the implementation should bet it
does not have to do this very often. When a source file in deleted, its
package name gives us exactly which subfolder of the output folder might
contain corresponding class files that might now be obsolete. In the worst
case, the implementation would need to access all class files in that subfolder
to determine whether any of them have become obsolete. In cases where there
is more than one source folder on the builder classpath, and there is therefore
the possibility of one source file hiding another by the same name, it
is necessary to consult the build classpath to see whether the deleted
source file was exposed or buried.</p>
<h4>
Implementation Tricks</h4>
Some observations and implementation tricks that should help reduce the
space and time impact of doing this.
<ul>
<li>
When one or more source files are deleted from a single source folder,
their position under the source package fragment root gives us the package
name. This package name tells us exactly which subfolder of the output
folder might contain corresponding class files that might now be obsolete.
In the worst case, the implementation would need to access all class files
in that subfolder to determine whether any of them have become obsolete.
This shows that you only need information about a small portion of the
output folder in order to process one or more deletions within a single
source folder.</li>
<li>
A source file named Foo.java typically compiles to a single class file
named Foo.class. There might be more class files (for nested classes and/or
secondary non-public types); and there might be less (when the source file
contains only non-public types with names other than "Foo"). When recording
the extracted source file name information, only the exceptional cases
need to be represented explicitly. For example, only Foo$1.class (derived
from Foo.java) and Internal.class (derived from Foo.java) are unusual;
Bar.class, Foo.class, and Main.class are all derived from source files
with the expected name. This means you can store the information extracted
from class files much more compactly that a simple class file name to SourceFile
string mapping.</li>
<li>
There is often only one source folder on the builder classpath. In this
case, all source files in the source folder get compiled; there is no possibility
of one source file "hiding" another by the same name. This observation
can be used to avoid checking for source file hiding.</li>
</ul>
<h3>
When all else fails</h3>
A special concern is that the user must be able to recover from crashes
or other problems that result in obsolete class files being left behind
in the output folder. It can be very bad when this kind of thing happens
(and it does happen, despite our best efforts), and can undercut the user's
confidence in the Java compiler and IDE. In a large output folder that
contains important user files, the user can't just delete the output folder
and do a full build. The user has no easy way to distinguish class files
with corresponding source from ones without. A simple way to address this
need would be to have a command (somewhere in the UI) that would delete
all class files in the output folder for which source code is available
("Delete Generated Class Files"). This would at least give the user some
help in recovering from these minor disasters.
<p>[Revised proposal: The Java builder remembers the names of the class
files it has generated. On full builds, it cleans out all class files that
it has on record as having generated; all other class files are left in
place. On incremental builds, it selectively cleans out the class files
that it has on record as having generated corresponding to the source files
that it is going to recompile. There is no need to monitor source file
deletions: corresponding generated class files will be deleted on the next
full build (because it nukes them all) or next incremental build (because
it sees the source file deletion in the delta). The Java builder never
looks at class files for their SourceFile attributes. A full build always
deletes generated class files, so there's no need to a special UI action.]</p>
<h3>
<a NAME="Allowing Folders to Play Multiple Roles"></a>Allowing Folders
to Play Multiple Roles</h3>
<p>The proposed change is to consistently allow the same folder to be used
in multiple ways on the same build classpath.</p>
<ul>
<li>
As source folder and as output folder.</li>
<ul>
<li>
N.B. This is currently supported (e.g., when folder is the project root).</li>
<li>
Allows generated class files to be co-located with Java source files.</li>
<li>
Since output folder is automatically included on runtime classpath, this
arrangement would automatically make any class files or resource files
available at runtime.</li>
<ul>
<li>
However, these class files would not be seen at compile time library folder.</li>
<li>
Recommendation: when class files or resources are present in a folder,
there should always be a library folder entry on the build classpath for
it.</li>
</ul>
</ul>
<li>
As source folder and as library folder.</li>
<ul>
<li>
N.B. This is currently disallowed.</li>
<li>
Allows library class files to be co-located with Java source files.</li>
<li>
Allows resource files to be co-located with Java source files.</li>
<li>
In virtue of being a library entry on the build classpath, the folder is
used at compile time for library class files and is included on the runtime
classpath.</li>
</ul>
<li>
As library folder and as output folder.</li>
<ul>
<li>
N.B. This is currently disallowed.</li>
<li>
Allows library class files to be co-located with generated class files.</li>
<li>
Allows resource files to be co-located with generated class files.</li>
<li>
Remove duplicate entry when forming the runtime class path.</li>
<li>
Note that the generated class files in this library folder are ignored
by the builder because it has source for all these by definition.</li>
</ul>
<li>
As source folder and as output folder and as library folder.</li>
<ul>
<li>
This is just a combination of all of above.</li>
<li>
Allows library class files, generated class files, and resource files to
be co-located with Java source files.</li>
<li>
Simple "one folder Java development" setup for someone with library class
files and possibly resources.</li>
</ul>
</ul>
<p>This change is not a breaking change; it would simply allow some classpath
configurations that are currently disallowed to be considered legitimate.
The API would not need to change.</p>
<p>[Revised proposal: Many parts of the Java model assume that library
folders are relatively quiet. Allow a library folder to coincide with the
output folder would invalidate this assumption, which would tend to degrade
performance. For instance, the indexer indexes libraries and source folders,
but completely ignores the output folder. If the output folder was also
a library, it would repeatedly extract indexes for class files generated
by the builder.</p>
<p><i>N.B. This means that the original scenario of library class files
in the output folder is cannot be done this way. It will need to be addressed
in some other way (discussed later on).</i></p>
<p><font color="#3366FF">The identity criteria for package fragment root
handles are based on resources/paths and do not take kind (source vs. binary)
into account. This means that a source folder and a library folder at the
same path map to the same package fragment root handle! Thus allowing a
source folder to coincide with a library folder cannot be supported without
revising Java element identity criteria (which is due for an overhaul,
but that's a different, and bigger, work item).</font></p>
<br>]
<h3>
<a NAME="Completely eliminate resource file copying behavior"></a>Completely
eliminate resource file copying behavior</h3>
<p>The current Java builder copies "resource" files from source folders to
the output folder (provided that source and output do not coincide). Once
in the output folder, the resource files are available at runtime because
the output folder is always present on the runtime class path.</p>
<p>This copying is problematic:</p>
<ul>
<li>
Copying creates duplicates of resource files.</li>
<ul>
<li>
Takes up extra disk space.</li>
<li>
Copying resources takes extra time.</li>
<li>
Increases risk of user confusion (modify the copy).</li>
</ul>
<li>
Copying is out of character for Java builder.</li>
<ul>
<li>
Java builder should compile Java source files to binary class files.</li>
</ul>
<li>
Copying behavior is quirky.</li>
<ul>
<li>
Resources are never copied from a source folder that coincides with the
output folder.</li>
<li>
Resources are copied from a source folder that does not coincide with the
output folder, even if the output folder happens to be another source folder.</li>
<li>
Modifying the copy and building causes the file to be deleted (!); it is
replaced by a fresh copy on the next full build.</li>
<li>
When there are several resource files with same name, it is impossible
to reliably control which one ends up in the output folder.</li>
<li>
When the project source is the project itself, and the output is in a folder
under the project, the builder copies the .classpath file into the output
folder too.</li>
</ul>
</ul>
<p>The proposal is to eliminate this copying behavior. The proper way to handle
this is to include an additional library entry on the build classpath for
any source folders that contain resources. Since library entries are also
included on the runtime classpath, the resource files contained therein
will be available at runtime.</p>
<p>We would beef up the API specification to explain how the build classpath
and the runtime classpath are related, and suggests that one deals with
resource files in source folders using library entries. This would be a
breaking change for clients or users that rely on the current resource
file copying behavior.</p>
<p>The clients that would be most affected are ones that co-locate their
resource files with their source files in a folder separate from their
output folder. This is a fairly large base of customers that would need
to add an additional library entry for their source folder.</p>
<p>It would be simple to write a plug-in that detected and fixed up the
Java projects in the workspace as required. By the same token, the same
mechanism could be built in to the Java UI. If the user introduces a resource
files into a source folder that had none and there is no library entry
for that folder on the build classpath, ask the user whether they intend
this resource file to be available at runtime.</p>
<p>(JW believes that WSAD will be able to roll with this punch.)</p>
<p>[Revised proposal: Retain copying from source to output folder where
necessary.</p>
<ul>
<li>
Source folder different from output folder, no additional source folders:
copy resources from source folder to output folder (current behavior).</li>
<li>
Source folder different from output folder, additional source folders:
copy resources from all source folders to output folder honoring build
classpath ordering (current behavior).</li>
<li>
Source folder same as output folder, and no additional source folders:
no copying (current behavior).</li>
<li>
Source folder same as output folder, and additional source folders: error
(new behavior).</li>
</ul>
This eliminates the screw case where resources get copied from one source
folder into another source folder, possibly overwriting client data.]
<h3>
<a NAME="Minimize the opportunity for obsolete class files to have bad effects"></a>Minimize
the opportunity for obsolete class files to have bad effects</h3>
<p>The Java compiler should minimize the opportunity for obsolete class files
to have bad effects.</p>
<p>Consider the following workspace:</p>
<p>Java project p1/
<br>&nbsp;&nbsp;&nbsp; src/com/example/&nbsp; (source folder on build classpath)
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; C1.java {package com.example;
public class C1 {}}
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; C2.java {package com.example;
public class C2 extends Secondary {})
<br>&nbsp;&nbsp;&nbsp; lib/com/example/ (library folder on build classpath)
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; C1.class {from compiling
an old version of C1.java
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; that read
package com.example; public class C1 {}; class Secondary {}}
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; C2.class {from compiling
an old but unchanged version of C2.java}
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Secondary.class {from compiling
an old but unchanged version of C2.java}
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Quux.class {from compiling
Quux.java}</p>
<p>Assume the source folder precedes the library folder on the build classpath
(sources should always precede libraries).</p>
<p>When the compiler is compiling both C1.java and C2.java, it should not
satisfy the reference to the class com.example.Secondary using the existing
Secondary.class because the SourceFile attributes shows that Secondary.class
is clearly an output from compiling C1.java, not an input. In general,
the compiler should ignore library class files that correspond to source
files which are in the process of being recompiled. (In this case, only
Quux.class is available to satisfy references.) The Java builder does not
do this.</p>
<p>Arguably, the current behavior should be considered a bug. (javac 1.4
(beta) has this bug too.) Fixing this bug should not be a breaking change.</p>
<p>When the SourceFile attribute is not present in a class file, there
is no choice but to use it.</p>
<p>[Revised proposal: Maintain current behavior.]</p>
<h3>
<font color="#000000">Library Copying Proposal</font></h3>
<p><font color="#000000">The proposal is to arrange to copy class files from
a certain library folder into the output folder. The library folder would
have to be represented by a library classpath entry so that the compiler
can find any class files it needs to compile source files. Copying the
class files to the output folder would unite them with the class files
generated by the compiler. Since there may be source code in the source
folder corresponding to some of the classes in the library folder, the
builder should only use a class file when source is available.</font></p>
<p><font color="#000000">Desired semantics:</font></p>
<p><font color="#000000">S (source folder)</font>
<br><font color="#000000">L (library folder)</font>
<br><font color="#000000">O (output folder)</font></p>
<p><font color="#000000">Invariant:</font></p>
<p><font color="#000000">x.class in O =</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp; if some y.java in S generates
x.class then</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; x.class
from compiling x.java in S</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp; else</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if
x.class in L then</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
x.class in L</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
none</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; endif</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp; endif</font></p>
<p><font color="#000000">Full builds achieve invariant.</font>
<br><font color="#000000">Incremental builds maintain invariant.</font></p>
<p><font color="#000000">Full build:</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp; Scrub all class files from
O.</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp; Compile all source files in
S into class files in O.</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp; Infill/copy all class files
from L to O (no overwriting).</font></p>
<p><font color="#000000">Incremental build:</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp; (phase 1) process all changes
to L:</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for
delete or change x.class in L</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if
x.class in O was not generated by compiler then scrub x.class from O</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for
add or change x.class to L</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
remember to infill x.class</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp; (phase 2) process negative
changes to S:</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for
delete or change y.java from S</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
scrub any class file x.class from O that y.java compiled into</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
remember to infill x.class</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp; (phase 3) process positive
changes to S:</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for
add or change y.java from S</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
compile y.java into O</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp; (phase 4) Infill/copy indicated
class files from L to O (no overwriting).</font></p>
<p><font color="#000000">We will look at ways to implement the above behavior
that do not involve changing the Java builder. This would mean that a customer
(such as WSAD) that requires library copying would be able to add it themselves;
otherwise, we will need to complicate the Java builder (which is complex
enough as it is) and integrate the mechanism into JDT Core.</font></p>
<h4>
<font color="#000000">Copying pre-builder</font></h4>
<p><font color="#000000">Could the copying of class files from the library
folder L to the output folder O be accomplished in a separate incremental
project builder that would run <i>before</i> the Java builder?</font></p>
<p><font color="#000000">Assume the Java builder manages its own class
files in the output folder and knows nothing of the pre-builder. Conversely,
assume that the pre-builder has no access to the insides of the Java builder.</font></p>
<p><font color="#000000">Pre-copying of class files to the output folder
cannot handle the case where a source file gets deleted and a pre-existing
class file in the library folder should now take its place. The Java builder,
which runs last, deletes the class file; the pre-builder has missed its
chance and does not get an opportunity to fill that hole. When this happens
on a full build, the full build does not achieve the invariant. This is
unacceptable.</font></p>
<p><font color="#000000">Here's the nasty case:</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp; S (source folder): Bar.java
(but recently has Foo.java as well)</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp; L (library folder): Foo.class</font></p>
<p><font color="#000000">On a full build</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp; Pre-builder runs first:</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Scrubs
Foo.class and Bar.class from O.</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Copies
in Foo.class from L to O.</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp; Java Builder runs second:</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Scrubs
Foo.class from O (generated by Java builder from Foo.java on last build).</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Compile
Bar.java into Bar.class O (Foo.java is no longer around).</font></p>
<p><font color="#000000">The output folder should contain a copy of Foo.class
from L since there is no equivalent source file that compiles to Foo.class.
It doesn't.</font></p>
<h4>
<font color="#000000">Copying post-builder</font></h4>
<p><font color="#000000">Could the copying of class files from the library
folder to the output folder be accomplished in a separate incremental project
builder that would run <i>after</i> the Java builder?</font></p>
<p><font color="#000000">Again, assume the Java builder manages its own
class files in the output folder and knows nothing of the post-builder,
and conversely.</font></p>
<p><font color="#000000">Post-copying of class files to the output folder
(no overwriting) cannot handle the case where library class files are changed
or deleted since the last build, because the post-builder is never in a
position to delete or overwrite class files in the output folder (they
might have been generated by the Java builder). Once lost, the invariant
cannot be reachieved no matter how many full builds you do (you're stuck
with stale or obsolete class files). This is unacceptable.</font></p>
<h4>
<font color="#000000">Combination of pre- and post-builder</font></h4>
<p><font color="#000000">Could the copying of class files from the library
folder to the output folder be accomplished by a pair of separate incremental
project builders that run on either side of the Java builder?</font></p>
<p><font color="#000000">Assume the Java builder manages its own class
files in the output folder and knows nothing of the pre-builder and post-builder,
and the pre- and post-builders have no access to the insides of the Java
builder.</font></p>
<p><font color="#000000">Full build:</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp; Pre-builder runs first:</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Scrubs
all class files from O.</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp; Java Builder runs second:</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Scrubs
all class files from O generated by Java builder.</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Compiles
all source files into O.</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp; Post-builder runs third:</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Infill/copy
class files from L to O (no overwriting).</font></p>
<p><font color="#000000">Incremental build when L changes:</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp; Pre-builder runs first:</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; For
delete or change x.class in L</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Does nothing (FAILs if no corresponding source file)</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; For
add x.class to L</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Infill/copy Foo.class from L to O (no overwriting).</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp; Java Builder runs second:</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Recompiles
classes that depend on affected class files in L.</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp; Post-builder runs third:</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Infill/copy
class files from L to O (no overwriting).</font></p>
<p><font color="#000000">Incremental build - changes to source folder:</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp; Pre-builder runs first:</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Does
nothing since library did not change.</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp; Java Builder runs second:</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Compiles
source files into O.</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp; Post-builder runs third:</font>
<br><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Infill/copy
class files from L to O (no overwriting).</font></p>
<p><font color="#000000">An incremental build may fail in the case of a
library class file being changed or deleted, leading to stale or obsolete
class files in the output folder. Fortunately, a full build always achieves
the invariant, and can be used to repair the damage due to changes to the
library.</font></p>
<p><font color="#000000">So while the combination of pre- and post-builders
is not perfect, it does work in many cases. If the user could do a full
build after making changes to the library folder, they would avoid all
the problems. The solution has the advantage of not requiring anything
special from the Java Core (i.e., WSAD should be able to implement it themselves).</font>
An example implementation is available <a href="libcopy.html">here</a></p>
<h3>
<font color="#000000">Resources in Output Folder</font></h3>
<p><font color="#000000">When the source folder and output folder coincide,
there is no problem keeping resource files in the output folder since they
are not at risk of being overwritten (no with the proposed change to disable
resource copying when the source folder and output folder coincide).</font></p>
<p><font color="#000000">When the source folder and output folder do not
coincide, keeping resource files in the output folder on a permanent basis
encounters two issues:</font></p>
<p><font color="#000000">(1) The first issue is that output folder has
no presence in the packages view. Any resources that permanently resided
in the output folder would therefore be invisible during regular Java development.
One would have to switch to the resource navigator view to access them.</font></p>
<p><font color="#000000">The packages view only shows resource files in
source and library folders. Changing the packages view to show resources
in the output folder is infeasible. Including the output folder on the
classpath as a library folder was discussed at length above and is out
of the question. Including the output folder on the classpath as a source
folder is an option (in fact, it's exactly what you get when your source
and output folders coincide).</font></p>
<p><font color="#000000">(2) The second issue is that resource files in
the output folder are in harm's way of resources of the same name being
copied from a source folder.</font></p>
<p><font color="#000000">If resources existing in the output folder are
given precedence over the ones in source folders, then the ones from source
folders would only be copied once and nevermore overwritten. Copies in
the output folder would get stale or obsolete; automatic cleanup would
not be possible.</font></p>
<p><font color="#000000">On the other hand, if resources existing in source
folders are given precedence over the ones in the output folders, then
one that exists only in the output folders would be permanently lost if
a resource by the same name was ever to be created in a source folder.
It is a dangerous practice to allow the user to store important data in
a place that could be clobbered by an automatic mechanism that usually
operates unseen to the user.</font></p>
<p><font color="#000000">Conclusion: Keeping resource files in the output
folder on a permanent basis is not well supported at the UI, and should
only be done if the resource files can be considered expendable.</font>
</p>
</body>
</html>