JDK-8351188 : java launcher's implementation of (instance) main method selection can cause unexpected classloading failures
  • Type: Bug
  • Component: tools
  • Sub-Component: launcher
  • Affected Version: 23
  • Priority: P4
  • Status: Closed
  • Resolution: Delivered
  • Submitted: 2025-03-04
  • Updated: 2025-05-05
  • Resolved: 2025-05-05
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 25
25Resolved
Related Reports
Causes :  
Duplicate :  
Duplicate :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Description
Consider the following two trivial java files:

Foo.java:

    public class Foo {
        public static void main(final String[] args) throws Exception {
            System.out.println("hello world");
        }

        // never invoked or referenced (dead) code
        private SomeNonExistentRuntimeType doNothing() throws Exception {
            return null;
        }
    }

SomeNonExistentRuntimeType.java:

public class SomeNonExistentRuntimeType {
	
}

Compile them as follows:

javac Foo.java SomeNonExistentRuntimeType.java

Now delete (only) the compiled SomeNonExistentRuntimeType.class file to simulate the case where that class is missing at runtime (in the classpath).

Now run:

java Foo

This will rightly print:

hello world

and the program exits normally. Now, using a JDK which has "Instance Main Methods" preview feature, like JDK 23, 24 or mainline, --enable-preview and run the same program again:

java --enable-preview Foo 

This results in the application failing to launch with the following exception:

Error: Unable to initialize main class Foo
Caused by: java.lang.NoClassDefFoundError: SomeNonExistentRuntimeType

This is due to the current implementation of the launcher where, to support JEP-495 https://openjdk.org/jeps/495, it tries to identify potential "main" methods and while doing so it ends up using the existing reflection based infrastructure where it iterates over each method of the main class and tries to resolve the types of the method params and return types, thus resulting in additional classloading and potential classloading failures of non-existent types (that may be unused by the application at runtime).

I think the launcher's implementation can be changed to minimize the methods it looks for (it just needs to look for methods named "main") and only resolve the referenced types if that "main" method is determined as the one to invoke.
Comments
It is needed to remove corresponding tests from ProblemList-enable-preview.txt
05-05-2025

Changes in https://bugs.openjdk.org/browse/JDK-8344706 addressed this issue.
05-05-2025

Re-tested with 25-ea (no more --enable-preview on the command-line) and this specific case with the canonical and well-known entry-point: > public static void main(String[] args) {...} works as expected. It also works with a public instance main method that has a single `String[]` parameter: > public void main(String[] args) {...} It still fails with the same error message (and reason) when using a non-public main method and also fails for public main methods without any parameters.
05-05-2025

Interesting. I'll take a look and link the underlying issue with this one.
23-04-2025

There's currently a PR open https://github.com/openjdk/jdk/pull/24438 for "8344706: Compiler Implementation of Compact Source Files and Instance Main Methods" which does some changes in the MethodFinder internal implementation code. I don't know if those changes will have any useful impact on this current issue, but it was on my list to take a deeper look at that change and run the reproducer against it to see if it makes and difference. Specifically this change https://github.com/openjdk/jdk/pull/24438#pullrequestreview-2783300705
23-04-2025

A trivial work-around would be to collect and discard all throwables when searching for "main" methods - those errors should show up later in a similar form, when their code is actually hit. Or is the class flagged as "could not be resolved" by the application class loader?
23-04-2025

Not sure if the suggestion can work as establishing which methods are present in the class will require them all to be resolved, which will encounter the missing class. I think you would need a new internal API and VM support to "peek" into a class and selectively enquire about the existence of specific named methods.
17-04-2025