I have old binary data serialized and stored in a db with an old class 'mypackage.Myclass'
I would like to refactor this class to 'mypackage.topic.Myclass' and still able to read the binary data back (deserialization)
I get an error Classnotfound when :
ois = new ObjectInputStream(bos);
o = ois.readObject();
mypackage.topic.Myclass myclass = (mypackage.topic.Myclass) o;
Is there a way to force readObject() to match another class then the original serialized class ? Or any otherhint doing this ?
You can solve this by creating a data wrapper class called mypackage.Myclass. When deserializing the binary data, you can first try to deserialize it as mypackage.topic.Myclass. When this fails, deserialize it as mypackage.Myclass and convert it afterwards to the class mypackage.topic.Myclass.
You can also set the serialVersionUID of the mypackage.topic.Myclass to the serialVersionUID of the mypackage.Myclass. If you don't know the serialVersionUID of the class mypackage.Myclass, or if you doesn't have set the serialVersionUID, you can generate the serialVersionUID, which is probably used/automatically created by the JVM using this command: serialver -classpath whatever com.foo.bar.MyClass (See: Java - Modifying serialVersionUID of binary serialized object)
When the classes have the same serialVersionUID, there will be no error when you deserialize the class.
Related
I'm trying to pick up Java and wanted to test around with Java's client/server to make the client send a simple object of a self defined class(Message) over to the server. The problem was that I kept getting a ClassNotFoundException on the server side.
I think the rest of the codes seem to be alright because other objects such as String can go through without problems.
I had two different netbeans projects in different locations for client and server each.
Each of them have their own copy of Message class under their respective packages.
Message class implements Serializable.
On the client side, I attempt to send a Message object through.
On the server side, upon calling the readObject method, it seems to be finding Message class from the client's package instead of it's own. printStackTrace showed: "java.lang.ClassNotFoundException: client.Message" on the server side
I have not even tried to cast or store the object received yet. Is there something I left out?
The package name and classname must be exactly the same at the both sides. I.e. write once, compile once and then give the both sides the same copy. Don't have separate server.Message and client.Message classes, but a single shared.Message class or something like that.
If you can guarantee the same package/class name, but not always whenever it's exactly the same copy, then you need to add a serialVersionUID field with the same value to the class(es) in question.
package shared;
import java.io.Serializable;
public class Message implements Serializable {
private static final long serialVersionUID = 1L;
// ...
}
The reason is, that the readObject() in ObjectInputStream is practically implemented as:
String s = readClassName();
Class c = Class.forName(s); // Here your code breaks
Object o = c.newInstance();
...populate o...
I have a class like
class Stundent
{
private static final long serialVersionUID = 1L;
private int no;
private String name;
//setters and getters
}
And then i used the following code for serialization & deserialization
public class Serialization{
public static void main(String args[]) throws Exception {
File file = new File("out.ser");
FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos);
SerializeMe serializeMe = new SerializeMe(1);
oos.writeObject(serializeMe);
oos.close();
}
}
public class DeSerialization{
public static void main(String args[]) throws Exception {
File file = new File("out.ser");
FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);
SerializeMe dto = (SerializeMe) ois.readObject();
System.out.println("data : " + dto.getData());
ois.close();
}
}
After running the Serialization class i changed the serialiversionID to 2 and then i run the second program,then i got like
java.io.InvalidClassException:
SerializeMe; local class incompatible
That means whenever i am performing deserialization
serialversionID of Student class is checking.
My doubt is
1)Is it mandatory to have Student class at the time of deserialization ?
2)As per serialization definition, to transfer the java objects as stream of bytes through network we are performing serialization.So if an object is transferred through network ,how the Student class is available in other side.
For example in my application every entity(Hibernate entity) is
Serializable.
Because my web application exist in different server and my database
is in differentserver.That is the reason we have implemented
Serializable.In this case can u explain how serialization is working?
Thanks in advance...
When you deserialize a serialized object, the same class has to be present in order to construct an instance of that class.
The serialVersionUID is to tell whether the same version of the class is present in terms of the serialization process. If the class that is present has a different serialVersionUID value (compared to the value read from the binary data/stream of the serialized object), deserialization will be aborted by throwing an InvalidClassException.
1)Is it mandatory to have Student class at the time of deserialization?
Yes.
2)As per serialization definition, to transfer the java objects as stream of bytes through network we are performing serialization.So if an object is transferred through network ,how the Student class is available in other side.
You have to take care of that. You have to distribute the Student class prior to deserializing a serialized Student.
Deserialization can only happen if the same version (determined by the serialVersionUID value) exists of the serialized class. Serializing instances of the standard lib is not a problem, because those are present in all JRE's (although different versions might be present with different serialVersionUID fields!), so you can "transfer" such objects between different JRE's. If an instance of a custom class is transferred, the same class file must be made available at the destination prior to the deserialization process.
Edit:
You wrote that your "web application exists on different servers". Your web application includes your class files which implicitly means that the class files will be available on all servers. So a serialized object from one server can be deserialized on another.
As far as my understanding is concerned, usually when we transfer objects, it is the attribute values inside the Student object is what we are require.
The Student class should be present on the other side.
I had saved one java object in the Database and then after few days I changed my jre version.
Now when i tried to read that same object I am getting following exception:
Exception in thread "main" java.io.InvalidClassException:
SerializeMe; local class incompatible: stream classdesc
serialVersionUID = -6377573678240024862, local class serialVersionUID = -8204757486033751616
How can I get rid of this,how can I get the saved object?
please help me.
If you can affect source code of this class and JRE was only thing that changed, most likely you can still deserialize object that was serialized by older JVM. Just define following field in class to be deserialized:
private static final long serialVersionUID = -6377573678240024862L;
I am getting the following serialization error and I am trying to read my object that I saved to a file
java.io.InvalidClassException: com.testGame.scoreCard; Incompatible class (SUID): com.testGame.scoreCard: static final long serialVersionUID =-5895378336422852901L; but expected com.testGame.scoreCard: static final long serialVersionUID =0L;
at java.io.ObjectInputStream.verifyAndInit(ObjectInputStream.java:2376)
at java.io.ObjectInputStream.readNewClassDesc(ObjectInputStream.java:1658)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:683)
at java.io.ObjectInputStream.readNewObject(ObjectInputStream.java:1799)
at java.io.ObjectInputStream.readNonPrimitiveContent(ObjectInputStream.java:787)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:1999)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:1956)
But what I don't get is why scoreCard is serialized in the first place? The class(object) that I am writing and reading is serialized and does not call or make use of scoreCard class. Why would it complain about that class? Is there a way to see why this scoreCard is involved? ( I am using eclipse btw)
Thank you
Are you perhaps serializing an inner class of ScoreCard? They have secret references to the containing object.
Could it be that class that you are trying to restore depends indirectly on ScoreCard, through another class for example?
To see dependencies in Eclipse you can click on a class name or method name and press Ctrl+Shift+G, it will show you all the places where class or method is used.
Another way to discover dependencies is to click on a method name and press Ctrl+Alt+H, it will show you call graph that you can discover further.
I have compiled and jarred the various projects in my Java application, generating serialVersionUIDs automatically through Eclipse for all my classes derived from Serializable.
I read the answers to this question, and verified that serialVersionUids are all private static final long.
Nevertheless, I get an error like this when I try to run:
java.io.InvalidClassException: com.acme.product.Widget; local class
incompatible: stream classdesc serialVersionUID = 5226096973188250357, local
class serialVersionUID = -5432967318654384362
What am I missing?
You probably have a classpath issue, where your program is resolving an older incompatible version of the class which has a different value for serialVersionUID.
Or the serialized object that is being loaded, was serialized with an oder version of the class which is now unavailable.
If the class has changed since you serialized it, the change may be incompatible. Serialization can't deserialize it, even with the included serialVersionUID.
If you have the class as it was when serialized (e.g. from SCM), then try reverting back to that, regenerate the serialVersionUID and rerun.
If you have made incompatible changes, then you will have to implement readObject() /writeObject() to handle the serialization details yourself.
stream classdesc serialVersionUID =
5226096973188250357
What am I missing?
What you are missing is private static final long serialVersionUID = 5226096973188250357L;
However if the changed class is no longer serialization-compatible (see the Object Serialization Specification) you may now get more obscure errors.