On Mon, 15 Apr 2024 07:36:05 GMT, Jan Lahoda <jlah...@openjdk.org> wrote:
>> Consider code like: >> >> public class MainClass { >> public MainClass() { >> System.out.println("Constructor called!"); >> } >> public static void main() { >> System.out.println("main called!"); >> } >> } >> >> and compile and run it, with preview enabled, like: >> >> $ javac /tmp/MainClass.java >> $ java --enable-preview -classpath /tmp MainClass >> Constructor called! >> main called! >> >> >> That is wrong, as the `main` method is static, and there is no need to >> create a new instance of the class. >> >> The reason is that as launcher attempts to invoke the main method, it goes >> in the following order: 1) static-main-with-args; 2) >> instance-main-with-args; 3) static-main-without-args; 4) >> instance-main-without-args. But, for the instance variants, the code first >> creates a new instance of the given class, and only then attempts to lookup >> the `main` method, and will pass to the next option when the `main` method >> lookup fails. So, when invoking static-main-without-args, the current class >> instance may be created for instance-main-with-args, which will then fail >> due to the missing `main(String[])` method. >> >> The proposed solution to this problem is to simply first do a lookup for the >> `main` method (skipping to the next variant when the given main method does >> not exist, without instantiating the current class). >> >> There is also a relatively closely related problem: what happens when the >> constructor throws an exception? >> >> public class MainClass { >> public MainClass() { >> if (true) throw new RuntimeException(); >> } >> public void main() { >> System.out.println("main called!"); >> } >> } >> >> >> when compiled an run, this produces no output whatsoever: >> >> $ javac /tmp/MainClass.java >> $ java --enable-preview -classpath /tmp MainClass >> $ >> >> >> This is because any exceptions thrown from the constructor are effectively >> ignored, and the launcher will continue with the next variant. This seems >> wrong - the exception should be printed for the user, like: >> >> $ java --enable-preview -classpath /tmp/ MainClass >> Exception in thread "main" java.lang.RuntimeException >> at MainClass.<init>(MainClass.java:3) >> >> >> This patch proposes to do that by not consuming the exceptions thrown from >> the constructor, and stop the propagation to the next variant. > > Jan Lahoda has updated the pull request incrementally with one additional > commit since the last revision: > > Reflecting review feedback. src/java.base/share/native/libjli/java.c line 419: > 417: invokeInstanceMainWithArgs(JNIEnv *env, jclass mainClass, jobjectArray > mainArgs) { > 418: jmethodID constructor = (*env)->GetMethodID(env, mainClass, > "<init>", "()V"); > 419: CHECK_EXCEPTION_FAIL(); Shouldn't this also not be checked until you know you have an instance method? ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/18753#discussion_r1567092479