Source file launcher - Handling of pre-compiled classes of the source file
seth lytle
seth.lytle at gmail.com
Fri Sep 14 22:00:00 UTC 2018
ah - compiler semantics vs launcher semantics, and the source code launcher
lives in both worlds
javac refuses to compile two sources for the same class
javac will compile a source file for a class that exists on the classpath
(and even overwrite a class on the classpath)
java accepts two class files for the same class on the classpath (favors
the first)
java -jar accepts a jar containing classes that also exist on the classpath
(favors the jar)
java refuses to launch a source file for a class that exists on the
classpath
the source code launcher "feels" like an outlier to me, but it could
certainly go either way
and i guess the source code launcher is an outlier anyway, as it decouples
the first toplevel class name from the file name
On Fri, Sep 14, 2018 at 1:49 PM, Jonathan Gibbons <
jonathan.gibbons at oracle.com> wrote:
> Seth,
>
> The reason for reporting an error is to prevent the "wrong" class being
> used!
>
> -- Jon
>
>
> On 09/14/2018 10:14 AM, seth lytle wrote:
>
>> this behavior of throwing an error if the class is found twice on the
>> classpath strikes me as unusual - afaik, in all other cases, java is fine
>> with finding multiple implementations on the classpath and uses the first
>> found (similar to the unix path, which also allows overriding by providing
>> an explicit path) and this is really one of the powerful features of java
>> -
>> allowing you to swap out one class for another seamlessly. and for rapid
>> prototyping, "java -cp target/classes:$cp src/myPackage/Stuff.java" runs
>> much faster than "mvn package -Dexec.mainClass=myPackage.Stuff", and
>> doubly
>> so for mvnDebug
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>> On Fri, Sep 14, 2018 at 3:33 AM, Peter Levart <peter.levart at gmail.com>
>> wrote:
>>
>> Hi Jaikiran,
>>>
>>> Forwarding to compiler-dev as the core of source file launcher feature is
>>> produced there...
>>>
>>> The check for main class is performed after compilation (which actually
>>> produces the main class name).
>>>
>>> I think it would be possible to check for all classes compiled from the
>>> source file after compilation without to much complication. The
>>> compilation
>>> produces classes and stores them into a Map<String, byte[]>. The keySet()
>>> of that map is a Set of compiled class names. Each of them could be
>>> tested
>>> via .getResource() invoked upon the application class loader. The error
>>> could even point to the URL of the conflicting class file that way...
>>>
>>> Regards, Peter
>>>
>>>
>>> On 09/14/2018 07:36 AM, Jaikiran Pai wrote:
>>>
>>> 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
>>>
>>>
>>>
>>>
>>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openjdk.java.net/pipermail/compiler-dev/attachments/20180914/abcecc71/attachment.html>
More information about the compiler-dev
mailing list