openjdk-jfx icon indicating copy to clipboard operation
openjdk-jfx copied to clipboard

JDK-8230119: NullPointerException if Application subclass has non-static main(String[]) method

Open tkslaw opened this issue 6 years ago • 8 comments
trafficstars

When using the below as a main-class:

import javafx.application.Application;
import javafx.stage.Stage;

public class App extends Application {

    @Override
    public void start(Stage primaryStage) {
        throw new AssertionError("Failed to reproduce NPE.");
    }

    // non-static
    public void main(String[] args) {
        Application.launch(args);
    }

}

The following exception is thrown:

Exception in thread "main" java.lang.reflect.InvocationTargetException
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:567)
	at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1051)
Caused by: java.lang.NullPointerException
	at java.base/java.lang.reflect.Method.invoke(Method.java:560)
	at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:464)
	at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:363)
	... 5 more

Which is caused by LauncherImpl calling mainMethod.invoke(null, new Object[]{args}), which is just assuming the main method it found is static.


While I doubt such a situation arises often, it came up recently in a question on Stack Overflow. The issue here is the error message does not make the cause obvious. It'd be beneficial if LauncherImpl checked whether or not the method is static and, if it's not, throw a more detailed exception. For example:

if (!Modifier.isStatic(mainMethod.getModifiers()) {
    throw new RuntimeException(mainMethod + " must be static");
}
mainMethod.invoke(null, (Object) args);

tkslaw avatar Aug 23 '19 10:08 tkslaw

In this case we shouldn't throw an exception, but we should ignore that main method and launch the Application in the same manner as if the main method were not there at all.

kevinrushforth avatar Aug 23 '19 13:08 kevinrushforth

My assumption was that a non-static main method in an Application subclass being used as the main-class is obviously a mistake on the programmer's part, thus the detailed exception. However, I'm happy to consider that assumption incorrect (e.g. because the method may be legitimate). My only worry is ignoring the method altogether might hide the issue where the method is supposed to be static but isn't.

tkslaw avatar Aug 24 '19 01:08 tkslaw

ignoring the method altogether might hide the issue where the method is supposed to be static but isn't.

I agree. Maybe a warning should be emitted.

nlisker avatar Aug 24 '19 02:08 nlisker

That's a fair point about emitting a warning, since it is likely a mistake. Similarly, if the main method is not public, a warning seems a good idea. I would only want to emit a warning if the signature matches, meaning void main(String[] args) would emit a warning, but void main() would be ignored, since it isn't the same method.

One thing to point out, which might help inform what we want to do here, is that during the review of the launcher test changes needed as part of decoupling of JavaFX from the JDK, the JDK team raised the question of whether the Java launcher support for launching JavaFX Application classes without a main method should be deprecated and removed in a future version. If that is the route we end up going, then a public static void main(String[]) method would be required or else an error would occur. I think that also suggests that a warning is better than silently ignoring it.

kevinrushforth avatar Aug 24 '19 12:08 kevinrushforth

I agree a warning seems the best option.

Also, if the launching-without-main-method functionality does get deprecated then a warning should be emitted if the main-class is missing the public static void main(String[]) method, saying something like "main method will be required in a future release". To be honest, I was surprised the functionality remained after JavaFX was decoupled from the JDK.

tkslaw avatar Aug 24 '19 12:08 tkslaw

if the launching-without-main-method functionality does get deprecated then a warning should be emitted if the main-class is missing the public static void main(String[]) method, saying something like "main method will be required in a future release".

Yes, something along those lines was exactly my thinking.

To be honest, I was surprised the functionality remained after JavaFX was decoupled from the JDK.

It only stayed in because I successfully argued that it would be too disruptive to remove it with no warning and potentially break existing applications. This reminds me that I was supposed to file an RFE to deprecate and then remove it, but haven't done so yet.

kevinrushforth avatar Aug 24 '19 12:08 kevinrushforth

I filed JDK-8230119 in JBS to track this.

kevinrushforth avatar Aug 24 '19 12:08 kevinrushforth

Worth noting is that a non-public static void main(String[]) method is silently ignored today. As I mentioned above, when/if we fix JDK-8230119, I think we should emit a warning in that case as well.

kevinrushforth avatar Aug 24 '19 13:08 kevinrushforth