Summary
Modify the java source launcher to execute an inherited instance main method from the referenced class, rather than from the declaring type. This matches the current behavior of the java class launcher.
Problem
In the source launcher the candidate main method is executed in the context of the declaring class/interface/abstract class, rather than in the context of the referenced class:
In the following example the launcher should call new A().main(), but rather new B().main() is called.
Example 1:
Code
// A.java
class A extends B {}
// B.java
class B {
void main() {
System.out.println(getClass().getName());
}
}
Commands
$ java A.java
B // expected "A" here
$ java B.java
B
When using the same example with: "javac A.java" and "java A" we get the expected output of "A".
When A inherits its instance main method, either from an abstract class or from a default method on an interface, the source launcher also attempts to instantiate the declaring type. In both cases this results in an output of error: abstract class: B cannot be instantiated. Here the "javac + class launcher" path handles both cases correctly and prints the expected "A".
Solution
Remove the logic for recovering the main class from the main method's declaring class:
Class<?> mainClass = mainMethod.getDeclaringClass();
And rather store the referenced class where we found the mainMethod and use this as the context to execute from.
Specification
No changes to the specification.
The specification is clear here, that the initial class (referred to above as referenced class) is the class of which an instance must be created and not the declaring class.
"If the candidate main method is an instance method then first an instance of the initial class must be created." -- JLS 12.1.4
The standard java launcher semantics match this statement, but the source launcher semantics do not.
- csr of
-
JDK-8376534 Source launcher instantiates wrong class on inherited instance main
-
- Resolved
-