5

I'm experimenting with JavaFX labels and Groups with moving them over the screen by mouse dragging. New nodes are added to the animation group from some Threads. However, sometimes I see the following exception out of the sudden - I assume, when some nodes are overlapping. But I don't know what the problem is... because my code is not involved. Does anybody know this exception and root cause (using JDK 1.8.0.-112)? Thanks

'JavaFX Application Thread' lambda$main$68 - Thread[JavaFX Application Thread,5,main] threw an uncaught exception: java.lang.ArrayIndexOutOfBoundsException: -1
    at java.util.ArrayList.elementData(ArrayList.java:418) ~[?:1.8.0_112]
    at java.util.ArrayList.get(ArrayList.java:431) ~[?:1.8.0_112]
    at com.sun.javafx.collections.ObservableListWrapper.get(ObservableListWrapper.java:89) ~[jfxrt.jar:?]
    at com.sun.javafx.collections.VetoableListDecorator.get(VetoableListDecorator.java:306) ~[jfxrt.jar:?]
    at javafx.scene.Parent.updateCachedBounds(Parent.java:1591) ~[jfxrt.jar:?]
    at javafx.scene.Parent.recomputeBounds(Parent.java:1535) ~[jfxrt.jar:?]
    at javafx.scene.Parent.impl_computeGeomBounds(Parent.java:1388) ~[jfxrt.jar:?]
    at javafx.scene.layout.Region.impl_computeGeomBounds(Region.java:3078) ~[jfxrt.jar:?]
    at javafx.scene.Node.updateGeomBounds(Node.java:3579) ~[jfxrt.jar:?]
    at javafx.scene.Node.getGeomBounds(Node.java:3532) ~[jfxrt.jar:?]
    at javafx.scene.Node.getLocalBounds(Node.java:3480) ~[jfxrt.jar:?]
    at javafx.scene.Node.updateTxBounds(Node.java:3643) ~[jfxrt.jar:?]
    at javafx.scene.Node.getTransformedBounds(Node.java:3426) ~[jfxrt.jar:?]
    at javafx.scene.Parent.getChildTransformedBounds(Parent.java:1732) ~[jfxrt.jar:?]
    at javafx.scene.Parent.updateCachedBounds(Parent.java:1596) ~[jfxrt.jar:?]
    at javafx.scene.Parent.recomputeBounds(Parent.java:1535) ~[jfxrt.jar:?]
    at javafx.scene.Parent.impl_computeGeomBounds(Parent.java:1388) ~[jfxrt.jar:?]
    at javafx.scene.Node.updateGeomBounds(Node.java:3579) ~[jfxrt.jar:?]
    at javafx.scene.Node.getGeomBounds(Node.java:3532) ~[jfxrt.jar:?]
    at javafx.scene.Node.getLocalBounds(Node.java:3480) ~[jfxrt.jar:?]
    at javafx.scene.Node.impl_intersectsBounds(Node.java:5015) ~[jfxrt.jar:?]
    at javafx.scene.Parent.impl_pickNodeLocal(Parent.java:705) ~[jfxrt.jar:?]
    at javafx.scene.Node.impl_pickNode(Node.java:4914) ~[jfxrt.jar:?]
    at javafx.scene.Scene$MouseHandler.pickNode(Scene.java:3899) ~[jfxrt.jar:?]
    at javafx.scene.Scene$MouseHandler.access$1600(Scene.java:3485) ~[jfxrt.jar:?]
    at javafx.scene.Scene.pick(Scene.java:1942) ~[jfxrt.jar:?]
    at javafx.scene.Scene.access$6700(Scene.java:159) ~[jfxrt.jar:?]
    at javafx.scene.Scene$MouseHandler.process(Scene.java:3799) ~[jfxrt.jar:?]
    at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3485) ~[jfxrt.jar:?]
    at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762) ~[jfxrt.jar:?]
    at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2494) ~[jfxrt.jar:?]
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:381) ~[jfxrt.jar:?]
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:295) ~[jfxrt.jar:?]
    at java.security.AccessController.doPrivileged(Native Method) ~[?:1.8.0_112]
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$354(GlassViewEventHandler.java:417) ~[jfxrt.jar:?]
    at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389) ~[jfxrt.jar:?]
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:416) ~[jfxrt.jar:?]
    at com.sun.glass.ui.View.handleMouseEvent(View.java:555) ~[jfxrt.jar:?]
    at com.sun.glass.ui.View.notifyMouse(View.java:937) ~[jfxrt.jar:?]
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method) ~[jfxrt.jar:?]
    at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191) ~[jfxrt.jar:?]
    at java.lang.Thread.run(Thread.java:745) [?:1.8.0_112]

