DefaultFocusHistory NullPointerException

Hello Beni,

I’m getting the following random error:

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
   at java.util.LinkedList$ListItr.next(LinkedList.java:891)
   at bibliothek.gui.dock.control.focus.DefaultFocusHistory.getHistory(DefaultFocusHistory.java:76)
   at bibliothek.gui.dock.common.DefaultCFocusHistory.getHistory(DefaultCFocusHistory.java:58)
   at bibliothek.gui.dock.common.DefaultCFocusHistory.getFirst(DefaultCFocusHistory.java:70)
   at bibliothek.gui.dock.common.intern.AbstractCDockable.setLocationsAside(AbstractCDockable.java:409)
   at bibliothek.gui.dock.common.intern.AbstractCDockable.setLocationsAsideFocused(AbstractCDockable.java:418)
   at bibliothek.gui.dock.common.CWorkingArea.show(CWorkingArea.java:122)
   at MainTableFrame.createNewDock(MainTableFrame.java:1828)

About once every 20 times I start my program, when it creates the first DefaultMultipleCDockable, I get the above error.

Line # 1828 of MainTableFrame.java is:

cwArea.show(dmcd);

It has never happened when the code opens the 2nd, 3rd, etc. DefaultMultipleCDockable but only on the first DefaultMultipleCDockable.

Note: I’m using the latest release of Docking Frames (Preview 17b).

Regards,
Roger

Hallo Roger,

[quote=RogerL]
Line # 1828 of MainTableFrame.java is: cwArea.show(dmcd);[/quote]
then I suppose, that “cwArea” will be null (that means, it’s not initialized) !!

Kind regards
Klaus

the StackTrace is posted, cwArea is not null, the NPE happens inside an iterator, which seems rare

