Please consider this trivial code C.java: public class C { public static void main(String[] args) throws Exception { System.out.println("main() execution started"); } }
> ls C.java Similar to a previous discussion[1] while doing random testing, I ended up compiling C.java explicitly using javac: > javac C.java > ls C.java C.class and then at a later date tried to use the source file launcher feature of Java 11 (without realizing C.class was already present in the dir): > java C.java This threw the error: error: class found on application class path: C Although the error isn't that clear for the reason I note in [2], having run into this before, I was aware what this meant and deleted the C.class and moved on. The important part here is that the source launcher noticed this condition and aborted even before it auto compiled(?) and launched and executed the main() of the program. Now consider a slight modification to that source file: public class C { public static void main(String[] args) throws Exception { System.out.println("main() execution started"); final B b = new B(); System.out.println("Done"); } private static class B { } } Again at some point I compiled this explicitly using javac, so my directory is (among other things): > ls C$B.class C.class C.java Then ran the source file launcher feature: > java C.java error: class found on application class path: C As expected, ran into the same previous error. As before, in order to move on, deleted C.class: > rm C.class but forgot to delete the nested static class that belonged to it. So the directory now contained: > ls C$B.class C.java Now used the source launcher feature again: > java C.java This time it failed with: main() execution started Exception in thread "main" java.lang.IllegalAccessError: failed to access class C$B from class C (C$B is in unnamed module of loader 'app'; C is in unnamed module of loader com.sun.tools.javac.launcher.Main$MemoryClassLoader @1b1473ab) at C.main(C.java:4) The error message isn't clear to pinpoint the issue, but at least the reference to MemoryClassLoader was a hint that was enough for me to understand where to look. It did take me a few minutes to realize that C$B.class was lying around which I needed to remove too. However, IMO, the important part here is that unlike in the first case where the program itself wasn't launched and instead was aborted early, in this case the program did get executed (notice the System.out.println "main() execution started" message that got printed) and failed at runtime. Would it be possible to make these two behaviours consistent and detect such cases and abort early here too? Or would that add too much complexity to this feature? Finally, any thoughts on the error messages for this feature to make it a bit easier in terms of debugging (classloading) issues like these? [1] http://mail.openjdk.java.net/pipermail/jdk-dev/2018-June/001425.html [2] http://mail.openjdk.java.net/pipermail/jdk-dev/2018-June/001438.html -Jaikiran