3

I've been wondering if you serialize class data in an object like so:

public Something implements Serializable{
     private static final long serialVersionUID = 1L;
     public Class type;
}

What data is actually serialized and saved as type?

Is it possible to get info like simplename and fullname from type even if you don't have that class loaded at the time?

GhostCat
  • 137,827
  • 25
  • 176
  • 248
Moff Kalast
  • 1,024
  • 1
  • 12
  • 22

2 Answers2

3

Is it possible to get info like simplename and fullname from type even if you don't have that class loaded at the time?

As long as the class for the type is present, the class which the Class object refers to will be loaded.


Using the code below:

class Test implements Serializable {
    // verion UID

    public Class type;

    public Test(Class type) {
        this.type = type;
    }
}

I serialized a Test object which contained the Class for a different type: Second

ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("text.obj"));
out.writeObject(new Test(Second.class));
out.close();

Now, reading it back in:

ObjectInputStream in = new ObjectInputStream(new FileInputStream("text.obj"));
Test test = (Test) in.readObject();
in.close();

There's no reference to the Second class in this code. If Second is loaded when running the program above, we can assume it was due to deserialization rather than direct reference.

And it does:

enter image description here

So yes, attempting to obtain things like type.getSimpleName() will work.

Running:

ObjectInputStream in = new ObjectInputStream(new FileInputStream("text.obj"));
Test test = (Test) in.readObject();
System.out.println(test.type.getSimpleName());
in.close();

Prints

Second

When you delete the Second class, you get ClassNotFoundException as expected. By reading the stacktrace, you can see that the program attempts to load the Second class:

Exception in thread "main" java.lang.ClassNotFoundException: test.Second
    at java.net.URLClassLoader.findClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Unknown Source)
    at java.io.ObjectInputStream.resolveClass(Unknown Source)
    at java.io.ObjectInputStream.readNonProxyDesc(Unknown Source)
    at java.io.ObjectInputStream.readClassDesc(Unknown Source)
    at java.io.ObjectInputStream.readClass(Unknown Source)
    at java.io.ObjectInputStream.readObject0(Unknown Source)
    at java.io.ObjectInputStream.defaultReadFields(Unknown Source)
    at java.io.ObjectInputStream.readSerialData(Unknown Source)
    at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
    at java.io.ObjectInputStream.readObject0(Unknown Source)
    at java.io.ObjectInputStream.readObject(Unknown Source)
Vince
  • 14,470
  • 7
  • 39
  • 84
  • Thanks, that was pretty exhaustive! Just a slight follow up: Say if you had an array of different Class types in a serialized object (that are all missing from the project), I assume the inputstream would throw the exception as soon as it hits the first one, correct? Would it be possible to read the declared data of those? – Moff Kalast Jun 28 '17 at 11:44
  • @MoffKalast Yeah, an exception will be thrown as soon as it attempts to deserialize an object which the class doesn't exist in the project for for. May I ask why you're exploring this? Object streams tend to be abused (used for things that can be done more efficiently using a different tool) and serialization may lead to problems when to scaling up if not treated with caution (see my answer on "[What is the penalty for unnecessarily implementing Serializable](https://stackoverflow.com/questions/39079928/what-is-the-penalty-for-unnecessarily-implementing-serializable/39088501#39088501)) – Vince Jun 28 '17 at 13:53
  • Well I had a substantial amount of serialized files that contained Class data as a means of identifying components which I need to keep compatibility with while modifying the actual classes' packages. I ended up modifying the ObjectInputStream so it matches the class simplename to one in a hashmap in case it cannot find it by default (like this answer suggests: https://stackoverflow.com/a/3916282/4012132). I was mostly interested in other ideas and the fact that a Class raw type is serializable while the Class it contains may not be - causing some odd stuff on loading it up again. – Moff Kalast Jun 28 '17 at 14:16
  • @MoffKalast I created a chat, [click here](https://chat.stackoverflow.com/rooms/147830/room-for-vince-emigh-and-moff-kalast). I may be able to help ya out, hopefully stray you away from the headaches of attempting to modify a serialized type – Vince Jun 28 '17 at 14:28
0

Simple: this will serialize all non-transient fields that exist in that Class class.

In that sense: turn to the source of Class.java if you really care about the details.

The second question (if it is possible to deserialize a class which can't be loaded) - I am making an educated guess: I think this should fail. The point is: the Class object would allow you to query for fields, methods,... Which is not possible without full knowledge about that class.

But that should be pretty easy to test. In case nobody comes up with a better answer tonight... I will check tomorrow and let you know.

GhostCat
  • 137,827
  • 25
  • 176
  • 248