‘at java.util.LinkedList$ListItr.next(LinkedList.java’ can be searched
->
java - Nullpointer exception in LinkedList while using for-each loop - Stack Overflow

which says what has to be considered anyway:
the List is used by several threads without synchronisation, or the list is modified within iteration (although then the error should happen every time),
something wrong in any case, how is the list used?

synchronisation/ concurrent modification known?

(edit: if the error is inside the framework, then of course it is/ it looks as an error of DockingFrames, yes)

From the symptoms that you described, I have to make a guess:

Do you modify ANY GUI-Component from a thread that is NOT the Event Dispatch Thread?

The StackTrace that you posted happens on the EDT. But when it happens “randomly”, then this almost certainly a race condition.

So do you have other Threads in your program? What are they doing? (You have to make sure that ALL operations that influence the GUI happen on the Event Dispatch Thread)

DockingFrames is not thread-safe, hence an issue with multi-threading would have been my guess too.

Seriously, I’m not a newbie. Ahhhh. Did you even look at the stack trace!

[QUOTE=SlaterB;136767]something wrong in any case, how is the list used?

synchronisation/ concurrent modification known?

(edit: if the error is inside the framework, then of course it is/ it looks as an error of DockingFrames, yes)[/QUOTE]
Yes, it is Docking Frames code - not mine. Beni, have you looked at the Docking Frames code?

In this particular case no. The user has selected File → Open and creating the new dock is one of the last things it does.

It is not randomly within the application but rather the user starts the program, on the first time they do File → Open, once out of every 20 (freshly started program) it has this issue.

The program hasn’t really started yet (user has not selected anything), so no, there are not any other threads running.

Regards,
Roger

*** Edit ***

But at the startup of my program, there are no other threads (of mine) running.

Here is the createNewDock() method code:

private void createNewDock(String title, ImageIcon icon, JComponent jc)
{
   DefaultMultipleCDockable dmcd = new DefaultMultipleCDockable( null );
   dmcd.setTitleText(title);
   dmcd.setCloseable( true );
   dmcd.setExternalizable(false);
   dmcd.setTitleIcon(icon);
   dmcd.setRemoveOnClose(true);

   MyDockableListener mdl = new MyDockableListener(dmcd, jc, countJC++);
   dmcd.addVetoClosingListener(mdl);
   dmcd.addFocusListener(mdl);
   dmcd.addCDockableStateListener(mdl);

   dmcd.add(jc);

   cwArea.show( dmcd );

   if (dmcd != null)
      dmcd.toFront();

   if (jc == null)
      resetCurrentDFInfo();

   setNewState();
}

When the user starts the program, on the first time they do File → Open, once out of every 20 (freshly started program) it has this issue.

Note: „jc“ is never ever null when passed onto createNewDock() but do you see:

   if (jc == null)
      resetCurrentDFInfo();

I had to add this code because sometimes after the „cwArea.show(dmcd)“ call, the Docking Frames code would set it to null. Absolutely, weird thing to do. So, I had to create a method „resetCurrentDFInfo()“ to rebuild the information. Very annoying. Are these 2 problems related, I don’t know.

I guess I could wrap the „cwArea.show(dmcd)“ call in a try/catch and if it throws an exception, then attempt to recreate the dock. That’s like using a hammer when a screwdriver would work!!

Regards,
Roger

[QUOTE=RogerL]Seriously, I’m not a newbie. …

Note: „jc“ is never ever null when passed onto createNewDock() but do you see:

   if (jc == null)
      resetCurrentDFInfo();

I had to add this code because sometimes after the „cwArea.show(dmcd)“ call, the Docking Frames code would set it to null.
[/QUOTE]

When the parameter jc is not null, then it can not be set to null without any explicit assignment. More specifically: The DockingFrames code can not set jc to null.

Consider adding something like

private void createNewDock(String title, ImageIcon icon, JComponent jc)
{
    System.out.println("Calling with "+jc+" on "+Thread.currentThread());
    ...
}

and see whether it prints something unexpected. Namely, whether jc is null occasionally, or whether the calling thread is not the Event Dispatch Thread.

Sorry, I still suspect that there is some non-EDT-thread involved - maybe even just the main thread (!?)

Otherwise, Beni will have to take a closer look at the code, I guess…

One should not use absolute statements. :slight_smile: :slight_smile:

So I updated the code to be:

try
{
   System.out.println("Before calling with "+jc+" on "+Thread.currentThread());
   cwArea.show( dmcd );
   System.out.println("After (1) calling with "+jc+" on "+Thread.currentThread());
}
catch (Exception e)
{
   System.out.println("Exception : cwArea.show : "+e.getLocalizedMessage());
   System.out.println("After (2) calling with "+jc+" on "+Thread.currentThread());
}

And here’s the output and this is WITHOUT the random error:

Before calling with MyJPanel[,0,0,0x0,invalid,layout=java.awt.BorderLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=9,maximumSize=,minimumSize=,preferredSize=] on Thread[AWT-EventQueue-0,6,main]
After (1) calling with null on Thread[AWT-EventQueue-0,6,main]

Notice how after the „cwArea.show(dmcd)“, jc is null. I don’t know what Docking Frames is doing or why it is doing it, but it likes to zap jc to null. And this is all without the random error.

Beni, should the code add the dock listeners after the „cwArea.show(dmcd)“? Right now, it is done before.

Regards,
Roger

[QUOTE=RogerL]One should not use absolute statements. :slight_smile: :slight_smile:

Notice how after the „cwArea.show(dmcd)“, jc is null. I don’t know what Docking Frames is doing or why it is doing it, but it likes to zap jc to null.
[/QUOTE]

This, in all modesty, is plainly not possible…

and because you’re absolutely right with your absolute statement about absolute statements, I’ll add the follwing, to be on the safe side:

… unless you have a compiler that does not follow the Java Language Specification, or a Java Virtual machine that does not follow the Java Virtual Machine Specification.

To avoid further debates about this, I challenge you to implement the magic method in the example below so that it „zaps jc to null“:

import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class OnlyANewbieWouldSeriouslyTryThis
{
    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(
            () -> createAndShowGuiOnEventDispatchThread());
    }

    private static void createAndShowGuiOnEventDispatchThread()
    {
        JComponent jc = new JPanel();
        createNewDock(jc);
    }
    
    private static void createNewDock(JComponent jc)
    {
        boolean nullBefore = (jc == null);
        magic(jc);
        boolean nullAfter = (jc == null);
        if (nullBefore != nullAfter)
        {
            System.out.println("You'll never see this");
        }
    }

    private static void magic(JComponent jc)
    {
        // Try it...
    }
}

Hint: It’s not possible.


