Every JavaFX application I've run throws two NullPointerExceptions. They don't prevent or even affect the execution of the projects, and I can only see them if I run my applications in debug mode. I'm even having this issue with the HelloWorld sample from Oracle and this minimal program:
public class JavaFXTSample extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
StackPane iAmRoot = new StackPane();
Scene scene = new Scene(iAmRoot, 300, 250);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main (String[] args) {
launch(args);
}
}
Here is the stack trace of the first error:
Thread [main] (Suspended (exception NullPointerException))
SystemProperties.setVersions() line: 81 [local variables unavailable]
SystemProperties.lambda$static$28() line: 67
30621981.run() line: not available
AccessController.doPrivileged(PrivilegedAction<T>) line: not available [native method]
SystemProperties.<clinit>() line: 64
LauncherImpl.startToolkit() line: 668
LauncherImpl.launchApplicationWithArgs(String, String, String[]) line: 337
LauncherImpl.launchApplication(String, String, String[]) line: 328
NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]
NativeMethodAccessorImpl.invoke(Object, Object[]) line: not available
DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: not available
Method.invoke(Object, Object...) line: not available
LauncherHelper$FXHelper.main(String...) line: not available
And here is the second:
Thread [JavaFX Application Thread] (Suspended (exception NullPointerException))
PropertyHelper.lambda$getBooleanProperty$514(String) line: 39
7164036.run() line: not available
AccessController.doPrivileged(PrivilegedAction<T>) line: not available [native method]
PropertyHelper.getBooleanProperty(String) line: 37
Parent.<clinit>() line: 87
JavaFXTSample.start(Stage) line: 16
LauncherImpl.lambda$launchApplication1$162(AtomicBoolean, Application) line: 863
2266602.run() line: not available
PlatformImpl.lambda$runAndWait$175(Runnable, CountDownLatch) line: 326
32251660.run() line: not available
PlatformImpl.lambda$null$173(Runnable) line: 295
11305869.run() line: not available
AccessController.doPrivileged(PrivilegedAction<T>, AccessControlContext) line: not available [native method]
PlatformImpl.lambda$runLater$174(Runnable, AccessControlContext) line: 294
30052382.run() line: not available
InvokeLaterDispatcher$Future.run() line: 95
WinApplication._runLoop(Runnable) line: not available [native method]
WinApplication.lambda$null$148(int, Runnable) line: 191
32126786.run() line: not available
Thread.run() line: not available
What's more, if I remove any instance of iAmRoot
and scene
(so start()
just reads primaryStage.show();
), the second error doesn't occur. Why is this happening?
I've been able to find this question before (JavaFX application throws NullPointerException at startup), but noone seems to have resolved it, and it was asked over 2 years ago.
If it helps, I'm running Eclipse 4.5.2 on Windows 7 Professional, and I don't think I'm using FXML at all.
EDIT:
for what it's worth, I can't find the source code for the second error, but I found JavaFX's code for the method which throws the first error (line 81):
58 private static final String versionResourceName =
59 "/com/sun/javafx/runtime/resources/version.properties";
...
78 private static void setVersions() {
79 int size;
80 InputStream is =
81 SystemProperties.class.getResourceAsStream(versionResourceName);
82 try {
83 size = is.available();
84
85 byte[] b = new byte[size];
86 int n = is.read(b);
87 String inStr = new String(b, "utf-8");
88 SystemProperties.setFXProperty("javafx.version",
89 getValue(inStr, "release="));
90
91 SystemProperties.setFXProperty("javafx.runtime.version",
92 getValue(inStr, "full="));
93
94 } catch (Exception ignore) {
95 }
96 }
This question is 1 year old, but i feel like still very relevant. That's why i answer this question (in length).
I'll try to answer this question to the best of my knowledge
JavaFX has some quirky code-lines and the exceptions are cause by those. All can be traced back to some line in JavaFX, which misses a check or uses an unchecked part.
Every JavaFX application I've run throws two NullPointerExceptions. They don't prevent or even affect the execution of the projects, and I can only see them if I run my applications in debug mode.
The first Exception you shown is located at:
SystemProperties.setVersions() line: 81 [local variables unavailable]
You already posted the correlating code. To visualize this, i'll post this again. The Line in Problem is:
InputStream is =
SystemProperties.class.getResourceAsStream(versionResourceName);
try {
size = is.available(); // InputStream "is" = null
...
} catch (Exception ignore) {
}
This is pretty easy explained. The getResourceAsStream
method returns the following (from the JavaDoc):
Returns: A InputStream object or null if no resource with this name is found
This means, that the resource (that you again already posted) "/com/sun/javafx/runtime/resources/version.properties"
is not found.
This however is not handled, but simply ignored. This exception is therefor not printed, but still is thrown. It is catched by the debugger, but that's it. Therefor only identifiable by the debugger.
The why is not really well identifiable. One possibility might be that the JDK does not contain the resource. In my tests of the JDK-10 (which i currently use), the package com.sun.javafx.runtime exists, but the sub-package resources does not. This is not really reproducible, since the com.sun package appears to not be documented. The base api of javafx is documented here, but the com.sun.javafx package is not. You can look at it, if you are using a sophisticated IDE (like IntelliJ for example). My JDK-8 does contains it. I use the Oracle JDK on Ubuntu 18.04.1.
One possibility might be, that the package has been ditched along the way. Maybe someone thought, that referencing the resource through packages is not that great and put it within the resources path, but since the exception is swallowed into nothing, this error has never been detected.
NOTE: This potential fix is NOT tested thoroughly
This issue might be fixed, if you manually introduce the resource. Considering the code you posted (and that can be found within the SystemProperties.setVersions
method), you would have to create a file called "version.properties" within the package com.sun.javafx.runtime.resources. This versions.properties should look like something like this:
release=1
full=1
Those are arbitrary values which you would have to test.
The second NullPointer is rooted within the line PropertyHelper.lambda$getBooleanProperty$514(String) line: 39
. This method looks like this:
static boolean getBooleanProperty(final String propName) {
try {
boolean answer = AccessController.doPrivileged((java.security.PrivilegedAction<Boolean>) () -> {
String propVal = System.getProperty(propName);
return "true".equals(propVal.toLowerCase()); // Line 39
});
return answer;
} catch (Exception any) {
}
return false;
}
This leads to the conclusion, that the propVal
is null, which is backed by the JavaDoc from System.getProperty
Returns: the string value of the system property, or null if there is no property with that key.
This means, the propName
is not found. But propName
is the method argument. So, what is the propName
? This again can be found within the stacktrace. The line:
Parent.() line: 87
defines the property that should be found. It reads the following:
private static final boolean warnOnAutoMove = PropertyHelper.getBooleanProperty("javafx.sg.warn");
So, the method stated before tries to find the SystemProperty "javafx.sg.warn", but does not check whether or not it exists. This again is not handled and therefor only visible within the debugger.
This Exception would not occur if the "toLowerCase" call would be erased.
You can simply fix this exception, by introducing the following code before referencing the Parent class in any way:
System.setProperty("javafx.sg.warn", "true");
It has to be done before any reference, because this attribute is static. So, if this class is referenced in any way in code, it is loaded. One possibility would be, to add a static block to your main class, which contains this code. Another way would be to add the following to the command line:
-Djavafx.sg.warn="true"
This would erase the need to call the code before references. Of course you can exchange true for anything else. But with that, the property exists and the problem line will not throw a NullPointerException.
Stage.show
is executed?This is pretty simple. In JavaFx any element to display is a Node
within the Scene graph. Every Node may have a Parent
, which is a subclass of Node. Nearly all classes extend Parent, so does the StackPane, but not the Stage. By referencing the StackPane, you reference Parent, which triggers the loading of the property. If you do not set a StackPane, you do not reference the Parent class, which means you do not trigger the loading of the property. So no Exception is thrown.
Since the team behind javafx appears to ignore those exception, you can too. I do not say that this is good practice or you should code in this way, but fixing those issues, that do not prevent you from running this application and that do not change the behavior may cost more time than it is worth.
This answer explained the raw "why", but i want to give my two cents to the real issue. Please note that this is just my opinion! If you do think differently, that's totally okay. It is no longer directly necessary to answer the question.
This root of all of this is (in my opinion) the many many code smells within the javafx api. From magic strings within all parts, over downcasting within all ParentHelper.ParentAccessor implementations within the components of JavaFX, passing by many Large-Classes (maybe even god classes) and finally ending in Inappropriate intimacy. The abstraction could have been much better and the size of (for example) the Node class is way to enormous.
With the new release cycle, my hopes are high that they take their time to eliminate at least some of those code smells, but i fear that they just build upon those code smells, which means that at some time, a new ("modern") GUI-API has to be build.
Have a nice day!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With