-1

I'm writing a PreferedCustomer object to a .dat file using FileIOStreams and ObjectIOStreams. I'm practicing Inheritance so there is a simple class hierarchy.

PreferredCustomer.java inherits from Customer.java

Customer.java inherits from Person.java.

When I read my PreferredCustomer object from the .dat file, it calls the Person.java no arg constructor and sets the Name, Address, and PhoneNumber field to "". How do I prevent it from calling the no arg construct which resets the String values?

I have the project hosted on github. https://github.com/davidmistretta/CustomerObjectDAT

The code I believe needs to be reworked is in Consumers -> src -> CustomerDemo -> StoreConsumerObjects.java lines 30->40 (the try/catch statement below)

Main method which writes an object then reads an object

public static void main(String[] args)
{
    try (FileOutputStream fos = new FileOutputStream("customers.dat");
         ObjectOutputStream oos = new ObjectOutputStream(fos)) {

        PreferredCustomer pc = new PreferredCustomer("David Mistretta","943 Fakedale Way, Funnyvale, MO, 01337","978-000-0000","01A001");
        pc.setBalance(550);
        System.out.println("Object to input into customers.dat\n" + pc.toString() +"\n\n");
        oos.writeObject(pc);
    } catch (IOException e) {
        e.printStackTrace();
    }

    try (FileInputStream fis = new FileInputStream("customers.dat");
         ObjectInputStream ois = new ObjectInputStream(fis)) {

        PreferredCustomer pca = (PreferredCustomer) ois.readObject();
        System.out.println("Object output from customers.dat\n" + pca.toString());
        ois.close();
    } catch (IOException | ClassNotFoundException e) {
        e.printStackTrace();
    } 
} 

The no arg constructor I wrote in Person.java (lines 28 -> 34)

public Person() 
{
    System.out.println("Person no arg construct");
    m_name = "";
    m_phoneNumber = "";
    m_address = "";
}

Current output

Object to input into customers.dat
Preferred Customer
Name: David Mistretta
Address: 943 Fakedale Way, Funnyvale, MO, 01337
Phone Number: 978-000-0000
Customer Number: 01A001
Mailing List: true
Balance: 550.0
Discount: 0.05


Person no arg construct
Object output from customers.dat
Preferred Customer
Name: 
Address: 
Phone Number: 
Customer Number: 01A001
Mailing List: true
Balance: 550.0
Discount: 0.05

I expect for the Name, Address, and Phone Number field to reflect the fields when they were input. I followed the instructions on how to store an object in a file here https://kodejava.org/how-do-i-store-objects-in-file/

If someone could point me in the right direction on how to handle this, it would be appreciated.

  • If those fields are in a non-serialiBle class they won't be serialized. It is unclear what you're really asking here. You certainly can't change the mechanics of Serialization in this way, and it's unclear why you think it would help even if you could. – user207421 Jan 23 '19 at 06:19

2 Answers2

2

Each non-Serializable class constructor must be called. The Java language forbids anything else. The Java Serialization mechanism has to dodgy bytecode validation in order to avoid the constructor. In some classes constructors may perform some kind of security check.

However, the superclass constructor is called before anything on the Serializable classes. So you problem is presumably elsewhere.

(NB: Destroying and recreating persons in order to change their preferred status is frowned upon.)

Tom Hawtin - tackline
  • 145,806
  • 30
  • 211
  • 305
  • AHA! Thank you. You're comment enlightened me to the fact that I forgot an implements Serializible for my Person.java class. I guess I assumed only the Sub Class being written and read had to implement it. Thanks! I realize it makes a lot more sense to hold a database for changeable information, I just wanted to experiement reading and writing objects into and from .dat files. I'm thinking doing that may be a way to say, save a plethora of NPC objects in a game that hold specific information about them? Anyways, thanks for the help! – David Douglas Jan 23 '19 at 01:59
-1

So, I had neglected to add an implements Serializable in my Person.java class. Thanks to Tom Hawtin for telling me that the superclass constructor is called before anything on the Serializable classes which lead me to the source of my problem. Thus to prevent a no arg call to a superclass constructor when reading objects from ObjectInputStream, make sure that the superclass is using the Serializable interface. If it isn't the no arg constructor will be called.

  • It will still call the no-arg constructor of the nearest non-Serializable base class. The real issue was that you were expecting data in a non-Serializable class to be serialized, which is just a contradition in terms. – user207421 Jan 23 '19 at 06:30
  • So I realize now that I only need to implement Serializable in Person.java because PreferredCustomer.java inherits from it through Customer.java. How can a class be non-Serializable? From my understanding, you can Serialize - or write a byte stream - to a .dat file holding the state of an instantiated object. Then you can read that object by deserializing the byte stream, and loading that objects state into memory to be accessed(?). – David Douglas Jan 23 '19 at 08:20
  • A class is non-serializable if neither it nor any of its base classes or interfaces implements/extends `Serializable`. In which case nothing of it is serialized. – user207421 Jan 23 '19 at 11:24
  • @user207421 so when I added implements Serializable to Person.java (note: Cusomer and PreferredCustomer both implemented Serializable at the beginning of my question) it becomes a Serializable class. So, where is the contradiction of terms? When you say it will call the no arg constructor of the nearest non-Serializable class what do you mean by nearest? Any class within the scope of the package, or the project? Are you saying if I have another class in the same package the no arg constructor will still be called? What if that class doesn't inherit from Person.java? – David Douglas Jan 24 '19 at 03:22