-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 8 posts ] 
Author Message
 Post subject: InvalidClassException After Upgrade To 3.2.2 GA
PostPosted: Thu May 03, 2007 3:33 pm 
Regular
Regular

Joined: Wed Nov 17, 2004 11:49 am
Posts: 65
Location: Pittsburgh
I have an application where we store report criteria as serializable types to the database. These criteria can be any serializable java type, including hibernate entities. This all works dandy in 3.0.3, however, after a recent upgrade to 3.2.2, we find that we can no longer deserialize the report criteria.


Hibernate version:

Store serializable type in 3.0.3. Serializable type cannot be read in 3.2.2 GA.

Full stack trace of any exception that occurs:

Caused by: java.io.InvalidClassException: org.hibernate.collection.AbstractPersi
stentCollection; local class incompatible: stream classdesc serialVersionUID = 7
663409046372276524, local class serialVersionUID = 7602608801868099635
at java.io.ObjectStreamClass.initNonProxy(Unknown Source)
at java.io.ObjectInputStream.readNonProxyDesc(Unknown Source)
at java.io.ObjectInputStream.readClassDesc(Unknown Source)
at java.io.ObjectInputStream.readNonProxyDesc(Unknown Source)
at java.io.ObjectInputStream.readClassDesc(Unknown Source)
at java.io.ObjectInputStream.readOrdinaryObject(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.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)
at java.util.ArrayList.readObject(Unknown Source)
at sun.reflect.GeneratedMethodAccessor35.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at java.io.ObjectStreamClass.invokeReadObject(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)
at org.hibernate.util.SerializationHelper.deserialize(SerializationHelpe
r.java:210)
... 86 more

Any thoughts on how to get around this problem? It seems that the nature of serialization has changed between these hibernate releases. I am pretty sure that my classes (outside of Hibernate) are backwards compatible, as I have unit tests that demonstrate this.


Top
 Profile  
 
 Post subject: Re: InvalidClassException After Upgrade To 3.2.2 GA
PostPosted: Thu May 03, 2007 4:08 pm 
Expert
Expert

Joined: Tue Jul 11, 2006 10:21 am
Posts: 457
Location: Columbus, Ohio
Kerstetter wrote:
Any thoughts on how to get around this problem? It seems that the nature of serialization has changed between these hibernate releases. I am pretty sure that my classes (outside of Hibernate) are backwards compatible, as I have unit tests that demonstrate this.


I think you need to brush up on the "nature of serialization". Serialization and the serialVersionUID's enforce version control. You change the version of the class, of course you cannot deserialize an old version into the new version. It would be utter chaos! Dogs and cats sleeping together, mass hysteria and all that. ;)

In short, you're stuck with 3.0.3 for now unless you want to deserialize everything using 3.0.3 and then reserialize in 3.2.2 (which sounds like a huge PITA). Even better, never rely on serialization for anything other than remoting operations, unless 1) you have total control over the classes involved (including contained Serializable objects) and 2) never, ever, plan to change them.

Backwards compatibility (at a method/field level) has nothing to do with serialization/deserialization operations. S/D operation are more fundamental than that.


Top
 Profile  
 
 Post subject:
PostPosted: Thu May 03, 2007 4:14 pm 
Regular
Regular

Joined: Wed Nov 17, 2004 11:49 am
Posts: 65
Location: Pittsburgh
Absolutely untrue. The entire purpose of the serialVersionUID and the Externalizable interface is to support backward-compatibility of java classes.

Basically, If I listened to your suggestion, I could *never* use serialization, since the classes that I have full control over and never intend to change amount to.. ZERO. Maybe I would have been better off *not* using Serialization, but that ship has sailed.


Top
 Profile  
 
 Post subject:
PostPosted: Thu May 03, 2007 4:41 pm 
Expert
Expert

Joined: Tue Jul 11, 2006 10:21 am
Posts: 457
Location: Columbus, Ohio
That would be true if the classes in question explicitly defined the suid, which they do not. It falls back to the hashcode, which, of course, changed between versions. Just as a for instance,

