javanullpointerexceptiongridworld

NullPointerException in the middle of GridWorld code


I am using the GridWorld case study. I seem to have discovered a bug in the provided program. After attempting to create a grid of invalid size through the GUI and closing the error message, whenever I try to do anything with the existing grid, I get a NullPointerException:

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
        at info.gridworld.gui.GUIController$3.mousePressed(GUIController.java:119)
        at java.awt.AWTEventMulticaster.mousePressed(AWTEventMulticaster.java:279)
        at java.awt.Component.processMouseEvent(Component.java:6501)
        at javax.swing.JComponent.processMouseEvent(JComponent.java:3321)
        at java.awt.Component.processEvent(Component.java:6269)
        at java.awt.Container.processEvent(Container.java:2229)
        at java.awt.Component.dispatchEventImpl(Component.java:4860)
        at java.awt.Container.dispatchEventImpl(Container.java:2287)
        at java.awt.Component.dispatchEvent(Component.java:4686)
        at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4832)
        at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4489)
        at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4422)
        at java.awt.Container.dispatchEventImpl(Container.java:2273)
        at java.awt.Window.dispatchEventImpl(Window.java:2713)
        at java.awt.Component.dispatchEvent(Component.java:4686)
        at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:707)
        at java.awt.EventQueue.access$000(EventQueue.java:101)
        at java.awt.EventQueue$3.run(EventQueue.java:666)
        at java.awt.EventQueue$3.run(EventQueue.java:664)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
        at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:87)
        at java.awt.EventQueue$4.run(EventQueue.java:680)
        at java.awt.EventQueue$4.run(EventQueue.java:678)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
        at java.awt.EventQueue.dispatchEvent(EventQueue.java:677)
        at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThre ad.java:211)
        at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread. java:128)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThre   ad.java:117)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:113)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:105)
        at java.awt.EventDispatchThread.run(EventDispatchThread.java:90)

Additionally, I am unable to change the grid to something else, via the provided GUI:

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
        at info.gridworld.gui.WorldFrame.setGrid(WorldFrame.java:237)
        at info.gridworld.gui.MenuMaker$GridConstructorItem.actionPerformed(MenuMaker.java:344)
        at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2018)
        at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2341)
        at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:402)
        at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:259)
        at javax.swing.AbstractButton.doClick(AbstractButton.java:376)
        at javax.swing.plaf.basic.BasicMenuItemUI.doClick(BasicMenuItemUI.java:833)
        at javax.swing.plaf.basic.BasicMenuItemUI$Handler.mouseReleased(BasicMenuItemUI.java:877)
        at java.awt.Component.processMouseEvent(Component.java:6504)
        at javax.swing.JComponent.processMouseEvent(JComponent.java:3321)
        at java.awt.Component.processEvent(Component.java:6269)
        at java.awt.Container.processEvent(Container.java:2229)
        at java.awt.Component.dispatchEventImpl(Component.java:4860)
        at java.awt.Container.dispatchEventImpl(Container.java:2287)
        at java.awt.Component.dispatchEvent(Component.java:4686)
        at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4832)
        at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4492)
        at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4422)
        at java.awt.Container.dispatchEventImpl(Container.java:2273)
        at java.awt.Window.dispatchEventImpl(Window.java:2713)
        at java.awt.Component.dispatchEvent(Component.java:4686)
        at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:707)
        at java.awt.EventQueue.access$000(EventQueue.java:101)
        at java.awt.EventQueue$3.run(EventQueue.java:666)
        at java.awt.EventQueue$3.run(EventQueue.java:664)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
        at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:87)
        at java.awt.EventQueue$4.run(EventQueue.java:680)
        at java.awt.EventQueue$4.run(EventQueue.java:678)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
        at java.awt.EventQueue.dispatchEvent(EventQueue.java:677)
        at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:211)
        at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:128)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:117)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:113)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:105)
        at java.awt.EventDispatchThread.run(EventDispatchThread.java:90)

I think this is a bug in the GridWorld program itself, and not in any code I write, because this seems to happen even when I just launch the program without giving it any code to execute. I've done some investigation and found that for some reason, the grid gets set to null whenever I attempt to change the grid in the GUI, and the grid I try to create is invalid (or any exception happens when creating the grid). Why is the grid getting set to null? Is there a way I can fix this in the provided source code myself?

The build that I am using is GridWorld 1.02 available at GridWorld.info under the "unofficial code" link. The code at the CollegeBoard website is older. I've tested this and it also happens for older releases.


Solution

  • Here is what happens

    The NullPointer Exception happens in Source File GUIController.java as indicated by the stacktrace.

    Grid<T> gr = parentFrame.getWorld().getGrid();
    Location loc = display.locationForPoint(evt.getPoint());
    if (loc != null && gr.isValid(loc) && !isRunning())
    

    gr, which is retreived from getWorld().getGrid() can be null and the if statement does not check gr before calling gr.isValid().

    Tracing the Source:

    The Grid gets set by the setGrid() method in WorldFrame.java, which does not check its imput, that is, if you call the method with null, it will set the new grid to null.

    The setGrid() method is beeing called from MenuMaker.java (line 343)

    Grid<T> newGrid = (Grid<T>) invokeConstructor(); 
    parent.setGrid(newGrid);
    

    and the invokeConstructor() method returns null on exceptions. This is, where your null comes from

    Fix

    Make sure that setGrid in WorldFrame.java does not accept null values as parameter.

    public void setGrid(Grid<T> newGrid) {
        if (newGrid == null) {
            return;
        }
        // rest of method goes here
    

    An probably better, yet more complex, solution would be, to ensure that invokeConstructor() in MenuMaker.java does not return null. Notifying the GUI and handling the Exception (instead of returning null) would be a more elegant solution.

    Hope this helps.