Null pointer in JTree rendering

This bug has been annoying me for a while, and I can’t seem to track down a good way to fix it. Many of my commands in my editor require the scene graph view (a JTree of all the nodes) to be rebuilt as nodes are added, deleted, moved etc. For the time being I typically do a brute force update when major changes are performed since its much easier (and I havn’t run into any problems yet).

However what this ends up doing is that I’m totally rebuilding the tree nodes (only the root node is persistant) and frequently Swing is trying to paint the JTree at the same time, so hits a null pointer (stack below). Now the line actually points to:


      component = currentCellRenderer.getTreeCellRendererComponent
                    (tree, path.getLastPathComponent(),
                   tree.isRowSelected(row), isExpanded, isLeaf, row,
                   (leadIndex == row));

which is unfortunatly rather vauge as it could be multiple objects here that are the cause. Trying to grab it in the debugger is tricky since it only gets caught in a finally block, and manually stepping though means that the exception doesn’t happen because it disrupts the timing and redraw events. /me needs a multi monitor setup to get around this…

The only thing i can think of doing is a setVisible(false) on the tree before the tree update happens, yet this doesn’t seem to fix anything. Anyone any suggestions on how to fix this?

java.lang.NullPointerException
      at javax.swing.plaf.basic.BasicTreeUI.paintRow(BasicTreeUI.java:1375)
      at javax.swing.plaf.basic.BasicTreeUI.paint(BasicTreeUI.java:1171)
      at javax.swing.plaf.ComponentUI.update(ComponentUI.java:142)
      at javax.swing.JComponent.paintComponent(JComponent.java:537)
      at javax.swing.JComponent.paint(JComponent.java:804)
      at javax.swing.JComponent.paintChildren(JComponent.java:643)
      at javax.swing.JComponent.paintWithOffscreenBuffer(JComponent.java:4742)
      at javax.swing.JComponent.paintDoubleBuffered(JComponent.java:4688)
      at javax.swing.JComponent._paintImmediately(JComponent.java:4632)
      at javax.swing.JComponent.paintImmediately(JComponent.java:4464)
      at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:404)
      at javax.swing.SystemEventQueueUtilities$ComponentWorkRequest.run(SystemEventQueueUtilities.java:117)
      at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:178)
      at java.awt.EventQueue.dispatchEvent(EventQueue.java:443)
      at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:190)
      at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:144)
      at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138)

You could copy your existing model, make your modifications and then reset the model of the tree. That’d prevent it being in mid-redraw I think, since I guess the setting of the model would be sort of atomic. It’d be crappy for memory I spose.

Kev

Number one suggestion: never use JTree. And if you ever meet the person responsible for it’s design, kick them. Hard. After 5 years, I still can’t work out why JTree is so incompatible with the rest of Swing - JTable Jlist etc share API design, and frequently classes. JTree is not only incompatible in design terms, but uses really stupid objects like TreePath (insane: should have been an interface at the very least) and Tree( ?Model? )Event. It doesn’t help that the **** never documented the class….

Now for practical suggestions :wink:

Create your own state machine, and force it upon Swing. This has always served me well for overcoming bugs / design-mistakes in Swing since it first came out - the default state-management is appalling, and there is virtually no protection against trivial StackOverflows etc (although later Swing components actually protect against this by throwing appropriate Exceptions).

With JTree (and often with JTable) I usually have a set of flags, e.g.

boolean hasFinishedInitialisingData, isRepainting, isRebuilding;

…dependent on how complex your underlying data is. The first one is not normally necessary with JTree IIRC, but is often necessary/extremely useful with other swing components. Another handy one is a guard on “selecting via JTree” and one on “selecting via a different source” - helps prevent infinite recursion. Every method you possess in JTree that could be invoked at a “dangerous” time, you guard using the booleans. A bit like synchronization on the cheap (nb synchronization would probably be better than booleans. I don’t know if this is a bad habit of mine, e.g. if there was some good reason for me doing it back in 1998…possibly synchronization overhead).

I often get null TreePath objects. Seeing as JTree won’t allow null to be used as your root object (even though this makes perfect sense, EDIT: …but is documented, although I had been lazily reading the wrong docs :)), they aren’t coming from the tree nodes themselves. I can think of at least one way you can get null’s introduced, but handling null TP explicitly is probably the easiest workaround. If the lazy little git at Sun that wrote the class had a sense of decency, such info might be (I don’t know if it’s deliberate or not!) in the API docs (I’m afraid I have nothing but utter contempt for people who write an API for use by millions of people and don’t bother to document it. Sorry if I offend anyone…).