But seriously, you seem to have a problem there. The output that you observed can not be explained from the given code. (The only possibility would be that the state of the object that is referred to by jc is changed in a way that causes its toString() method to either return null or "null" - but in both cases, jc itself would NOT be null). So I’m afraid I can’t help you any more - assuming that it is not possible to create a small example where the problem can be reproduced…?!

I haven’t read everything you guys wrote, but I will tomorrow (weekend and today were/are already filled up with things to do).

I can assure you that ‚jc‘ is null (and not „null“) because the resetCurrentDFInfo() method does get called!!!

Even though Beni hasn’t responded yet, I decided to move the MyDockableListener code to after the ‚show()‘ call.

private void createNewDock(String title, ImageIcon icon, JComponent jc)
{
   DefaultMultipleCDockable dmcd = new DefaultMultipleCDockable( null );
   dmcd.setTitleText(title);
   dmcd.setCloseable( true );
   dmcd.setExternalizable(false);
   dmcd.setTitleIcon(icon);
   dmcd.setRemoveOnClose(true);

   dmcd.add(jc);

   cwArea.show( dmcd );

   if (dmcd != null)
      dmcd.toFront();

   if (jc == null)
      resetCurrentDFInfo();

   MyDockableListener mdl = new MyDockableListener(dmcd, jc, countJC++);
   dmcd.addVetoClosingListener(mdl);
   dmcd.addFocusListener(mdl);
   dmcd.addCDockableStateListener(mdl);

   setNewState();
}

‚jc‘ is no longer being zapped to null. I cannot say whether the original error of the random NullPointerException is gone or not because it takes a lot of start → open tries to get it to fail.

Beni, what is the proper coding standard for using a DockableListener? Should it be instantiated before or after the cwArea.show() method call? I have it as an internal class.

class MyDockableListener implements CDockableStateListener, CFocusListener, CVetoClosingListener
{
   private DefaultMultipleCDockable dmcd = null;
   private JComponent               jc = null;
   private int                      index = 0;

   public MyDockableListener(DefaultMultipleCDockable dmcd, JComponent jc, int index)
   {
      super();
      this.dmcd = dmcd;
      this.jc = jc;
      this.index = index;
   }

   public void focusGained(CDockable arg0)
   {
   }

   public void focusLost(CDockable arg0)
   {
   }

   public void closed(CVetoClosingEvent arg0)
   {
   }

   public void closing(CVetoClosingEvent arg0)
   {
   }

   public void visibilityChanged( CDockable dockable )
   {
   }

   public void extendedModeChanged( CDockable dockable, ExtendedMode mode )
   {
   }
}

Personally, I think it should be after because when MyDockableListener is instantiated before the cwArea.show() call, doing the cwArea.show() call will invoke the visibilityChanged() method of MyDockableListener but the code in visibilityChanged() shows that nothing is actually visible.

This is like which came first, the chicken or the egg.

Regards,
Roger

Looking at your first question:

The method “getHistory” only iterates over a list, it does not modify the list in any way, hence it can not be the source of the error. The list however is modified by a “DockableFocusListener” which may remove elements from the list when some Dockable receives the focus. Now I followed the call hierarchy of this listener, and it may be called by any thread.

I suggest you add a DockableFocusListener (like in the example below) that will trigger an alert if it is ever called by something that is not the EDT. If it is triggered, then you have found the issue.


import javax.swing.JFrame;
import javax.swing.SwingUtilities;

import bibliothek.gui.dock.common.CControl;
import bibliothek.gui.dock.common.CWorkingArea;
import bibliothek.gui.dock.event.DockableFocusEvent;
import bibliothek.gui.dock.event.DockableFocusListener;

public class ThreadTest {
	public static void main(String[] args) throws Exception{
		// JFrame frame = new JFrame("bla");
		// frame.setVisible(true);
		CControl control = new CControl(frame);

		// frame.add(control.getContentArea());
		control.getController().addDockableFocusListener(new ErrorListener());

//		CWorkingArea area = control.createWorkingArea("work");
//		area.setVisible(true);
//
//		frame.dispose();
	}

	private static class ErrorListener implements DockableFocusListener {
		@Override
		public void dockableFocused(DockableFocusEvent event) {
			if (!SwingUtilities.isEventDispatchThread()) {
				Thread current = Thread.currentThread();

				System.out.println("we should not be here! Stacktrace is:");

				for (StackTraceElement e : current.getStackTrace()) {
					System.out.println(e);
				}
			}
		}
	}
}