I assume, it has something to do with the Label (=BorderPane) adding method. I introduced it to shorten the Java FX Application thread processing time. Is there a problem with that?

private Queue<BacklogGroupAction> todoList = new ConcurrentLinkedQueue<>();

class BacklogGroupAction {
    boolean add;
    boolean visibleState;
    BorderPane dv;

    public BacklogGroupAction(boolean add, boolean visibleState, BorderPane dv) {
        this.add = add;
        this.visibleState = visibleState;
        this.dv = dv;
    }

}

private synchronized void processBacklogGroupList() {
    if (Platform.isFxApplicationThread()) {
        while (!todoList.isEmpty()) {
            BacklogGroupAction p = todoList.poll();
            if (p.add) {
                p.dv.setVisible(p.visibleState);
                backlogGroup.getChildren()
                .add(p.dv);
            } else
                backlogGroup.getChildren()
                .remove(p.dv);
        }
        backlogGroup.applyCss();
        backlogGroup.layout();
    } else
        logger.error("This is not FX Application Thread");
}
Defarine
  • 293
  • 5
  • 13
  • because my code is not involved means can you post code of the same , without code getting involved null pointer wont be thrown – Rahul Singh Jun 27 '17 at 09:55
  • This usually happens when trying to change an `ObservableList` bound to a node from a thread other than the JavaFX UI thread, or else when manipulating the list during a change. In both cases usually wrapping the offending call in a `Platform.runLater` solves the problem. See e.g. [this related question](https://stackoverflow.com/questions/27769583/calling-clear-on-observablelist-causes-indexoutofboundsexception). – Itai Jun 27 '17 at 10:03
  • @RahulSingh: yes, of course, my code causes the problem for sure ;) However, it is not involved in the exception – Defarine Jun 27 '17 at 11:30
  • 1
    In what circumstances does the method `processBacklogGroupList` get called? Is it possible it is being called while the changes are taking place? – Itai Jun 27 '17 at 13:33
  • ArrayList is not thread safe – LazerBanana Jun 27 '17 at 13:48
  • Why are you generating doing layout on `backlogGroup`? If you modify the child list, this should be triggered automatically; the screen is not updated any faster by doing it manually. If you do not modify the child list, it should be unnecessary to do the layout... Also `processBacklogGroupList` seems to be the only part of the code synchronizing on the containing object. Why do this, if you only allow to call this method from a dedicated thread??? – fabian Jun 27 '17 at 15:10
  • Hi - the applyCss and layout is needed to update bounds even on invisible objects. If you need to determine height and width, the layout is needed beforehand - otherwise, width and height may evaluate to 0.0. – Defarine Jul 05 '17 at 10:48
  • @LazerBanana: there is no ArrayList being used – Defarine Jul 05 '17 at 10:53

2 Answers2

2

thanks for all your help. The code above "processBacklogGroupList" is actually correct and works... (so why -1..?)

The problem was in a totally different place, where an animation was defined not running in JFX Application Thread - but exception occured a bit later.

So thanks to @sillyfly for pointing me to the real problem

This usually happens when trying to change an ObservableList bound to a node from a thread other than the JavaFX UI thread, or else when manipulating the list during a change. In both cases usually wrapping the offending call in a Platform.runLater solves the problem. See e.g. this related question. – sillyfly Jun 27 at 10:03"

Defarine
  • 293
  • 5
  • 13
  • see https://bugs.openjdk.java.net/browse/JDK-8163078 It wouldn't be silly if Oracle would add some code to not throw a Nullpointer exception but point out the fact that the code is not on the JFX Thread. – Wolfgang Fahl Aug 14 '17 at 17:14
0

I had got this problem, it was decided by Platform.runLater(() -> {//your code});