0

EDIT : solved using this solution

I have a very strange problem. I'm trying to deserialize a HashMap with two classes that have since been changed, though not to any large degree. Can't post code because it's under copyright.

Notably the constructor of Class 2 has an added field (String name) since the file I'm trying to deserialize was serialized.

It seems like Class 1 is trying to be cast to String as the name field of Class 2.

I've always been using ObjectInputStream and ObjectOutputStream. The part that has me mystified is that Class 1 has never had a member variable of type Class 2, and the HashMap types have always been in the order . I don't really know what's going on, so I tried a solution posted in this question that had the same exception as I'm getting, but despite lots of research on ClassLoaders, I still don't really understand and didn't really know what ClassLoader to use as the "free variable".

Here is the stack trace (class names changed) of the problem I'm encountering:

java.lang.ClassCastException: cannot assign instance of [CLASS 1] to field [CLASS 2].name of type java.lang.String in instance of [CLASS 2]
at java.io.ObjectStreamClass$FieldReflector.setObjFieldValues(ObjectStreamClass.java:2034)
at java.io.ObjectStreamClass.setObjFieldValues(ObjectStreamClass.java:1207)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1975)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1893)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1775)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1327)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:349)
at java.util.HashMap.readObject(HashMap.java:1030)
at sun.reflect.GeneratedMethodAccessor27.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:969)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1871)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1775)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1327)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:349)

Code snip:

    final ClassLoader loader = this.getClass().getClassLoader();    //attempt to solve ClassCastException issue below.
            FileInputStream fin = new FileInputStream(targetFile);
            InputStream buffer = new BufferedInputStream(fin);
            ObjectInputStream ois = new ObjectInputStream(buffer)   {

                /*
                 * As seen here: https://stackoverflow.com/questions/2358886/how-can-i-deserialize-the-object-if-it-was-moved-to-another-package-or-renamed
                 */
                @Override
                protected ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException    {
                    ObjectStreamClass resultClassDescriptor = super.readClassDescriptor();

                    if (resultClassDescriptor.getName().equals("Class 1 [old path]"))
                        resultClassDescriptor = ObjectStreamClass.lookup(Class 1 [new path].class);                    
                    else if (resultClassDescriptor.getName().equals("Class 2 [old path]"))
                        resultClassDescriptor = ObjectStreamClass.lookup(Class 2 [new path].class);

                    return resultClassDescriptor;
                }

                /*
                 * As seen here : https://stackoverflow.com/questions/9110677/readresolve-not-working-an-instance-of-guavas-serializedform-appears
                 */
                @SuppressWarnings("rawtypes")
                @Override
                protected Class resolveClass(ObjectStreamClass objectStreamClass)
                        throws IOException, ClassNotFoundException {
                    return Class.forName(objectStreamClass.getName(), true, loader);
                }
            };

            Object ob = ois.readObject(); //exception happens here
            HashMap<Class 1, Class 2> loadedMap = (HashMap<Class 1, Class 2>)ob;

            ois.close();
            buffer.close();
            fin.close();
Community
  • 1
  • 1
tM --
  • 207
  • 1
  • 13

1 Answers1

0

it looks like that you are assigning the two incompatible classes.

class_1 = new class_2()

class_1 has to be either of class_2 or superclass of class_2. it seems that

resultClassDescriptor = ObjectStreamClass.lookup(Class 2 [new path].class);

may be the culprit. //................... EDIT

class A{}
class B extends A{}
class C{}

A obj = new B(); , will not give error since A is super class of B. if you cast obj to class C, then it will throw ClassCastException

C cobj = (C) obj;

navyad
  • 3,752
  • 7
  • 47
  • 88
  • I don't understand, why does Class 1 have to be either Class 2 or superclass of Class 2? – tM -- Sep 04 '13 at 17:09
  • But it seems like Class 1 is trying to be cast to a String, more specifically in the name field of Class 2. I don't understand how this answers my question. – tM -- Sep 04 '13 at 17:26