aspose file tools*
The moose likes Java in General and the fly likes Deserialization problem - InvalidClass w/ negative serialVersionUid for local class Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Java » Java in General
Bookmark "Deserialization problem - InvalidClass w/ negative serialVersionUid for local class" Watch "Deserialization problem - InvalidClass w/ negative serialVersionUid for local class" New topic
Author

Deserialization problem - InvalidClass w/ negative serialVersionUid for local class

Robert Edmonston
Greenhorn

Joined: Aug 08, 2003
Posts: 11
In my application, I am making a query remotely through an EJB and attempting to deserialize the result. When this happens I get an InvalidClassException:
java.rmi.UnmarshalException: failed to unmarshal cookie; nested exception is: java.io.InvalidClassException: com.govolution.transactionengine.transaction.event.FinancialTransactionEventSupport; local class incompatible: stream classdesc serialVersionUID = 1684827760387770896, local class serialVersionUID = -7862461873359489309
I have checked the class file using the serialVer utility and it says that the serialVersionUid of the class file being used by the client ClassLoader matches the one being used by the EJB. My question is - what could be happening here? Is there any significance that the serialVersionUid is a negative number on the local class? I even inspected the local ClassLoader at the time of the exception and found that the class being loaded was in fact the one I expected and there wasn't an extra outdated version in the classpath somewhere. Any advice, debugging tips, etc is appreciated!
John Smith
Ranch Hand

Joined: Oct 08, 2001
Posts: 2937
Has your class changed recently (new methods/data member, changed signatures)? Do you explicitely declare the field named serialVersionUID? Do you use a default or a custom implementation of the Serializable?
Robert Edmonston
Greenhorn

Joined: Aug 08, 2003
Posts: 11
Originally posted by Eugene Kononov:
Has your class changed recently (new methods/data member, changed signatures)? Do you explicitely declare the field named serialVersionUID? Do you use a default or a custom implementation of the Serializable?


The class hasn't changed recently. We are not explicitly declaring the serialVersionUID. We are using the default implementation of Serializable. I think I (almost) figured out the problem though. We have our app deployed on WLS 7. I have one jar file containing some ejbs and a war file containging my web app which uses these EJBs. Inside the war file, however, I have all the classes from the EJB module under the WEB-INF/ classes (this is the way the build was set up when I got here recently). This appears to be a bad idea according to what I am reading in the WL documentation due to the fact that they are loaded by sibling class loaders which can apparently lead to these types of exceptions (I am still not sure exactly why though). Here is the documentation from BEA that makes me think this is the problem:
"Although you could deploy the WAR and JAR files separately, deploying them together in an EAR file produces a classloader arrangement that allows the servlets and JSPs to find the EJB classes. If you deploy the WAR and JAR files separately, WebLogic Server creates sibling classloaders for them. This means that you must include the EJB home and remote interfaces in the WAR file, and WebLogic Server must use the RMI stub and skeleton classes for EJB calls, just as it does when EJB clients and implementation classes are in different JVMs."
"RMI call optimization and call by reference can only be used when the caller and callee are within the same application. As usual, this is related to classloaders. Since applications have their own classloader hierarchy, any application class has a definition in both classloaders and receives a ClassCastException error if you try to assign between applications. To work around this, WebLogic Server uses call by value between applications, even if they are within the same JVM."
"Applications usually have shared utility classes. If you create or acquire utility classes that you will use in more than one application, you must package them with each application as separate JAR files. The JAR files should be self contained and not have any references to the classes in the EJB or Web components. Common types of shared utility classes are data transfer objects or JavaBeans, which are passed between the Web tier and EJB tier."
If someone can explain to me exactly why having these EJB classes in both modules causes the InvalidClassException and the mismatched serialVersionUIDs even though both of the class files are identical - that would be very informative.
Robert Edmonston
Greenhorn

