0

I've created a class Auto that contains an OptionSet array class (ie Color, Transmission), which connects to an OptionSet class that contains an Options array inner class(ie Blue, Red). I plan to read in a text file line by line and populate an Auto object with it. However, I don't know how to create an Auto object with a OptionSet array that is defined when reading the file, without having a NullPointerException.

From what I understand, I shouldn't use the specific constructor because the array length will become unchangeable, making reading other sized files difficult. But using the default constructor means the arrays in the optionSet and Option objects aren't initialized and cause NullPointerErrors. (I know arrayList is another option for building this, and one we'll be using; this is a class project that goes through common mistakes on its way to building a product.) IS there a way around this problem, or something else I'm missing?

Here's my error code:

Exception in thread "main" java.lang.NullPointerException
    at model.Automotive.setOptionSetName(Automotive.java:61)
    at util.FileInput.readData(FileInput.java:32)
    at driver.Driver.main(Driver.java:17)

The auto class:

package model;

import java.io.*;
import java.io.Serializable;

import model.OptionSet;
import model.OptionSet.Option;
import util.FileInput;

public class Automotive implements Serializable{

//variables
private String name;
private static float basePrice;
private OptionSet[] opSet;

//constructor
public Automotive(int size, String n, float price) {
    opSet = new OptionSet[size];
    name = n;
    basePrice = price;
    for(int i=0; i<opSet.length; i++) {
        opSet[i] = new OptionSet();
    }
}

public Automotive() {
}

public void createOptionsSet(int opSetSize) {
    this.opSet = new OptionSet[opSetSize];  
}

public void createOption(int opSetLocation, int size) {
    this.opSet[opSetLocation].createOption(size);
}

public void setName(String newName) {
    name = newName;
}

public String getName() {
    return name;
}

public void setPrice(float price) {
    basePrice = price;
}

public float getPrice() {
    return basePrice;
}

public OptionSet getOptionSet(int location) {
    return opSet[location];
}

public void setOptionSetName(int opSetLocation, String opSetName) {
    this.opSet[opSetLocation].setOptionSetName(opSetName);
}   

public String getOptionSetName(int opSetLocation) {
    return this.opSet[opSetLocation].getOptionSetName();
}

public void setOption(int opSetLocation, int opLocation, String name, float price) {
    this.opSet[opSetLocation].setOption(opLocation, name, price);
}

public Option getOption(int opSetLocation, int opLocation) {
    return this.opSet[opSetLocation].getOption(opLocation);
}
}

The optionSet class (with inner class Option)

package model;

import java.io.Serializable;
import java.util.Arrays;

import model.OptionSet;

public class OptionSet implements Serializable{
//variables
private OptionSet[] opSet;
private Option opt[];
private String name;

//constructor
protected OptionSet(String n, int size) {
    opt = new Option[size];
    name = n;
    for(int i=0; i<opt.length; i++) {
        opt[i] = new Option();
    }
}

public OptionSet() {
}

//methods
protected void createOptionsSet(int size) {
    OptionSet[] opSet = new OptionSet[size];//creates OptionSet array
}

protected void createOption(int size) {
    this.opt = new Option[size];
}

protected void setOptionSetName(String newNname) {
    name = newNname; //to name the optionSet cells - color, transmission, etc
}

protected String getOptionSetName() {
    return name;
}


protected void setOption(int location, String newName, float newPrice) {
    this.opt[location].setName(newName);
    this.opt[location].setPrice(newPrice);
}

protected Option getOption(int location) {
    return this.opt[location];
}

protected void setOptionName(int location, String newName) {
    this.opt[location].setName(newName);
}

protected String getOptionName(int location) {
    return this.opt[location].name;
}

protected void setOptionPrice(int location, float newPrice) {
    this.opt[location].setPrice(newPrice);
}

protected float getOptionPrice(int location) {
    return this.opt[location].price;
}

protected void deleteOption(int location) {
    this.opt[location].deleteOption();
}

protected void deleteOptionName(int location) {
    this.opt[location].deleteName();
}

protected void deleteOptionPrice(int location) {
    this.opt[location].deletePrice();
}

//does this work to print a custom object?
protected void print(Automotive auto) {
    System.out.printf("%10s", name);
    for(int j=0; j<opt.length; j++) {
        this.opt[j].print(auto);
    }
}

//inner class Option
protected class Option implements Serializable{
    private String name;
    private float price;

    Option(String name, float price){
        name = name;
        price = price;
    }

    public Option() {
    }

    protected void print(Automotive auto) {
        System.out.printf("%10s", name);
        System.out.printf("%10f", price);
    }

    protected void createOption(String name, float price) {
        Option opt = new Option(name, price);
    }

    protected void setName(String newName) {
        name = newName;
    }

    protected String getName() {
        return name;
    }

    protected void setPrice(float newPrice) {
        price = newPrice;
    }

    protected float getPrice() {
        return price;
    }

    protected void updateName(String newName) {
        name = newName;
    }

    protected void updatePrice(float newPrice) {
        price = newPrice;
    }
}

The FileInput class, using public Auto methods:

package util;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.StringTokenizer;

import model.*;

public class FileInput {
    public Automotive readData(String fileName){
        //houses parser
        Automotive auto = new Automotive();
//      auto.createOptionsSet(5);


        try {
            FileReader file = new FileReader(fileName);
            BufferedReader buff = new BufferedReader(file);
            String name = buff.readLine(); //Focus Wagon ZTW
            auto.setName(name);
            String price = buff.readLine(); //18445
            auto.setPrice(Integer.parseInt(price));
            int opSetSize = Integer.parseInt(buff.readLine()); //5
            auto.createOptionsSet(opSetSize); //create optionSet of size 5
            for(int opSetLocation=0; opSetLocation < opSetSize; opSetLocation++) {
                String optionTitle = buff.readLine(); //Color
                auto.setOptionSetName(opSetLocation, optionTitle);
                int opSize = Integer.parseInt(buff.readLine()); //10
                //optionsettotal, in each option set option array of size blah
                auto.createOption(opSetLocation, opSize);
                for (int opLocation=0; opLocation < opSize; opLocation++) { //loop to parse colors
                    String optionLine = buff.readLine(); //get first color, "gold, 0"
                    StringTokenizer st = new StringTokenizer(optionLine, ", ");
                    String optionName = st.nextToken();
                    float optionPrice = Float.parseFloat(st.nextToken());
                    auto.setOption(opSetLocation, opLocation, optionName, optionPrice);
                }
            }
        buff.close();   
        }
        catch (IOException e) {
            System.out.println("Error -- " + e.toString());
        }
        return auto;
    }

    public void serializeAuto(Automotive auto) 
    {
        try {
            ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("auto.ser"));
            out.writeObject(auto);
            out.flush();
            out.close();
        } catch (IOException e) {
            System.out.print("Error: " + e);
            System.exit(1);
        }
    }

    public Automotive deserializeAuto(String fileName) {
        Automotive newAuto = null;
        try {
            ObjectInputStream in = new ObjectInputStream(new FileInputStream(fileName));
            newAuto = (Automotive) in.readObject();
        }
        catch(IOException e) {
            System.out.print("Error: " + e);
            System.exit(1);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    return newAuto;
    }
}

And the Driver class for running the actual program:

package driver;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

import model.Automotive;
import util.FileInput;

public class Driver{

    public static void main(String[] args) {
        //Build Automotive object from a file
        FileInput file = new FileInput();
        Automotive FordZTW = file.readData("C:\\Users\\~ Adam ~\\Documents\\Computer Programming Notes\\Advanced Problem Solving\\FordZTW.txt");
        //print attributes before serialization
        FordZTW.printAuto(FordZTW);
        //Serialize object
        file.serializeAuto(FordZTW);
        //Deserialize the object and read it into memory
        Automotive newFordZTW = file.deserializeAuto("auto.ser");
        //print new attributes
        newFordZTW.printAuto(FordZTW);
    }
}
Adam
  • 47
  • 5
  • You need to write your code to be bullet-proof, so that it's not *possible* to access a null array, ever. – Hovercraft Full Of Eels Apr 24 '18 at 20:32
  • For my money the easiest solution is to not use an array of OptionSet but instead a List, `private List optionSetList = new ArrayList();`. Declare and initialize this not in a constructor but in variable declaration, and then use it as needed for a non-null list of OptionSet objects. – Hovercraft Full Of Eels Apr 24 '18 at 20:35
  • I absolutely agree, and if I were building this outside the classroom that would be my fix. Unfortunately because this is for a class, that solution is walled off until later, so I have to find a way around with arrays instead. – Adam Apr 24 '18 at 20:47
  • Then create your array in the constructor even if no parameters. You know where the NPE is being thrown so this should tell you how to avoid it. – Hovercraft Full Of Eels Apr 24 '18 at 20:47

0 Answers0