Reputation: 121
InvalidClassException: local class incompatible: stream classdesc serialVersionUID = -196410440475012755, local class serialVersionUID = -6675950253085108747
I struct with the InvalidClassException in the following scenario. Here my EAR is installed in 4 Websphere App servers and execution is shared among this. Sometimes I got the exception InvalidClassException from POJO class, Which is implements Serializable interface. Please any clue on this. I don't have any clue regarding to this.
Upvotes: 12
Views: 55646
Reputation: 346
When an object is serialized, the serialVersionUID is serialized along with the other contents.
Later when that is deserialized, the serialVersionUID from the deserialized object is extracted and compared with the serialVersionUID of the loaded class.
If the numbers do not match then, InvalidClassException is thrown.
Upvotes: 1
Reputation: 5648
Ok, so as asked I will give an example and my piece:
Here is a list and performance metrics for various forms of serialization of PoJos
You will have to judge trade offs of performance and convenience. But, since I said 'JSON' as a means of serialization then here is a trivial example that will not be compiler dependent. Basically, unless you changed the structure of your pojo on the receiving end it is completely irrelevant when/how/where you compile it (in fact, it doesn't even have to be between 2 JVMs). As you can see from the link, JSON is actually amongst the slowest and XML is just a payload pig. But both of them have the decisive advantage of being universally supported. XML even allows for the application of style sheets.
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.3.1</version>
<scope>test</scope>
</dependency>
Code
@Test
public void testJSON() throws Exception {
Foo expected = new Foo(1,"Christian",1000000.00d);
Gson gson = new GsonBuilder().setPrettyPrinting().create();
String testJson = gson.toJson(expected);
System.out.println(testJson);
Foo result = gson.fromJson(testJson, Foo.class);
assertEquals(expected,result);
}
public static class Foo {
private String name;
private Integer age;
private Double paycheck;
public Foo(Integer age, String name, Double paycheck) {
this.age = age;
this.name = name;
this.paycheck = paycheck;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Foo foo = (Foo) o;
if (age != null ? !age.equals(foo.age) : foo.age != null) return false;
if (name != null ? !name.equals(foo.name) : foo.name != null) return false;
if (paycheck != null ? !paycheck.equals(foo.paycheck) : foo.paycheck != null) return false;
return true;
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + (age != null ? age.hashCode() : 0);
result = 31 * result + (paycheck != null ? paycheck.hashCode() : 0);
return result;
}
}
Output
{
"name": "Christian",
"age": 1,
"paycheck": 1000000.0
}
Upvotes: 0
Reputation: 21
If somebody comes over this issue again in relation to the EJB TimerTask - like I just did - here is a hint if you're using WebSphere Application Server:
There are 2 batch files / shell scripts in the profile's bin folder, which can list and delete the EJB timer tasks. In my case, I had some timer tasks which serialized objects with a different, outdated serialVersionUID. I was't able to get rid of them, since the serialized objects really changed. So I just used those:
findEJBTimers.bat cancelEJBTimers.bat
Your timer tasks are gone then and so are the error messages. In my case that was exactly what I needed, but it was hard to get this infos.
Upvotes: 2
Reputation: 4272
When you implement java.io.Serializable interface to make a class serializable, the compiler looks for a static, final field named "serialVersionUID" of type long. If the class doesn't have this field declared explicitly then the compiler will create one such field and assign it with a value which comes out of a implementation dependent computation of serialVersionUID. This computation depends upon various aspects of the class and it follows the Object Serialization Specifications given by Sun. But, the value is not guaranteed to be the same across all compiler implementations.
This value is used for checking the compatibility of the classes with respect to serialization and this is done while de-serializing a saved object. The Serialization Runtime verifies that the serialVersionUID of the sender class (which was used for saving the state of the object on the stream) and that of the receiver class (the class which is being used to restore the object, possibly at some other system) both are exactly same. If the receiver system has loaded the class having some other serialVersionUID than that of the class used while serialization process then we get an InvalidClassException.
NOTE-- It's highly recommended that you explicitly declare and initialize the static, final field of type long and named 'serialVersionUID' in all your classes you want to make Serializable instead of relying on the default computation of the value for this field. This computation is extremely sensitive and may vary from one compiler implementation to another and hence you may turn up getting the InvalidClassException even for the same class just because you used different compiler implementations on the sender and the receiver ends of the serialization process.
In most of the cases you would be using 'private' access specifier only for this field as the declaration normally applies only to the class declaring it and we don't really need to either inherit this field in the subclasses OR to access it from outside. So, there is hardly any reason why we shouldn't keep it 'private'.
Upvotes: 40
Reputation: 308249
You get that exception when you try to deserialize an object that was serialized with an incompatible (usually earlier) version of the same class.
If you don't explicitly specify a serialVersionUID
in your class implementing Serializable
, then a value will be generated based on the (non-transient
) fields of your class. This is done to ensure that no partial objects are restored (it's better to fail than to blindly continue with a probably-broken object).
In web-application systems, a common use of serialization is for the session: if you put a value into the session, it's likely that it will be serialized eventually (for clustering support or simply to get persistent sessions).
So either keep all your classes compatible between versions or ensure that not restoring them does not break your application (i.e. don't store important information this way).
Upvotes: 9