7

If I serialize a Class object (for example, HashMap.class), and then deserialize it in another instance of JVM, it turns out that the deserialized class is identical to the one currently loaded:

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.HashMap;

final class DeserializationTest {

    static String path = "/home/suseika/test.ser";
    static Class<HashMap> cls = HashMap.class;

    public static void main(String[] args) throws Exception {
        if (args[0].equals("serialize")) {
            serialize();
        } else if (args[0].equals("deserialize")) {
            final Object deserialized = deserialize();

            // The important line, prints "true"
            System.out.println(deserialized == cls); 
        }
    }

    static Object deserialize() throws Exception {
        ObjectInputStream in = new ObjectInputStream(new FileInputStream(path));
        return in.readObject();
    }

    static void serialize() throws Exception {
        FileOutputStream fileOut = new FileOutputStream(path);
        ObjectOutputStream out = new ObjectOutputStream(fileOut);
        out.writeObject(cls);
        out.close();
        fileOut.close();
    }
}

How is Java able to deserialize objects in this case so that identity is preserved? Class doesn't seem to implement writeObject()/readObject()/readResolve().

Can this behavior be broken with loading a particular class/using a particular classloader/using a particular JVM setup/doing something during serialization? Are there instances where the loaded Class would not be the same as the deserialized one? In other words, can I rely on this behavior in my application to serialize and deserialize Class objects?

gvlasov
  • 18,638
  • 21
  • 74
  • 110
  • 3
    IMHO: a deserialized class object should be indistinguishable of a "standard" class object of the same type. See https://docs.oracle.com/javase/7/docs/api/serialized-form.html#java.lang.Class – Xvolks Mar 09 '16 at 12:43

2 Answers2

2

How is Java able to deserialize objects in this case so that identity is preserved?

This is because class instances are cached by the classloader.

Does Java guarantee that Object.getClass() == Object.getClass()?

Can this behavior be broken with loading a particular class/using a particular classloader/using a particular JVM setup/doing something during serialization?

For serialized instances of classes from packages not starting with java.* this can be broken using different classloaders in ObjectInputStream (an example here).

For classes in java.* like your case (java.lang.Class), only the Bootstrap class loader can load them, and given that class definition is unique per class loader (guaranteed by the JVM spec)

In other words, can I rely on this behavior in my application to serialize and deserialize Class objects

Yes

Community
  • 1
  • 1
idelvall
  • 1,536
  • 15
  • 25
  • Sure `Class`es are cached by the classloader, what was surprising to me is the fact that deserializing a `Class` created in _another_ JVM instance preserves identity with `Class` instances in the current JVM instance. So if I use the standard deserialization logic of `ObjectInputStream`, use only a single classloader and don't have different definitions for classes with same canonical names, then I can be sure that identity of `Class` objects will be preserved after deserialization? – gvlasov Mar 09 '16 at 17:50
  • Notice that this you refer to as "Class" is in fact an instance of class `Class` (sorry for the tongue-twister). So you can't have multiple instances per classloader representing the same class FQN. Therefore the answer is yes, you can be sure – idelvall Mar 09 '16 at 18:21
  • Also notice that deserializing a serialized object (from any class including `Class`) may lead to errors if the versions differ... – idelvall Mar 09 '16 at 18:24
  • I have just created an answer that maybe is of your interest: http://stackoverflow.com/a/35901086/4483113 – idelvall Mar 09 '16 at 19:44
  • Hi just edited my response. `java.lang.Class` can not be loaded by a different class loader, so it is guaranteed – idelvall Mar 13 '16 at 10:29
  • If I try to deserialize the object from a JVM where the class DeserializationTest is not loaded, would it be able to deserialize? In other words, is class level metadata stored in the serialized file? – Nishit Aug 21 '18 at 17:23
0

How is Java able to deserialize objects in this case so that identity is preserved? Class doesn't seem to implement writeObject()/readObject()/readResolve().

It doesn't need to implement readObject() or writeObject() to accomplish this, but it could do it by implementing readResolve(), or by special logic in ObjectInputStream.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • Thanks, but this should be a comment, not an answer. I edited my post mentioning that `Class` doesn't have `readResolve()` either. – gvlasov Mar 09 '16 at 12:57
  • It is not a comment. I have now quoted the question that is answered by this answer. As it appears to have been an incorrect answer, I have amended it. – user207421 Mar 09 '16 at 21:23