9

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 }
Lord Farquaad
  • 712
  • 1
  • 12
  • 33
  • It's back now. But it's still posted as images, which are really hard to read... "Thread[Main](Suspended...)" is weird. Are you running this in debug mode? – James_D Jun 21 '17 at 19:28
  • I reformatted it as code, and I am running it in debug. These errors don't get handled at all, and they don't affect the code, so the only way to even see them is to run in debug mode. – Lord Farquaad Jun 21 '17 at 19:32
  • 1
    So if you run it normally, they don't appear in the console? – James_D Jun 21 '17 at 19:33
  • They do not. Unless it's in debug mode it's like the errors never take place. I guess for all I know, they're only happening in debug mode, but I don't think that's the case. Wrapping the call to `launch()` in a `try-catch` doesn't affect anything either. – Lord Farquaad Jun 21 '17 at 19:35
  • Possibly loosely related: https://stackoverflow.com/questions/43928556/why-explicitly-throw-a-nullpointerexception-rather-than-letting-it-happen-natura – EJoshuaS - Stand with Ukraine Jun 23 '17 at 21:22
  • 2
    How much code smell can someone put into a single method? 1) assuming `InputStream.available()` to be the total file size, 2) ignoring the return value of `read(…)`, 3) not closing the `InputStream`, 4) catching and ignoring all exceptions. Discussing 5), the unnecessary broad scope of the variables would be pointless considering all these other smells… – Holger Jun 26 '17 at 07:46
  • Considering the place where the NPE was thrown `PropertyHelper.lambda$getBooleanProperty$514(String)` I think it's very possible than conversion from property value to boolean can't handle null/mepty values, but only true or false. But that's only a total guess, just find the property using debug, put it at a true of false value, and see if it happens with the same property. – Walfrat Jun 26 '17 at 14:40
  • Possible duplicate of [What is a NullPointerException, and how do I fix it?](https://stackoverflow.com/questions/218384/what-is-a-nullpointerexception-and-how-do-i-fix-it) – ManoDestra Jun 29 '17 at 13:24
  • You can use a [try-with-resources](https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html) block around your InputStream BTW. – ManoDestra Jun 29 '17 at 13:26
  • @ManoDestra That code isn't mine, it's JavaFX's. I just hunted down the source code and found the first method that was throwing the error so people wouldn't need to take a stab in the dark as to what was happening. This also isn't even almost a duplicate of the one you've flagged; I'm not asking what a NullPointerException is, I'm asking why the JavaFX code is throwing two of them in every application without affecting execution. – Lord Farquaad Jun 29 '17 at 15:21
  • Simple. Because you have a NullPointerException and using the other link will assist you in hunting it down. – ManoDestra Jun 29 '17 at 16:00
  • Then raise an issue with the external library's vendor. If it doesn't manifest itself in your code, then there's nothing to worry about here. If it DOES manifest itself in your code, then it would be useful to see the line that causes the exception to be thrown in YOUR code. The example you've provided runs fine without exception for me. If it raises no exception in your code and lets it roll on regardless, then I would recommend contact Oracle regarding this. They'll want to know about this potential bug. – ManoDestra Jun 29 '17 at 16:22
  • And what's the Java version used? – friednail Jul 03 '17 at 10:59
  • Well, probably it's environment configuration issue. I'm using Intellij IDEA 16.2, and tried both: jdk 1.7_u80 and 1.8_u102 for the project. Application starts without any problems. – friednail Jul 03 '17 at 11:06

1 Answers1

11

Disclaimer

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

TL;DR

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.

First NullPointerException

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.

Fixing this issue

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.

Second NullPointerException

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.

Fixing this Exception

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.

Why is the second Exception not thrown if only 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.

Should you fix the Exceptions?

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.

Further thoughts

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.

Finally

Have a nice day!

Thorben Kuck
  • 1,092
  • 12
  • 25