FWIW, AFAICS there are no other candidates for NPE in that line - your JTree is never going to be null, and I doubt you are ever making your cellrenderer null?

Ugh, I feel like I’ve just written the biggest hack ever - I made a new class and subclassed JTree, overriding the troublesome .paint and .getPreferedSize methods. I stuck in a try…catch in each and just delegate to the original methods. If an exception gets caught I just throw it away and scedule another repaint.

Yes its ugly, yes its probably not ‘correct’. But it does work :o

I looked into swapping the model, but didn’t think I liked the duplication method since this happens quite a lot and slowdown would be noticable I think. I had an idea of doing the same thing with the root node - build the tree and only at the very end switch the root. However I remember having great problems with switching the root before and don’t feel like trying to get it to work again.

blahblahblahh: Good to know its not just me that finds JTree totally alien when compared to the rest of Swing, out of all the components its the one thats given me the worst problems. The idea of using some state variables sounds promising, I assume to track the isPainting state you’d override the paint methods and set the flag during the method? (This was what I was doing before I stumbled across my ugly hack). How would I then wait for rendering to finish before tinkering with the tree? Sitting in a loop .yeild’ing doesnt sound like too much of a good idea…

Yeah. Exactly :).The beauty of OOP.

Back in the “old days” (ahem) before BufferStrategy etc you often had to do this anyway, just to make rendering work. E.g. Microsoft’s JVM had unbelievably stupid repaint() logic, and you had to “re-interpret” a large percentage of repaints - e.g. if someone scrolled the page the applet was in, MSIE would issue a repaint for every few pixels of movement, even if NOTHING in the applet had been uncovered :(.

(This was what I was doing before I stumbled across my ugly hack). How would I then wait for rendering to finish before tinkering with the tree? Sitting in a loop .yeild’ing doesnt sound like too much of a good idea…
[/quote]
I normally find that rendering is faster than my updates - Swing is pretty nippy (nb: if this is not hte case for you, you may need to investigate the current clip-bounds checking - and specifically whether you are are painting outside of it. I can’t remember if JTree is intelligent enough to do this itself).

So, for repaint(), I just disallow any repaint requests if I’m still in state “rebuilding tree”. If it’s painting when I want to rebuild, I usually rebuild anyway, like you, with all exceptions caught and ignored :slight_smile: - but disallowing repaint requests reduces the number of times that happens quite a lot.

More intelligently, you can:

  • set a flag, and wait for the repaint to complete (flag prevents it from repainting again afterwards)
  • or set a flag that tells your TreeModel to block on any method call, until rebuilding is complete (this traps the Swing repaint thread, so it’s very naughty, but I’ve seen it done quite often ;))
  • or use synchronization, and use wait()/notify() to automatically pause until the rendering is complete. I’d recommend this :slight_smile:

PS: I take it you’re already extending JTree anyway, so overriding a few JTree methods isn’t going to uglify your class structure?

I’ll be looking into it in detail later today, but I thought I’d just see if anyone has ideas for tracing stack overflow errors…

I looked into this thread because 30 minutes earlier my JTree had started stackoverflowing at bizarre occasions. AFAIAA, there is no way of tracking a stack overflow if it occurs in Swing (since you can’t set the default error handler, and with an overflow it’s probably run out of memory anyway? But I know nothing about any clever stuff the JVM does specifically against this problem…?)

I don’t suppose you have any ideas? Symptoms:

  • the overflows are non-fatal, and do not impact the application performance in any way (!).
  • the application (it’s a simple server-mgmt tool that I haven’t modified for over a year, and just started adding some new features too) only consists of menus, actions, JTables, JTrees, JPanels, JDialogs and JButtons. (plus simple underlying data model)
  • once overflow has occurred, a simple alt-tab to any other app causes two more overflows (!)
  • …and my guess is that’s in the tree’s valueChanged code and/or the TreeModelListener’s treeStructureChanged (I delegate EVERY change in the underlying model to that method - I just cannot be bothered to faff about with stupid TreePath objects etc). I could be abusing either of them unintentionally right now :).

What about having your own renderer for the nodes and disable the painting in the renderer while you are re-creating the tree ?

[quote]What about having your own renderer for the nodes and disable the painting in the renderer while you are re-creating the tree ?
[/quote]
If I understand OT’s problems correctly, they are coming from the repaint process - nothing to do with the components themselves used to paint individual cells.

JTree traverses the tree via the TreeModel you provide, and my understanding is that OT is in the middle of major changes to his model when JTree starts a traverse. So the renderers are irrelevant - the model will still be queried when in an inconsistent state.

