Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spontaneous NullPointerExceptions when firing Events

I'm currently making a JavaFX Level Editor in combination with the LWJGL library in order to implement OpenGL capabilities, and thus, using multi-threading.

My problem however, is that sometimes when I fire JavaFX events (when I press a button / key etc.) I get this spontaneous java.lang.NullPointerException. I can't seem to figure out the pattern of when exactly the error occurs, and for some strange reason the stacktrace won't provide me with where the exception occurred. All I know is that it occurs when I in some way interact with the JavaFX Application Thread.

When it does occur however, it does not only print it to the console once and then crash. What happens is that the application continuously prints out the the error message over and over again until I force-close the application. It seems like I can no longer fire some specific events when the error has occurred.

This is the spontaneous repeated error message that I get:

Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
at javafx.scene.Scene$ScenePulseListener.synchronizeSceneNodes(Unknown Source)
at javafx.scene.Scene$ScenePulseListener.pulse(Unknown Source)
at com.sun.javafx.tk.Toolkit.lambda$runPulse$30(Unknown Source)
at com.sun.javafx.tk.Toolkit$$Lambda$153/452428720.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.Toolkit.runPulse(Unknown Source)
at com.sun.javafx.tk.Toolkit.firePulse(Unknown Source)
at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(Unknown Source)
at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(Unknown Source)
at com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$400(Unknown Source)
at com.sun.javafx.tk.quantum.QuantumToolkit$$Lambda$42/424424770.run(Unknown Source)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(Unknown Source)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$145(Unknown Source)
at com.sun.glass.ui.win.WinApplication$$Lambda$38/12064136.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)

I guess that it has something to do with "synchronizing nodes". Since I'm working with multithreading in order to run a render-loop with OpenGL this might have something to do with the case. I am also using Lambda Expression from Java8, and apparently as it says in the error log it has something to do with them too.

I am not expecting someone to give me an exact answer to what my problem is, and what I've done wrong, since I do not provide any code (because my project is too big and I do not know where the Exception occurs). However, I have a few generic questions:

  1. What does this error log mean?

  2. What might cause this?

  3. Why does it not provide me with any information of where the Exception occurred?

I managed to get the line numbers from the stacktrace by switching JRE in Eclipse from the JRE installation to the jar provided by the JDK. This allowed me to get line numbers from the compiled APIs, such at JavaFX itself.

This is the new error log:

Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
at javafx.scene.Scene$ScenePulseListener.synchronizeSceneNodes(Scene.java:2289)
at javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2419)
at com.sun.javafx.tk.Toolkit.lambda$runPulse$30(Toolkit.java:314)
at com.sun.javafx.tk.Toolkit$$Lambda$153/478814140.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.Toolkit.runPulse(Toolkit.java:313)
at com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:340)
at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:525)
at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:505)
at com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$400(QuantumToolkit.java:334)
at com.sun.javafx.tk.quantum.QuantumToolkit$$Lambda$42/1940618951.run(Unknown Source)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$145(WinApplication.java:101)
at com.sun.glass.ui.win.WinApplication$$Lambda$38/640174177.run(Unknown Source)
at java.lang.Thread.run(Thread.java:745)

My error lies within the JavaFX classes and probably somewhere within my lambda expression, since the only place where it still says (Unknown Source) is where it also says "lambda". Maybe the stacktrace can't show line numbers in lambdas?

Anyway, this is the line of code that returns a NullPointerException:

if (node.getScene() == Scene.this)

This is within the JavaFX Scene class

like image 742
SporreKing Avatar asked Apr 05 '15 13:04

SporreKing


2 Answers

Not an answer, only suggestion from troubleshooting a very similar problem - a Swing one.

To avoid any guessing, we should look at the source code - resolve the "unknown source" part. The stacktrace you provided is lacking line numbers. This is because, the standard JRE is compiled without any debug information. Once, I believe at Sun times, one could download a separate distribution aimed at developers with all debugging symbols in place. That allowed, besides having the exact line numbers, also to set up breakpoints inside the JDK's code.

We could start investigating issues right from there.

If there is no JRE with debug symbols, You can always try compiling your own! I've once successfully compiled the "src.zip" file, which accompanied the JDK distribution. It wasn't self contained though! There were several parts missing, some Linux specific classes etc. The javac from JDK itself had problems with the file - it ran out of memory all the time. Fortunately, the Eclipse's javac compiler can deal with big codebase and partially compile classes.

Then, I ran my program with the resulting jar (the src.zip compiled with debug symbols) at the bootstrap classpath. Normally, you aren't allowed to modify anything inside "java." and "sun." packages. With bootstrap classpath, you can.

Now, back to Your certain problem: both JavaFX and OpenGL solve multithreading issues, by so called "thread confinement". That means, that everything is forcefully single-threaded. Probably, Your issues arises from the fact, that both javaFx and OpenGL has their separate threads! I'm betting, you did some interaction outside of the JavaFX's EDT. But, it's only a far fetched hypothesis. Try getting the source lines, we could go on from there.

At the time I needed the debug info, I was following the answer from here: debug jdk source can't watch variable what it is

But, all the work might not be needed! I just learned, You could attach the source files itself to the boot classpath, as specified here: https://stackoverflow.com/a/10498425


Update,

So, it seems the "node" reference is null (I doubt that "this" is null). Next step would identifying the null node and find the exact time where it was added. I'd probably put some breakpoints (or printout statements) at all sensible "addNode" invocations - from your program.

From the source code (I quickly skimmed through http://grepcode.com/file/repo1.maven.org/maven2/net.java.openjfx.backport/openjfx-78-backport/1.8.0-ea-b96.1/javafx/scene/Scene.java#2263 ) it seems, the "null" reference comes from the "dirtyNodes" array".

My best bet normally would be, that you're indirectly calling invoking the addToDirtyNodes ( http://grepcode.com/file/repo1.maven.org/maven2/net.java.openjfx.backport/openjfx-78-backport/1.8.0-ea-b96.1/javafx/scene/Scene.java#503 ) from outside the proper Thread. To my surprise, there is a first line which checks if it's called from the proper one:

Toolkit.getToolkit().checkFxUserThread();

Do You happen to see the line "Not on FX application thread; currentThread = " in your program's output?

Let's just hope, it's not a bug in JavaFX itself.

like image 130
Rekin Avatar answered Oct 13 '22 01:10

Rekin


Don't modify your GUI on a non-GUI thread.

As I don't see your code I'm not sure where exactly you do it, but I had the same issue and it turns out I had passed a GUI object to a class of mine that ran a method on a non-GUI thread that was updating a GUI object. So don't do that.

like image 45
Simon Forsberg Avatar answered Oct 13 '22 00:10

Simon Forsberg