Nifty Exception Handling

I would like to at least have an option to make nifty print stack traces in case of thrown exception, instead of failing silently. That would make error tracing a lot easier.

1 Like

I have had my problems with figuring out where Nifty took the wrong turn in the past, but eating stack traces wasn’t among them.



Do you have an example where Nifty does that?

Using some snippets from my main menu; rather straight forward:

[xml]

<control name="button" label="Map Editor" id="options" align="center" valign="center"

childLayout="center"

visibleToMouse="true">

<interact onClick="openEditor()"/>

</control>

[/xml]

[java]

public void openEditor() {

// TODO editor

System.out.println("TODO: editor entry point");

throw new NullPointerException();

}

[/java]

Clicking the button leads to a console output of:

[java]TODO: editor entry point

TODO: editor entry point

TODO: editor entry point[/java]



The fun thing is, that works even for Errors, which is really, really bad.



EDIT: I would expect nifty to print stack traces in case of regular exceptions and to rethrow errors.

@toolforger said:
I have had my problems with figuring out where Nifty took the wrong turn in the past, but eating stack traces wasn't among them.

Do you have an example where Nifty does that?


I've had it eat exceptions quite a lot. Mostly if a controller callback from nifty throws an exception nifty either silently eats it or prints a scrambled error message.
1 Like
@toolforger said:
Yes, rethrowing would be the best strategy, possibly after Nifty cleaning up whatever it needs to do after a callback.
Let the caller decide what to do with a problem, anyway.

The problem is, that nifty is the caller and rethrowing will cause the program to terminate. But I would call that reasonable, because exceptions are exceptions and not regular control flow and if an interaction method is unable to catch an exception, the program usually is in an illegal state.


For the moment, it's probably best to let the callback itself wrap everything in a try-catch block, and either print the exceptions or hook them up with whatever exception logging the application has in place.

No its not, because basically one would have to create proxy methods that would do the catching for you and invoke the intended methods. Afaik in Java there is no reasonable way to do this.

Yes, rethrowing would be the best strategy, possibly after Nifty cleaning up whatever it needs to do after a callback.

Let the caller decide what to do with a problem, anyway.



For the moment, it’s probably best to let the callback itself wrap everything in a try-catch block, and either print the exceptions or hook them up with whatever exception logging the application has in place.

Just read through the Bytecode of the invoke method and it looks a lot like they are guarding the whole thing against runtime exceptions and exceptions printing them to the log. But as far as I can tell, it is not displayed, so it might have an unintended low log priority.

But this is kind of wired, because it should not catch Errors, because Errors do not inherit from Exception.

Remember that most nifty callbacks are not coming from your code at any point - it’s coming from JME/Nifty threads. Whether caught or not (the Nifty source is available btw, its open source) the exceptions/errors are going to happen on that thread and never hit your code.

This slows me down whenever I’m working on code called from nifty, the most basic errors become a nightmare to diagnose

Here is a code snippet that recreates a silently swallowed exception

[java]public class Main extends SimpleApplication implements ScreenController {

int someValue=0;

public static void main(String[] args) {
    Main app = new Main();
    app.start();
}

@Override
public void simpleInitApp() {
    Box b = new Box(1, 1, 1);
    Geometry geom = new Geometry("Box", b);

    Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
    mat.setColor("Color", ColorRGBA.Blue);
    geom.setMaterial(mat);

    rootNode.attachChild(geom);
    
    setUpNifty();
}

private void setUpNifty(){
    NiftyJmeDisplay niftyDisplay = new NiftyJmeDisplay(
    assetManager, inputManager, audioRenderer, guiViewPort);
    /** Create a new NiftyGUI object */
    Nifty nifty = niftyDisplay.getNifty();
    /** Read your XML and initialize your custom ScreenController */
    //nifty.fromXml("Interface/screen.xml", "start",new ScreenController[]{new StartScreenController(), new NewGameScreenController(this), new LoadGameScreenController(this)});
    
    nifty.fromXml("Interface/screens.xml", "start");
    
    nifty.gotoScreen("start");
    
    // attach the Nifty display to the gui view port as a processor
    guiViewPort.addProcessor(niftyDisplay);
    
    inputManager.setCursorVisible(true);
    flyCam.setEnabled(false);
}

public void throwAndChange(){
    System.out.println("Throw and change");
    if (1==1){
        throw new RuntimeException("O No!");
    }
    someValue++;
}

public void printValue(){
    System.out.println(someValue);
}

public void bind(Nifty nifty, Screen screen) {}
public void onStartScreen() {}
public void onEndScreen() {}

}[/java]

[java]<?xml version=“1.0” encoding=“UTF-8”?>
<nifty xmlns=“http://nifty-gui.sourceforge.net/nifty-1.3.xsd
xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance
xsi:schemaLocation=“http://nifty-gui.sourceforge.net/nifty-1.3.xsd http://nifty-gui.sourceforge.net/nifty-1.3.xsd”>
<useStyles filename=“nifty-default-styles.xml” />
<useControls filename=“nifty-default-controls.xml” />

&lt;screen id="start" controller="mygame.Main"&gt;
    &lt;layer id="background" backgroundColor="#00000000"&gt;
        &lt;!-- ... --&gt;
    &lt;/layer&gt;
    &lt;layer id="foreground" backgroundColor="#0000" childLayout="vertical"&gt;
        &lt;panel id="panel_top" height="25%" width="75%" align="center" childLayout="center"&gt;  
            &lt;text text="Error swallowing test" font="Interface/Fonts/Default.fnt" width="100%" height="100%" /&gt;
        &lt;/panel&gt;
        &lt;panel id="panel_mid" height="50%" width="75%" align="center" childLayout="vertical"
         backgroundColor="#0f08"&gt; 
            &lt;panel id="panel_throw" height="20%" width="50%" align="center" childLayout="center"&gt;  
                &lt;control name="button" label="Throw Exception" id="NewGame" align="center" valign="center"                    visibleToMouse="true" &gt; 
                    &lt;interact onClick="throwAndChange()"/&gt;
                &lt;/control&gt;

            &lt;/panel&gt;
            &lt;panel id="panel_print" height="20%" width="50%" align="center" childLayout="center"&gt;  
                &lt;control name="button" label="Print value" id="LoadGame" align="center" valign="center"                    visibleToMouse="true" &gt; 
                    &lt;interact onClick="printValue()"/&gt;
                &lt;/control&gt;
            &lt;/panel&gt;
        &lt;/panel&gt;
        &lt;panel id="panel_bottom" height="25%" width="75%" align="center" childLayout="horizontal"
         backgroundColor="#00f8"&gt;  
            &lt;panel id="panel_bottom_left" height="50%" width="50%" valign="center" childLayout="center" 
           backgroundColor="#44f8"&gt;  
            &lt;/panel&gt;
            &lt;panel id="panel_bottom_right" height="50%" width="50%" valign="center" childLayout="center"
           backgroundColor="#88f8"&gt;  
            &lt;/panel&gt;
        &lt;/panel&gt;
    &lt;/layer&gt;
&lt;/screen&gt;

</nifty>[/java]

As a work around to this I have started wrapping anything nifty calls with the following, which at least helps

[java]
try{
//tasks
}catch(RuntimeException e){
//for some unknown reason nifty silently consumes all exceptions, this
//at least prints them
e.printStackTrace();
throw e;
}
[/java]