*** Edit ***

Looking at your second question:

You can add the listener whenever you want, the framework will generate and fire the events in any case. Adding or removing a listener does not change the way in which the framework works (I am assuming your listener does not modify the Dockable…).
Personally I would add the listeners before calling “show”, because in my applications calling a method like “show” or “setVisible(true)” is always the very last step. I don’t want to show anything that is not ready to be shown.

I cannot believe that “DockingFrames” itself is setting “jc” to null, because DockingFrames does not know that some field named “jc” exists.
However, DockingFrames could start some process that sets “jc” to null. For example it can call your “MyDockableListener”, which then may modify “jc”. Can you show us the entire class that holds “jc”? Is there any statement that could modify the “jc”-field? If so, ensure that any assignment to “jc” must not be null.

As far as my understanding goes, the NullPointerException in “getHistory” and “jc” being null are two separate issues and not related at all. So let’s make sure they don’t get mixed up.

Currently we only have your description of an error and short code snippets. In order to fully understand what is going on a small application that reproduces the issue(s) would be very helpful. Right now everyone here is just guessing and assuming what the bug could be. Or in other words: you could get a lot more help if you provided more information.

At least in the snippets provided so far, jc is not a field, but a function parameter. That’s why I said that DockingFrames can not set it to null (call by value…)

Uh, you are right Marco. I’m not certain if that is the real code we see here, or if it is a summary.

Ok, I’m back from vacation.

Yes, 2 separate issues.

I had to put back the listeners where I had them before because the order of events got very weird.

Humm, of course DockingFrames knows of jc (JComponent) because it is the component that is displayed in the dock!!!

dmcd.add(jc);
cwArea.show( dmcd );

So, I figured out why jc was being set to null. It was in the visibilityChanged method of MyDockableListener class. I have code to run through the docks to see if the last dock is being closed, hence, the code would disable menu items and buttons and set jc to null because it is the last dock being closed.

I need to better understand the visibilityChanged method of MyDockableListener class. It appears to only be invoked when the dock is either created or destroyed. True? The parameter for visibilityChanged is CDockable. For CDockable, what is the difference between isShowing() and isVisible() methods. They are either both true or both false.

If you are curious about my application, you can read about the beta of it here.

Regards,
Roger

Welcome back. I did read your blog. Nice application you have there. If you don’t mind I would like to put a link to your application on my website? :slight_smile:

visibility vs showing:
The idea behind visible and showing is copied from „java.awt.Component“, which also has an „isVisible“ and an „isShowing“-method.

Visible means, that the Dockable is registered at a CControl and that it has a parent (or, if it is a root, then the result of this method will always be true assuming the item is registered at a CControl). A „visible“ Dockable should be accessible by the user, although the user may need to perform some action first, like clicking on the right tab or un-minimize a Dockable.

Showing on the other hand is a guarantee that the Dockable is visible to the user right now. A „showing“ Dockable is displayed on the a screen, and it is not obscured (e.g. it is not minimized).

Humm, of course DockingFrames knows of jc (JComponent) because it is the component that is displayed in the dock!!!

You are misunderstanding me. Yes, DockingFrames knows about the value of „jc“, it does not know about the field „gc“. Let me explain in an example:

  JComponent jc = ... <something not null>
  method2( jc );

  // jc is not null here
}

public void method2( JComponent jc2 ){
  // we do know what value "jc" of method1 has

  // but we cannot change "jc" because we have no access to "jc".
  jc2 = null;
}```

Please wait until after I release V2 which should be in a week or so. I’ll let you know.

Regards,
Roger

Hello Beni,

Ok the applications have been (finally) officially released. I have 2 applications that use Docking Frames: MQ Visual Edit and MQ Visual Browse.

Note: MQ Visual Browse is the read-only version of MQ Visual Edit. It is for companies that cannot figure out how to do MQ security. :eek:

They are both using Docking Frames Preview 17b. You can use a screenshot of MQ Visual Edit, if you want. Just go to MQ Visual Edit’s overview page and click on Screenshots and use the 1st one labeled ‘3 queues open’.

Regards,
Roger