I tried running the TestAwtPanels app on my 64-bit win7 desktop, and it immediately hit an NPE. Here is the stack trace:
Apr 04, 2014 3:22:15 PM com.jme3.app.Application handleError
SEVERE: Uncaught exception thrown in Thread[LWJGL Renderer Thread,6,main]
java.lang.NullPointerException
at jme3test.awt.TestAwtPanels.simpleInitApp(TestAwtPanels.java:84)
at com.jme3.app.SimpleApplication.initialize(SimpleApplication.java:226)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.initInThread(LwjglAbstractDisplay.java:130)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:207)
at java.lang.Thread.run(Thread.java:744)
It looks to me like there’s a race condition between the Runnable and simpleInitApp().
If i remember correctly I have hit a similar problem, caused by different working Os logic, apparently some do block till creation nativly others not.
My solution was to block till ready,as else the canvas might be invalid/not existent
[java]
ConfigFrame.app = new CompileApplication();
ConfigFrame.app.setShowSettings(false);
ConfigFrame.app.start(JmeContext.Type.Canvas);
while (!ConfigFrame.app.started) { //set to true in the end of simple init
try {
Thread.sleep(100);
} catch (final InterruptedException e) {
e.printStackTrace();
}
}
this.jcan = (JmeCanvasContext) ConfigFrame.app.getContext();
Or if you use CountDownLatch you could reduce it to maybe fewer lines of code. This is essentially reimplementing most of countdown latch by hand and is a good example of a bad example, in my opinion… along the lines of trying to encourage people to use the proper threading primitives instead of rolling their own with synchronized. This is the opposite.
…though unfortunately you will still have to catch InterruptedException (stupid checked exceptions :)).
This:
final private static Object panelsAreReady = new Object();
Becomes:
final private static CountDownLatch panelsAreReady = new CountDownLatch(1);
…but it’s instantly clearer what is going on without reading everywhere.
Generally, I’d throw a RuntimeException in the InterruptedException block. It’s the only appropriate response… which is kind of why InterruptedException being a checked exception is a little silly but that’s been decided a long time ago.
throw new RuntimeException(“Interrupted waiting for panels”, e);
Aha! TestChooser invokes TestAwtPanels.start() instead of TestAwtPanels.main(), so among other things the Runnable never gets created. I’m not sure why TestChooser was written that way, but in this instance it looks like a poor choice.
If I force the chooser to invoke TestAwtPanels.main(), the test seems to work.