JDK-8174154 : NPE in JFXPanel$HostContainer#setEmbeddedStage
  • Type: Bug
  • Component: javafx
  • Sub-Component: swing
  • Affected Version: 8u60,9
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic
  • CPU: x86_64
  • Submitted: 2017-02-03
  • Updated: 2020-01-31
  • Resolved: 2017-02-14
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 8 JDK 9
8u152Fixed 9Fixed
Related Reports
Relates :  
Description
FULL PRODUCT VERSION :
ava version "1.8.0_112"
Java(TM) SE Runtime Environment (build 1.8.0_112-b15)
Java HotSpot(TM) 64-Bit Server VM (build 25.112-b15, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
4.4.0-21-generic #37-Ubuntu SMP Mon Apr 18 18:33:37 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux

EXTRA RELEVANT SYSTEM CONFIGURATION :
Dell Latitude E7440

A DESCRIPTION OF THE PROBLEM :
In my company we are embedding JavaFX controls into an already existing Swing application using a JFXPanel.

For a weird reason and without being able to provide you any particular test-case nor code snippet, I noticed that very often a NPE was thrown in the traces:

E!com.*********.util.log.uncaught ERROR [2017-02-01 21:20:06,897] [AWT-EventQueue-1] [] {}
M!Uncaught exception: thread=AWT-EventQueue-1
java.lang.NullPointerException
at javafx.embed.swing.JFXPanel$HostContainer.lambda$setEmbeddedStage$52(JFXPanel.java:864)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:756)
at java.awt.EventQueue.access$500(EventQueue.java:97)
at java.awt.EventQueue$3.run(EventQueue.java:709)
at java.awt.EventQueue$3.run(EventQueue.java:703)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:80)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:90)
at java.awt.EventQueue$4.run(EventQueue.java:731)
at java.awt.EventQueue$4.run(EventQueue.java:729)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:80)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:728)
at com.*********.util.operation.SessionEventQueue.dispatchEvent(AWTEvent)(SessionEventQueue.java:80)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)

While investigating the JDK code throwing this exception, I noticed that there was a nulllity check on stagePeer variable performed before enqueuing an action using it through a lambda in the AWT Event Queue.

In some situations, stagePeer variable seems to be resetted to null in the meantime, which throws the exception below.

Here's my suggested patch to fix that: shouldn't the nullity check also be present within the lambda to ensure stagePeer variable won't be nullified in between?

There has already been a similar fix for JFXPanel$HostContainer#setEmbeddedScene method fixed in Java8u60 as described here: https://bugs.openjdk.java.net/browse/JDK-8097368

So far, I haven't seen any consequences of this exception in the UI itself but I guess NPEs are never desired.

If this seems to be a valid use-case, could you try to fix it somehow?

Thanks in advance.

Regards

Fourfour


STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Embedding JavaFX controls within a Swing application using a JFXPanel.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
No NPE in the traces.
ACTUAL -
NPE thrown.

ERROR MESSAGES/STACK TRACES THAT OCCUR :
E!com.*********.util.log.uncaught ERROR [2017-02-01 21:20:06,897] [AWT-EventQueue-1] [] {}
M!Uncaught exception: thread=AWT-EventQueue-1
java.lang.NullPointerException
at javafx.embed.swing.JFXPanel$HostContainer.lambda$setEmbeddedStage$52(JFXPanel.java:864)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:756)
at java.awt.EventQueue.access$500(EventQueue.java:97)
at java.awt.EventQueue$3.run(EventQueue.java:709)
at java.awt.EventQueue$3.run(EventQueue.java:703)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:80)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:90)
at java.awt.EventQueue$4.run(EventQueue.java:731)
at java.awt.EventQueue$4.run(EventQueue.java:729)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:80)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:728)
at com.*********.util.operation.SessionEventQueue.dispatchEvent(AWTEvent)(SessionEventQueue.java:80)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)

REPRODUCIBILITY :
This bug can be reproduced often.


Comments
+1 Approved to push to FX 8u-dev for 8u152
15-06-2017

The backport: http://cr.openjdk.java.net/~ssadetsky/8174154/webrev.8backport/
15-06-2017

We should consider a backport to 8u since this is a regression introduced in an 8 update release.
14-02-2017

Changeset: 60f663a27bae Author: ssadetsky Date: 2017-02-14 08:25 -0800 URL: http://hg.openjdk.java.net/openjfx/9-dev/rt/rev/60f663a27bae 8174154: NPE in JFXPanel$HostContainer#setEmbeddedStage Reviewed-by: kcr, azvegint
14-02-2017

2/13/2017: Reviewed and ready to push
13-02-2017

Looks fine.
11-02-2017

Looks good. I verified that the unit test fails without the fix and passes with the fix. +1
10-02-2017

http://cr.openjdk.java.net/~ssadetsky/8174154/webrev.00/
10-02-2017

A closer look at the code suggests that this bug was introduced in 8u60 by the fix for JDK-8097368, since prior to that fix the call in question was run on the thread that called setEmbeddedStage so stagePeer could not have been null.
08-02-2017

Yes, this is a somewhat similar case to JDK-8097368. The stagePeer is known to be non-null at the time the lambda is sent to the EDT to call setFocused: invokeOnClientEDT(() -> { if (JFXPanel.this.isFocusOwner()) { stagePeer.setFocused(true, AbstractEvents.FOCUSEVENT_ACTIVATED); } }); However there is nothing preventing the stagePeer from being subsequently set to null on the JavaFX application thread after the lambda is sent to the EDT but before it is executed. A null check seems in order here. On a related note, the stagePeer (and probably scenePeer) field should be declared volatile since it is accessed from both the EDT and FX threads.
08-02-2017