1

I have read many of the other answers on StackOverflow regarding this same type of problem, however, mine is different than any I've read.

I am having troubles adding Objects to an ArrayList. I keep getting NullPointerException's. As you can see, my list is initialized, and I am feeding it the proper type of objects. It fails at the first one. You can see my println before trying to add to the ArrayList, and the println shows all information correctly, nothing is null, those are all the properties of the object. It tries to add that object to the ArrayList, and throws a NullPointerException.

Please help sort me out so I can move on from this issue. Thanks guys!

protected ArrayList units = new ArrayList<Fleet>();

public FleetParser(JSONObject json)
{
    super(json);
}

@Override
public void process(JSONObject o)
{
    Fleet fleet = new Fleet();
    fleet.inflateFromJSON(o);
    if(fleet.getUid() != null) {
        System.out.println(fleet.getUid() + " " + fleet.getPuid() + " " + fleet.getShips() + " " + fleet.getName());
        units.add(fleet);
    }
}

Edit: Here is the Stacktrace from the console in Intellij. You will notice it executes the first println just fine.

:compileJavaNote: /home/cody/IdeaProjects/NeptuneCommand/src/main/java/com/codyhalovich/neptunecommand/Parsers/FleetParser.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.

:processResources UP-TO-DATE
:classes
:runSimple
Exception in thread "main" java.lang.NullPointerException
78 17 45 New Bellatrix I
    at com.codyhalovich.neptunecommand.Parsers.FleetParser.process(FleetParser.java:25)
    at com.codyhalovich.neptunecommand.Parsers.BaseParser.initParse(BaseParser.java:24)
    at com.codyhalovich.neptunecommand.Parsers.BaseParser.<init>(BaseParser.java:16)
    at com.codyhalovich.neptunecommand.Parsers.FleetParser.<init>(FleetParser.java:14)
    at com.codyhalovich.neptunecommand.Parsers.ReportParser.<init>(ReportParser.java:26)
    at com.codyhalovich.neptunecommand.NeptuneCommand.main(NeptuneCommand.java:25)
:runSimple FAILED

Here is the Interface that is implemented by a base abstract class

public interface ParserInterface {
    ArrayList<Object> units = new ArrayList<Object>();
    JSONObject json = null;

    void initParse();
    void process(JSONObject o);

    java.util.ArrayList getUnits();
}

Here is the BaseParser abstract class

public abstract class BaseParser implements ParserInterface {

    private JSONObject json;
    protected ArrayList units = new ArrayList<Object>();

    public BaseParser(JSONObject json)
    {
        this.json = json;
        this.initParse();
    }

    public void initParse()
    {
        for(Object key: json.keySet())
        {
            if(key != null) {
                this.process((JSONObject) json.get(key));
            }
        }
    }

    public abstract void process(JSONObject json);

    public ArrayList getUnits()
    {
        return this.units;
    }

}

The piece of code that is running this is:

JSONObject fleets = report.getFleets();
FleetParser fleetParser = new FleetParser(fleets);
10
  • put a breakpoint in line units.add(). Commented Jul 3, 2014 at 18:20
  • 6
    Could you give us the stack trace from the exception? Commented Jul 3, 2014 at 18:20
  • 2
    I don't think that units in the subclass has been initialiased at the time that the base class constructor is running. Incidentally, it's a REALLY bad idea to have two fields of the same name - one in the base class and one in the subclass. It leads to confusing bugs like this one. Commented Jul 3, 2014 at 18:38
  • 1
    Do you know that fields in interface are static and final? Most probably you shouldn't be declaring ArrayList<Object> units and JSONObject json in ParserInterface, anyway you already declared them in BaseParser. Also you shouldn't be invoking non-private (or non-final, or non-static) methods in constructor (public void initParse()) since they are polymorphic so they could be overridden in derived class. Commented Jul 3, 2014 at 18:45
  • 1
    cody, Pshemo's answer is correct, and it's basically a much more detailed version of what I said. There would be no point in my duplicating it. I think you should just upvote and accept Pshemo's answer. Commented Jul 3, 2014 at 23:01

1 Answer 1

3

You have problem with order of initializing fields. You need to know that initialization blocks (which includes initialization of fields) is invoked

  • after constructor of super class (after explicit or implicit super(...) call which is always at start of constructor)
  • before constructors actual code (the one after super(...)).

In other words this code

class SomeClass extends BaseClass{
    String field = "some value";

    SomeClass(String data){ //constructor
        super(data);

        System.out.println(field);
    }
}

will be compiled into

class SomeClass extends BaseClass{
    String field = null;  // initialization is moved --+
                          //                           |
    SomeClass(String data){   //                       |
        super(data);          //                       |
        field = "some value"; // here <----------------+ 
        System.out.println(field);
    }
}

So while invoking super(data) field is not yet initialized so its value is null.

This code maybe will show it better:

abstract class Base {
    protected String field = "foo";
    public abstract void method();

    public Base() {
        method();
    }
}

class Derived extends Base {
    protected String field = "bar";

    public Derived() {
        super();
    }

    public void method() {
        System.out.println("value of field is "+field);
    }
}

class TestX{
    public static void main(String[] args) {
        new Derived();
    }
}

Output: value of field is null

It happened because while method refers to field from TestX class, and as mentioned earlier its value will be set after super(), so for now it is null.

If you wouldn't redeclare field in derived class method would use field from base class. So for

class Derived extends Base {
//  protected String field = "bar";

    public Derived() {
        super();
    }

    public void method() {
        System.out.println("value of field is "+field);
    }
}

result would be value of field is foo because initialization of field is completed before calling actual code from constructor (as mentioned earlier, field initialization happens after constructor of super class, but before actual code of current constructor).


Your case is similar to this example, but instead of String field you have

protected ArrayList units

Take a look at your code: in your BaseParser constructor you are calling initParse() which is calling abstract method process, which uses code from FleetParser (based on your stacktrace) which looks like

@Override
public void process(JSONObject o)
{
    //... some code
    units.add(fleet);
}

and units is list redeclared in FleetParser and since flow of control is currently in super(..) units couldn't be initialized.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.