0

after reading for serialization, i tried to perform an experiment on the example provided in the book. Following code has some variation and this is basically picked from SCJP book.

import java.io.FileInputStream;

public class SerializationTest {
    public static void main(String[] args) {
        Collar c = new Collar(4);
        Dog d = new Dog(c, "Sheru", 32);
        FileOutputStream fos = null;
        ObjectOutputStream oos = null;
        try {
            fos = new FileOutputStream(
                    "C:\\Users\\dell\\Desktop\\NewDir\\DogState.txt");
            oos = new ObjectOutputStream(fos);
            oos.writeObject(d);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                oos.close();
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        // ***************************************************************************************************
        // //
        Dog restore = null;
        FileInputStream fis = null;
        ObjectInputStream ois = null;
        try {
            fis = new FileInputStream(
                    "C:\\Users\\dell\\Desktop\\NewDir\\DogState.txt");
            ois = new ObjectInputStream(fis);
            restore = (Dog) ois.readObject();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            try {
                fis.close();
                ois.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        System.out.println("after: dog name: "+ restore.name +" , collar=" + restore.getCollar());
        System.out.println("Animal material is:" + restore.getWeight());
    }
}

// Intentionally added parameterized constructor so that default constructor is not called.
class Animal{
    int weight = 42;
    public Animal(int weight) {
        this.weight = weight;
        System.out.println("animal constructor");
    }
}


class Dog extends Animal implements Serializable {
    String name;
    transient Collar collar;

    public Collar getCollar() {
        return collar;
    }

    public void setCollar(Collar collar) {
        this.collar = collar;
    }

    public int getWeight() {
        return weight;
    }

    public void setWeight(int weight) {
        this.weight = weight;
    }

    public Dog(Collar collar, String name, int weight) {
        super(weight);
        System.out.println("Dog constructor");
        this.collar = collar;
        this.name = name;
    }

}
class Collar {
    int size;

    public Collar(int size) {
        System.out.println("Collar constructor");
        this.size = size;
    }
}

Here my question is why InvalidClassException is occuring, Please explain what is the root cause of exception. Current output is

Collar constructor
animal constructor
Dog constructor
java.io.InvalidClassException: Dog; Dog; no valid constructor
    at java.io.ObjectStreamClass.checkDeserialize(Unknown Source)
    at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
    at java.io.ObjectInputStream.readObject0(Unknown Source)
    at java.io.ObjectInputStream.readObject(Unknown Source)
    at SerializationTest.main(SerializationTest.java:39)
Caused by: java.io.InvalidClassException: Dog; no valid constructor
    at java.io.ObjectStreamClass.<init>(Unknown Source)
    at java.io.ObjectStreamClass.lookup(Unknown Source)
    at java.io.ObjectOutputStream.writeObject0(Unknown Source)
    at java.io.ObjectOutputStream.writeObject(Unknown Source)
    at SerializationTest.main(SerializationTest.java:18)
Exception in thread "main" java.lang.NullPointerException
    at SerializationTest.main(SerializationTest.java:54)

If i remove Animal constructor and comment out the super(weight) in Dog constructor, then output is

Collar constructor
Dog constructor
after: dog name: Sheru , collar=null
Animal material is:42

I understand this output, and i also get the fact that during de-serialization serialzable class's superclass constructor is called but here no default constructor is present, so exception occured. But why this exception occur i want to know.

3
  • Java doesn't know how to construct a new instance of your class without a default constructor. Commented Apr 17, 2013 at 17:45
  • @MattBall but the initial error occur while writing the object, and while writing i am providing the object to the JVM and JVM should store( serialize) it into the file. At this point ( storing of object ) why and where creation of object is needed. I read that while de-serializing an object is returned ( and non serialized superclass constructor is called to initialize the value ). But here problem starts with writeObject() not readObject() Commented Apr 17, 2013 at 18:15
  • possible duplicate of java.io.InvalidClassException: no valid constructor Commented Apr 17, 2013 at 19:06

3 Answers 3

1

The exception is thrown by the time you try to read the from the file:

at java.io.ObjectInputStream.readObject(Unknown Source)
at SerializationTest.main(SerializationTest.java:39)

The stack trace clearly indicates that your program aborts when it attempts to read an object. What may get you confused is the second stack trace referring to the write:

at java.io.ObjectOutputStream.writeObject(Unknown Source)
at SerializationTest.main(SerializationTest.java:18)

But you seem to have skipped this very important line:

Caused by: java.io.InvalidClassException: Dog; no valid constructor

Java stacktraces can be nested, one exception can lead to another; and this here is a litte ackward. As a matter of fact, during the serialization of an object it is already computed that there is no default constructor. Here's an excerpt of the involved source code:

...
cons = getSerializableConstructor(cl);
...
} else if (cons == null) {
    deserializeEx = new InvalidClassException(name, "no valid constructor");
}

This means that during the write, it is already clear that there is no valid constructor. However, the exception is not thrown but serialized along with the object. Later, when deserializing, this code is called:

void checkDeserialize() throws InvalidClassException {
    if (deserializeEx != null) {
        InvalidClassException ice =
            new InvalidClassException(deserializeEx.classname,
                                      deserializeEx.getMessage());
        ice.initCause(deserializeEx);
        throw ice;
    }
}

Here, a "real" exception is thrown, but the cause of it is set to be the one stored during serialization of the object.

This mechanism is only found in SUN/Oracle's Java implementation; OpenJDK clearly throws an exception by the time a read is attempted, and does not keep around a stack trace from writing.

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

1 Comment

This answer digs deep, but I'd like to add an important detail: If the super class is public, it gets a public default constructor and does not need to implement Serializable. However, if the class being extended is not public, it will need to implement Serializable.
0

The non-Serializable base class Dog must have an accessible default constructor. When you comment out the Dog(weight) constructor, you force the compiler to provide one, and when you leave it in the compiler doesn't provide one.

Comments

0

There is a rule that the parent class of the serializing class or any associated class to that must be implementing Serializable.
In your case, when you remove thesuper(weight); then it checks for default constructor and runs properly
But also if you put class Animal implements Serializable then also code runs properly.

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.