Joined: Aug 08, 2003
Posts: 11
I believe I have really determined the cause of the problem this time. Eclipse's internal compiler, while compliant with JDK 1.4, creates class files of a slightly smaller size and a different generated serialVersionUID than those created by the javac 1.4.1_03 HotSpot compiler. When running my app in Eclipse the classes generated by Eclipse where being loaded by the client WebApp's ClassLoader while the EJB's ClassLoader was using an EJB jar to obtain it's classes that had been built using javac in J2SE 1.4.1_03. This resulted in the IncompatibleClassError when the results were deserialized. When I placed the Eclipse-compiled classes in the Weblogic System Classpath, both the EJB and the Web App were using the same verision of the class that had been loaded by the parent ClassLoader and so everything worked. Lesson learned - be careful using Eclipse for development/compilation if you aren't specifically setting the serialVersionUID on your Serializable classes - even though it says JDK 1.4 compliant - there are differences in the class files generated.
This guy seemed to have a similar problem using WSAD which I believe Eclipse is based off of:
http://groups.google.com/groups?th=56e06838540e2da1
John Smith
Ranch Hand

Joined: Oct 08, 2001
Posts: 2937
Eclipse's internal compiler, while compliant with JDK 1.4, creates class files of a slightly smaller size and a different generated serialVersionUID than those created by the javac 1.4.1_03 HotSpot compiler.
Hmm, apparently Eclipse does more than just compacting the classes. I don't believe that the algorithm that calculates the value of serialVersionUID takes the class file size into consideration. Perhaps Eclipse monkeys around with the method signatures, in a some sort of optimization attempt?
Robert Edmonston
Greenhorn

Joined: Aug 08, 2003
Posts: 11
I found the source of the difference. Running javap on both class files, I found that the JDK has an extra method not present on the eclipse version. It is a static method with default access.
static java.lang.Class class$(java.lang.String);
This method is not present on the output of javap in the eclipse version. From what I have read from the site below and observerd in the source code of com.sun.corba.se.internal.orbutil.ObjectStreamClassUtil_1_3 this causes a different serialVersionUID to be generated:
"The following will NOT change the value of serialVersionUID for a class:
* Changing the order of declaration of interfaces a class implements
* Changing the order of declaration of methods and variables
* Adding or removing private transient and private static fields
* Adding or removing private methods
Any other changes in the class data that is used to compute the digest, as mentioned above, will change the value of serialVersionUID."
http://www.geocities.com/SiliconValley/Campus/1628/jstuff/serialver/serialver.html
Any ideas why the Sun compiler adds this extra method?
[ September 11, 2003: Message edited by: Robert Edmonston ]
Maulin Vasavada
Ranch Hand

Joined: Nov 04, 2001
Posts: 1871
hi Robert,
I read the problem initially when you posted. I couldn't think of possible reason but as you mention the problem you diognized seems correct. Now, my take would be following from this excesise,
1. Generate .class file ONLY ONCE and transfer them wherever you needed to avoid compiler dependencies
2. Try to use serialVersionUID variable in your code manually w/o depending upon default mechanism to calculate
Also, can you explain why you needed to 're-generate' .class file on the server? Couldn't you just copy the class files to the server when you moved server code over to EJBs...? (Please consider the fact while coming back that I have not developed EJBs or any J2EE apps so far )
Regards
Maulin
John Smith
Ranch Hand

Joined: Oct 08, 2001
Posts: 2937
I found the source of the difference. Running javap on both class files, I found that the JDK has an extra method not present on the eclipse version. It is a static method with default access.
Ah, that explains your deserialization problem perfectly. Now, does your serializable class have any inner classes?
Robert Edmonston
Greenhorn

Joined: Aug 08, 2003
Posts: 11
Originally posted by Eugene Kononov:
Ah, that explains your deserialization problem perfectly. Now, does your serializable class have any inner classes?

No - no inner classes in there. Why would this be relevant?
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: Deserialization problem - InvalidClass w/ negative serialVersionUid for local class