Search code examples
javaserializationclassloader

How do I deserialize an object when its class is stored in an external jar?


I implement Serializable to save objects, like so:

public class MyType implements Serializable {

    @Override
    public String toString() {
        return "This is a MyType";
    }

    public static void main(String[] args) {
        try {
            ObjectOutputStream outStream = new ObjectOutputStream(
                new FileOutputStream("objecturl");
            outStream.writeObject(new MyType());
            outStream.flush();
        } catch (Exception e) { e.printStackTrace(); }
    }
}

I run that program once so a MyType is saved at objecturl.

Then, I package that one-class library up into a jar at jarurl.

If I want to use the object I saved in a new program, how can I give access to MyType to my new program, given the jar that contains MyType.class?


In otherwords, how can I use the jar at jarurl to allow the following to work without getting a ClassNotFoundException?

public class NewProgram {

    public static void main(String[] args) {
        try {
            ObjectInputStream inStream = new ObjectInputStream(
                new FileInputStream("objecturl");
            Object o = inStream.readObject();
            System.out.println(o.toString());
        } catch (Exception e) { e.printStackTrace(); }
    }
}

where the output would be "This is a MyType", and MyType is not included in the same library as NewProgram.


Obviously there are other ways to get a program to output "This is a MyType". My major concern here is the usage of serialized, overridden implementation.

I know this has something to do with ClassLoaders, but I'm not sure how it works in this setting, where the type of the class is completely unknown, but the class's parent is known.


Solution

  • I haven't done this myself but from some googling it seems there are two stages to the problem.

    1. Create a ClassLoader that can load the class in question.
    2. Create (or find an existing in a third party library) a subclass of ObjectInputStream that overrides the resolveClass method to use your ClassLoader rather than the automatically selected one. Use the subclass of ObjectInputStream to read your file.

    https://docs.oracle.com/javase/7/docs/api/java/io/ObjectInputStream.html#resolveClass%28java.io.ObjectStreamClass%29