Summary
Add a new compiler lint flag output-file-clash
that will enable detection of output file clashes. An output file clash is when the compiler writes two different output files, but due to the behavior of the filesystem these files end up being written to the same underlying filesystem file.
Problem
Sometimes the compiler thinks it's writing out two separate files, but due to the way the underlying filesystem maps Path
's to actual files, it's really writing the same file twice.
This is usually due to case-insensitive filesystems, but can also be due to how a filesystem "normalizes" file names. For example, on MacOS, compiling this class will generate such a clash:
public class Test {
interface Cafe\u0301 {
}
interface Caf\u00e9 {
}
}
The reason is that \u0301
is the Unicode character "Combining Acute Accent" which means "stick an accent over the previous character". So MacOS normalizes the letter e
followed by a \u0301
into a Unicode \u00e9
, that is, é
. However, the Java language treats these the two names Cafe\u0301
and Caf\u00e9
as distinct.
Of course, on any case-insensitive filesystem a class like this would cause an output file clash for the file Test$Inner.class'
:
public class Test {
class Inner {
}
class INNER {
}
}
Solution
There's no way to avoid this problem without changing the way the compiler maps output files to filesystem filenames, which would be too disruptive.
So the solution here is to simply provide a way for people experiencing this problem to convert what is currently a runtime error into a compile-time warning (or error with -Werror
). This is by adding a new lint flag output-file-clash
that enables output file clash detection. The term "output file" covers class files, source files, and native header files.
If the flag is not used, then the compiler should behave exactly as it currently does. Therefore, there should be no backward compatibility risk.
An alternative, a more aggressive approach would be to always enable this behavior and/or make it an error instead of a warning.
Specification
New addition to "javac --help-lint":
output-file-clash
Warn when an output file is overwritten during compilation. This can occur, for example,
on case-insensitive filesystems. Covers class files, native header files, and source files.
An example of the new warning:
$ javac -Xlint:output-file-clash Test.java
warning: [output-file-clash] output file written more than once: /Users/archie/test/Test$Café.class
1 warning
- csr of
-
JDK-8296656 java.lang.NoClassDefFoundError exception on running fully legitimate code
- Resolved