Java Serialize Versioning.
Control the java serialize versioning.
- Every Serializable class contains a serialVersionUID.
- This long value is calculated by default from the name and signature of the class and its data members and methods using Sercure Hash algorithm..
- For backward compatibility, you can specify your own public static final long serialVersionUID
-
Prior to modify the class, you can use serialver tool to find out the old version ID:
> serialver app.Rectangle
- It is importent to make sure the changes are both forward and backward compatible.
- Add, remove or modify the methods are normally compatiple, but you should consider the consequences of the change in your business logic.
- To add new data members are compatiple. This means that the new class has to deal with missing data for the new data members, as the old class will ignore unknown data members of the new object.
- Removing fields is incompatiple. (The old class could might trust on non-default values from the fields that are missing in new objects.)
- You may need to implement a customize handling using the readObject() methods to ensure compatibility.
- Or you may need to use a full serializable control implementing the java.io.Externalizable interface to ensure compatibility.
A java serialize versioning example using customize object reading:
First an old class, Rectangle, that is made serializable:
package app;
public class Rectangle implements java.io.Serializable {
private int length;
private int width;
public Rectangle () {}
public Rectangle(int width, int length) {
this.length=length;
this.width=width;
}
@Override
public String toString() {
return " width: " + width + " length: " + length;
}
public int getLength() {
return length;
}
public void setLength(int length) {
this.length = length;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
}
Here is a main class to write the serializable object of a old Rectangle to a file Rectangle.ser:
package app;
import java.io.*;
public class WriteObj {
public static void main(String args[]) {
Rectangle rect = new Rectangle(25, 60);
ObjectOutputStream out = null;
try {
out = new ObjectOutputStream(new FileOutputStream("Rectangle.ser"));
out.writeObject(rect);
System.out.println("Wrote Rectangle with \"" + rect + "\" to file");
}
catch (IOException e) {
System.err.println("Error writing object: " + e.getMessage());
}
finally {
try {
out.close();
}
catch (IOException e) {
System.err.println(e.getMessage());
}
}
}
}
Here's console printout:
Wrote Rectangle with " width: 25 length: 60" to file
Here is the hexadecimal representation of the Rectangle.ser file:
AC ED 00 05 73 72 00 0D 61 70 70 2E 52 65 63 74
61 6E 67 6C 65 87 2E CA DB 51 AA DE 4D 02 00 02
49 00 06 6C 65 6E 67 74 68 49 00 05 77 69 64 74
68 78 70 00 00 00 3C 00 00 00 19
Then we need a new java project that contain only these last two files are included (this is included in the above download).
In the new java project create a new class, Rectangle, that is made serializable:
package app;
import java.awt.Color;
import java.io.IOException;
import java.io.ObjectInputStream;
public class Rectangle implements java.io.Serializable {
// You can get the serialVersionUID from the old Rectangle class using
// serialver app.Rectangle where old class exists.
static final long serialVersionUID = -8705797986343788979L;
private int length;
private int width;
// color is the new member variable
private Color color;
public Rectangle () {}
public Rectangle(int width, int length, Color color) {
this.length=length;
this.width=width;
this.color=color;
}
// using readObject method to set default values
private void readObject(ObjectInputStream input)
throws IOException, ClassNotFoundException {
// deserialize the non-transient data members first;
input.defaultReadObject();
// Set a default Color
setColor(Color.blue);
}
@Override
public String toString() {
return " width: " + width + " length: " + length +" color: "+color;
}
public int getLength() {
return length;
}
public void setLength(int length) {
this.length = length;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color;
}
}
To do this, open a command window and find the path
where the app.Rectangle class exists to run:
> serialver app.Rectangle
Then we need a main class to read the serializable
object of a old Rectangle from the file Rectangle.ser:
package app;
import java.io.*;
public class ReadObj {
public static void main(String args[]) {
ObjectInputStream in = null;
try {
in = new ObjectInputStream(new FileInputStream("Rectangle.ser"));
Rectangle rect = (Rectangle) in.readObject();
System.out.println("Read Rectangle with:\n \"" + rect + "\" from file");
}
catch (ClassCastException e) {
System.err.println("Error casting object to a Rectangle");
}
catch (ClassNotFoundException e) {
System.err.println("Class not found");
}
catch (IOException e) {
System.err.println("Error reading object: " + e.getMessage());
}
finally {
try {
in.close();
}
catch (IOException e) {
System.err.println(e.getMessage());
}
}
}
}
We must then run this last project in NetBeans and the result should be:
Read Rectangle with:
" width: 25 length: 60 color: java.awt.Color[r=0,g=0,b=255]" from file.
© 2010 by Finnesand Data.
All rights reserved.
This site aims to provide FREE programming training and technics.
Finnesand Data as site owner gives no warranty for the
correctness in the pages or source codes.
The risk of using this web-site pages or any program
codes from this website is entirely at the individual user.