It would be nice if you could just set a public “isInconsistent” method on the model, and JTree would go “oh, in that case I’d better not try accessing it”. The suggestions outlined above are essentially adding this behaviour- preventing JTree from traversing the model whilst the model is in a state of flux.

On a side note, you can often write apps that seem to work, but are broken. You can make it work perfectly AS LONG AS the user doesn’t obscure/unobscure the window whilst you are altering the tree (because you prevent repaints being caused by your updates whilst you’re updating the tree). If you write your own selection handler you can disable all selecting events too - which will prevent JTree (and other listeners) from responding to every change you make to the model by attempting to repaint. However, Swing still has no good system of batched updates (this is the single biggest design flaw in Swing, IME - it causes nearly all the hard-to-fix problems in user code, because most of the rest of swing is designed using listeners, which DO NOT WORK in any environment where every change is instantly propagated to all listeners; you need some form of buffering.).

If you can bring yourself to talk to the treemodel listeners the way you should :), then you can indicate to them the subtrees of the tree that have changed, and how. But because this is a completely different system to that used elsewhere in Swing, I find the additional maintenance cost normally means it’s not worth it - every time someone has to edit that code, they have to remind themself of all the JTree-specific method-names, API design etc.

On the whole, Swing (and AWT) are a great big mess for:

  • repaint management
  • updates to models in the M/V/C arch
  • consistent API principles across different classes even in the same package!

Although it is (very gradually) getting better. Every now and then a few things appear or get deprecated to make it a little less stupid (e.g. IMHO Graphics2D and J2D is absolutely fantastic API design by comparison…pity about the performance, but the API design will last forever, whereas performance can be transparently improved from release to release). But what is needed really is a major rewrite of the API…there is no fundamental reason why Swing is so hard to write and maintain complex apps, other than “it’s really really hard to design a generic GUI-building API from scratch”. In a perfect world (IMHO), Swing would go the way of AWT, and be the “learning experience” for Sun that enabled them to get it right third time lucky :).

P.S. Ever since Action’s and Action/InputMap’s, I’ve never had any problems with any of the form and menu controls - those developers on swing seem to have done really well.

One thing that bugs me about swing is that you are told to do (time consuming) things in worker threads to not block the UI, yet most methods in Swing can only be safely called from the GUI thread.

I understand the reasons to make Swing a single-threaded design. But the problem I have is that 90% of the time that “time consuming task” is something that is working on the data in your “Model”… e.g. building a table, list or tree. I think they should have drawn a line so that methods of the Model could be called from any thread, keep the View and Controller on the Swing thread.

Constant use of InvokeLater or InvokeAndWait can reduce the performance considerably… if you call it once for every item added to a list for instance. So then you have to provide a UI that is much less interactive. E.g. wait for the entire list to be generated before the user sees any part of it, which could mean doubling your memory requirements if you end up having two models in memory at once (before and after). You could also come up with a more complex batched updating of the model data… but that is more of a pain to write.
Perhaps solutions to these problems would make a good JDC TechTip…

I’d also like to see SwingWorker actually added to the JRE… instead of just being something provided as source code in a few examples.

I just saw http://spin.sourceforge.net/ posted on a Java email list.
It looks like it might help.

blahblahblahh,
you are right. The rendering problems occurs probably outside of the renderer. However I do not think that traversing the tree in an instable state should lead to a crash.
After looking at the code involved, it looks more like a test is missing to check if the currentCellRenderer is null in javax.swing.plaf.basic.BasicTreeUI.paintRow (the check is made in other places in the same class).
Maybe it is possible to the synchronize on the getTreeLock() of the tree during model updates to block any painting.

[quote]I’ll be looking into it in detail later today, but I thought I’d just see if anyone has ideas for tracing stack overflow errors…

I looked into this thread because 30 minutes earlier my JTree had started stackoverflowing at bizarre occasions. AFAIAA, there is no way of tracking a stack overflow if it occurs in Swing (since you can’t set the default error handler, and with an overflow it’s probably run out of memory anyway? But I know nothing about any clever stuff the JVM does specifically against this problem…?)
[/quote]
FYI, my stack overflow’s were caused by some cunning modification of the ActionMap/EventMap for Jtree that I’d been doing to turn “delete” into a valid shortcut key (I couldn’t find a way to get Swing to accept single-key presses as valid shortcuts for Action’s).

At app-startup, I grabbed the ActionMap (which is a tree structure), gone to the root, and then put it inside a one-level tree that handed the new keypresses I wanted. This works perfectly, since unhandled keypresses are delegated up the tree; however, it did result in this unpredictable but quite frequent stack overflow, so I was probably doing something wrong :(.