MrD
MrD

Reputation: 5084

Java NullPointerException in agent based model

I am using the MASON library to run a simple agent-based model.

As per specifications, I meant to access an agent's inspector by double-clicking on such agent in the Portrayal.

However, when I do so I get the following console error:

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
    at sim.display.Display2D.createInspectors(Display2D.java:1737)
    at sim.display.Display2D$8.mouseClicked(Display2D.java:1392)

I went to Display2D.java:1737 to find:

 public void createInspectors( final Rectangle2D.Double rect, final GUIState simulation )
        {
        Bag inspectors = new Bag();
        Bag names = new Bag();

        Bag[] hitObjects = objectsHitBy(rect);
        for(int x=0;x<hitObjects.length;x++)
            {
            FieldPortrayal2DHolder p = (FieldPortrayal2DHolder)(portrayals.get(x));
            for( int i = 0 ; i < hitObjects[x].numObjs ; i++ )
                {
                LocationWrapper wrapper = (LocationWrapper) (hitObjects[x].objs[i]);
                inspectors.add(p.portrayal.getInspector(wrapper,simulation));
                names.add(p.portrayal.getName(wrapper));
                }
            }
        simulation.controller.setInspectors(inspectors,names); //1737
        }

However, this is a library file so I'm not familiar with it.

Any advice?

Library: cs.gmu.edu/~eclab/projects/mason/

Update:

Ok, it gets interesting...

I did an echo on the toString method of inspectors and names, returning:

insepectors sim.util.Bag@1b2202a names sim.util.Bag@16b334d

Ok so they're bags, a type of collection. Time to get their sizes...

insepectors 1 names 1

Good, they're not empty.

Let's follow the error stack

Next bit:

at sim.display.Display2D$8.mouseClicked(Display2D.java:1392)

// add mouse listener for the inspectors
        insideDisplay.addMouseListener(new MouseAdapter()
            {
            public void mouseClicked(MouseEvent e) 
                {
                if (handleMouseEvent(e)) { repaint(); return; }
                else
                    {
                    // we only care about mouse button 1.  Perhaps in the future we may eliminate some key modifiers as well
                    int modifiers = e.getModifiers();
                    if ((modifiers & e.BUTTON1_MASK) == e.BUTTON1_MASK)
                        {
                        final Point point = e.getPoint();
                        if( e.getClickCount() == 2 )
                           1392-> createInspectors( new Rectangle2D.Double( point.x, point.y, 1, 1 ),
                                Display2D.this.simulation );
                        if (e.getClickCount() == 1 || e.getClickCount() == 2)  // in both situations
                            performSelection( new Rectangle2D.Double( point.x, point.y, 1, 1 ));
                        repaint();
                        }
                    }
                }

Ok, the error is clearly in the CreateInspectors method:

public void createInspectors( final Rectangle2D.Double rect, final GUIState simulation )
        {
        Bag inspectors = new Bag();
        Bag names = new Bag();

        Bag[] hitObjects = objectsHitBy(rect);
        for(int x=0;x<hitObjects.length;x++)
            {
            FieldPortrayal2DHolder p = (FieldPortrayal2DHolder)(portrayals.get(x));
            for( int i = 0 ; i < hitObjects[x].numObjs ; i++ )
                {
                LocationWrapper wrapper = (LocationWrapper) (hitObjects[x].objs[i]);
                inspectors.add(p.portrayal.getInspector(wrapper,simulation));
                names.add(p.portrayal.getName(wrapper));
                }
            }
        System.out.println("insepectors " + inspectors.size() + " names " + names.size());
        simulation.controller.setInspectors(inspectors,names);
        }

First thing I do:

System.out.println(rect.getCenterX() + " " + rect.getCenterY());

Which gives me 646.5 659.5. Seem to make sense as coordinates.

So next thing I want to look at hitObjects:

 System.out.println(hitObjects.length);

Returns 2. So I had two agents at that coordinates.

I assume the NPE is somewhere here:

for(int x=0;x<hitObjects.length;x++)
            {
            FieldPortrayal2DHolder p = (FieldPortrayal2DHolder)(portrayals.get(x));
            for( int i = 0 ; i < hitObjects[x].numObjs ; i++ )
                {
                LocationWrapper wrapper = (LocationWrapper) (hitObjects[x].objs[i]);
                inspectors.add(p.portrayal.getInspector(wrapper,simulation));
                names.add(p.portrayal.getName(wrapper));
                }
            }

The outer loop looks fine, but I'm having issues with the inner one. Advice?

Upvotes: 1

Views: 82

Answers (1)

djechlin
djechlin

Reputation: 60818

I'm actually going to write how to reason through the library code given as far as you've come since you sound capable.

You found the code. That's a good start. You've also found the line that it's on:

 simulation.controller.setInspectors(inspectors,names); //1737

And given what you know about NPEs you can reason that simulation or controller is null.

Do you know which? Can you reason about your code which you may have failed to set, or passed incorrectly? Can you put a debugger breakpoint or simple println statements in your code to determine which?

If not and you're using an IDE (you probably are), then from the source you just opened up, put a breakpoint before line 1737. When that line is reached, use the debugger to inspect the variable simulation then simulation.controller to see which is null. Exactly how to do this will depend on your IDE but it shouldn't be hard to find using XKCD's tech support cheat sheet.

Then you will probably know the cause. If not, continue reading source code, e.g. look a level up to line 1737.

Upvotes: 1

Related Questions