Spatial.getName() funny behaviour in a for-each loop

Hello everyone. I’ve been learning about jME3 for a couple of weeks now, and I’ve stumbled to something pretty weird, or maybe the problem is stupidly obvious, I don’t know anymore, I do know that I’ve spend a couple of days trying to figure this one out.

The following snippet is a part of an ItemControl that I’ve assigned to add items in the player’s inventory if the icon name of the item equals the name of the spatial in the scene.

The code works perfectly inside my game, the thing is though, if I would switch the spatialName with spatial.getName() in the if() statements inside the for-each loop, the game throws a NullPointerException. at (spatialName.equals(item.getIcon().getName())). I’ve tested getIcon() and it returns a string without problems, the problem is at spatial.getName(). I mean should that be the same thing? I just added the string to a reference variable and then used its name in the for each loop, why couldn’t I just call spatial.GetName() directly instead? To make it even more weird, when I launched the debugger and put some breakpoints a few lines before the for-each loop, the debugger just skips the breakpoints and directly jumps to the if() statement and throws the NPE.

Here’s the code that WORKS:

[java]
String spatialName = spatial.getName();

            for (Item item : inventoryWorld) {    
                if (spatialName.equals(item.getIcon().getName())) {
                    inventoryPlayer.add(item);               
                    if ("batteries".equals(spatialName)) {
                        spatial.removeControl(ItemControl.class);
                    } else {
                        spatial.removeFromParent();
                    }
                    guiNode.detachChild(interactIcon);
                    app.getStateManager().getState(Chapter1InventoryState.class).
                            setInventorySize(app.getStateManager().
                            getState(Chapter1InventoryState.class).getInventorySize() + 1);
               }
	}

[/java]

Here is the code that DOESN’T, along with the stack trace:

[java]
for (Item item : inventoryWorld) {
if (spatial.getName().equals(item.getIcon().getName())) {
inventoryPlayer.add(item);
if (“batteries”.equals(spatial.getName())) {
spatial.removeControl(ItemControl.class);
} else {
spatial.removeFromParent();
}
guiNode.detachChild(interactIcon);
app.getStateManager().getState(Chapter1InventoryState.class).
setInventorySize(app.getStateManager().
getState(Chapter1InventoryState.class).getInventorySize() + 1);
}
}
[/java]

Stack trace:

SEVERE: Uncaught exception thrown in Thread[LWJGL Renderer Thread,5,main]
java.lang.NullPointerException
at controls.ItemControl$1.onAction(ItemControl.java:130)
at com.jme3.input.InputManager.invokeActions(InputManager.java:169)
at com.jme3.input.InputManager.onMouseButtonEventQueued(InputManager.java:433)
at com.jme3.input.InputManager.processQueue(InputManager.java:833)
at com.jme3.input.InputManager.update(InputManager.java:883)
at com.jme3.app.Application.update(Application.java:604)
at com.jme3.app.SimpleApplication.update(SimpleApplication.java:231)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.runLoop(LwjglAbstractDisplay.java:151)
at com.jme3.system.lwjgl.LwjglDisplay.runLoop(LwjglDisplay.java:185)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:228)
at java.lang.Thread.run(Thread.java:722)

I think it’s because “spatial” becomes null. In your loop you have this:

spatial.removeControl(ItemControl.class);

and in the stack trace you have this:

at controls.ItemControl$1.onAction(ItemControl.java:130)

So i think that your code is IN an ItemControl.

When you call “spatial.removeControl(ItemControl.class);”, this remove “this” control (the one which is currently running the loop) from the spatial, making its attribute “spatial” null. So, when you try to do “spatial.getName()” again, it throws an NPE.

Can you try to to something like this:

[java]
Spatial oldRef = spatial
[/java]
before the loop, then use “oldRef.getName()” inside the loop, and check if you get this NPE ?

2 Likes
@bubuche said: When you call "spatial.removeControl(ItemControl.class);", this remove "this" control (the one which is currently running the loop) from the spatial, making its attribute "spatial" null. So, when you try to do "spatial.getName()" again, it throws an NPE.

Thank you so much, I can’t believe that I didn’t see that before. At one point the item is found in the ArrayList and then I need to continue to do something in the control but I just cut it off from the spatial. It’s like shooting yourself in the foot and still expect you to run. I guess I got tunnel vision after I started to pull out my hair with this one. I know what I’ll do now to fix the issue.

Thank you so much once again.

1 Like