Code:
3.0.5 (I don't have 3.0.3 src) fields in AbstractPersistentCollection:
   private transient SessionImplementor session;
   private boolean initialized;
   private transient List additions;
   private CollectionSnapshot collectionSnapshot;
   private transient boolean directlyAccessible;
   private transient boolean initializing;
   private Object owner;

3.2.2 fields:
   private transient SessionImplementor session;
   private boolean initialized;
   private transient List operationQueue;
   private transient boolean directlyAccessible;
   private transient boolean initializing;
   private Object owner;
   private int cachedSize = -1;
   
   private String role;
   private Serializable key;
   // collections detect changes made via their public interface and mark
   // themselves as dirty as a performance optimization
   private boolean dirty;
   private Serializable storedSnapshot;

Now, adding (non-transient) fields changes the implied hashcode of the class. If you would like another option, do a serialver on the 3.0.3 classes, and then add the found suid to the 3.2.2 source code and recompile the hibernate jar.


Top
 Profile  
 
 Post subject:
PostPosted: Thu May 03, 2007 4:41 pm 
Beginner
Beginner

Joined: Thu Nov 11, 2004 12:18 pm
Posts: 37
Location: Baltimore, MD
Kerstetter is right. Part of the Serialization spec is to support versioning. Even the link you included has a section about the "Evolution of a serializable class"

Quote:
"... A compatible change results in the evolved class being able to deserialize objects serialized by the class of a prior release. ..."

Examples of compatible changes are the following:

* Add fields
* Change a field from static to non-static
* Change a field from transient to non-transient
* Add classes to the object tree

_________________
-Chris


Top
 Profile  
 
 Post subject:
PostPosted: Thu May 03, 2007 4:49 pm 
Expert
Expert

Joined: Tue Jul 11, 2006 10:21 am
Posts: 457
Location: Columbus, Ohio
Only if the suid is explicitly defined, neh?

All's I can see is that the suid changed between version of Hibernate, whether though incompatible class changes or class changes to any of the Serializable fields contained therein (and the Serializable fields in those classes, etc, ad infinitum).

Got to jump out of the office now, but I'll check in later from home, interesting discussion.


Top
 Profile  
 
 Post subject:
PostPosted: Thu May 03, 2007 6:22 pm 
Regular
Regular

Joined: Wed Nov 17, 2004 11:49 am
Posts: 65
Location: Pittsburgh
OK. I didn't check the source code to see if the serialVersionUID was explicitly defined, but should I have had too? Hibernate deals with persistent data, data that lasts a long time, certainly between JVMs and probably between releases of Hibernate (definitely so in my unfortunate case). Shouldn't it be handling this situation?

The problem is that my serialized objects have Hibernate proxies for my associations. One way to avoid the issue in the future might be to remove the proxies before serialization, but I am unsure of how to strip these out. I don't need the associations in this case.

I considered hacking the suid of AbstractPersistentCollection, but how many other classes would have to change, and have all of these classes even changed in a way that is backward-compatible?

That leaves me with some sort of conversion utility for the data in the database *OR* stuck on 3.0.3. I am not liking either of these last options.


Top
 Profile  
 
 Post subject:
PostPosted: Thu May 03, 2007 7:13 pm 
Expert
Expert

Joined: Tue Jul 11, 2006 10:21 am
Posts: 457
Location: Columbus, Ohio
Sorry man, but they do change the instance variables from time to time and that will affect the default suid generation. I looked and looked, but once the instance variables change, the default suid changes.

But I don't think it would be a complex hunk of code to load the classes with 3.0.3 and then translate them into something with no Hibernate classes and then reserialize. I understand your frustration in this matter, but nonetheless that is the only solution that I can think of. AFAIK, the Hibernate team in no way guarantees a suid contract for Hibernate classes, especially the proxies. Those classes do change between releases, after all.

Perhaps someone with more experience in stripping off the proxies can direct your efforts in that regard.

Good luck and good coding!


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 8 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.