serialVersionUIDを理解する
Serializableインターフェースを実装したことがある場合は、この警告メッセージが表示される必要があります。
The serializable class xxx does not declare a static final serialVersionUID field of type long
だから…serialVersionUIDとは何ですか?
serialVersionUIDは、Serializableクラスのバージョン管理として使用されます。 serialVersionUIDを明示的に宣言しない場合、Java™ Object Serialization Specificationで説明されているように、JVMはSerializableクラスのさまざまな側面に基づいて自動的に宣言します。
1. SerialVersionUIDの例
上記のステートメントは、最初は理解するのが少し難しいです(少なくとも私はそうでした)。SerializableクラスがSerialVersionUIDを使用してバージョン管理を実装する方法を理解するための例を始めましょう。
1.1 Address.java
1LのserialVersionUIDを持つシリアル化可能なクラス。
import java.io.Serializable;
public class Address implements Serializable{
private static final long serialVersionUID = 1L;
String street;
String country;
public void setStreet(String street){
this.street = street;
}
public void setCountry(String country){
this.country = country;
}
public String getStreet(){
return this.street;
}
public String getCountry(){
return this.country;
}
@Override
public String toString() {
return new StringBuffer(" Street : ")
.append(this.street)
.append(" Country : ")
.append(this.country).toString();
}
}
1.2 WriteObject.java
Addressオブジェクトをファイル「c:\ address.ser」に書き込む/シリアル化するための単純なクラス。
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
public class WriteObject{
public static void main (String args[]) {
Address address = new Address();
address.setStreet("wall street");
address.setCountry("united states");
try{
FileOutputStream fout = new FileOutputStream("c:\\address.ser");
ObjectOutputStream oos = new ObjectOutputStream(fout);
oos.writeObject(address);
oos.close();
System.out.println("Done");
}catch(Exception ex){
ex.printStackTrace();
}
}
}
1.3 ReadObject.java
ファイルからAddressオブジェクトを読み取り/逆シリアル化するための単純なクラス–「c:\ address.ser」。
import java.io.FileInputStream;
import java.io.ObjectInputStream;
public class ReadObject{
public static void main (String args[]) {
Address address;
try{
FileInputStream fin = new FileInputStream("c:\\address.ser");
ObjectInputStream ois = new ObjectInputStream(fin);
address = (Address) ois.readObject();
ois.close();
System.out.println(address);
}catch(Exception ex){
ex.printStackTrace();
}
}
}
2. テスト
いくつかのテストを行って、serialVersionUIDの使用を実証します。
2.1 Same serialVersionUID
同じserialVersionUID、逆シリアル化プロセス中に問題はありません
javac Address.java javac WriteObject.java javac ReadObject.java java WriteObject java ReadObject Street : wall street Country : united states
2.2 Different serialVersionUID
Address.javaで、change the serialVersionUID to 2L(1L)を作成し、再度コンパイルします。
javac Address.java
java ReadObject
java.io.InvalidClassException: Address; local class incompatible:
stream classdesc serialVersionUID = 1, local class serialVersionUID = 2
...
at ReadObject.main(ReadObject.java:14)
serialVersionUID “1L”を使用してシリアル化クラスを記述し、更新されたシリアル化クラスserialVersionUID “2L”を使用してそれを取得しようとするため、「InvalidClassException」が発生します。
serialVersionUIDは、シリアル化および逆シリアル化プロセス中に一致する必要があります。
When should update your serialVersionUID?
シリアル化クラスがシリアル化可能なクラスへの互換性のないJavaタイプの変更で更新された場合、serialVersionUIDを更新する必要があります。
シリアライズ可能なクラスへの互換性のあるJavaタイプの変更と互換性のないJavaタイプの変更の詳細については、Java Object Serialization Specification.を参照してください。
3. デフォルトのserialVersionUIDの何が問題になっていますか?
serialVersionUIDが宣言されていない場合、JVMは独自のアルゴリズムを使用してデフォルトのSerialVersionUIDを生成します。アルゴリズムhereを確認できます。
The default serialVersionUID computation is highly sensitive to class details and may vary from different JVM implementationであり、逆シリアル化プロセス中に予期しないInvalidClassExceptionsが発生します。
3.1 Client / Server environment
–クライアントはWindowsでSUNのJVMを使用しています。
–サーバーはLinuxでJRockitを使用しています。
クライアントは、デフォルトで生成されたserialVersionUID(例:123L)のシリアル化可能なクラスをソケット経由でサーバーに送信します。サーバーは、逆シリアル化プロセス中に異なるserialVersionUID(例:124L)を生成し、予期しないInvalidClassExceptionsを発生させます。
3.2 File / Database environment
–アプリ#1はWindowsでSUNのJVMを使用しています。
–アプリ#2はLinuxでJRockitを使用しています。
シリアル化により、ファイルまたはデータベースに保存できます。 アプリ#1はデフォルトで生成されたserialVersionUID(例:123L)によってシリアル化可能なクラスをデータベースに保存しますが、アプリ#2はデシリアライズプロセス中に異なるserialVersionUID(例:124L)を生成し、予期しないInvalidClassExceptionsを発生させます。
ここでList of the JVM implementationを確認できます。
4. serialVersionUIDを生成する方法
JDK“serialver”またはEclipse IDEを使用して、serialVersionUID、see detailを自動的に生成できます。
結論
SUNは、上記のさまざまなJVMの問題を回避するために、serialVersionUIDを宣言することを強くお勧めしますが、シリアル化とは何か、serialVersionUIDがバージョン管理を実装する方法、およびクラスがシリアル化を使用する必要がある理由を理解することをお勧めします。 serialVersionUIDの概念を理解することは、推奨事項を目隠しすることよりも優れています。
参考文献
-
http://java.sun.com/javase/6/docs/platform/serialization/spec/class.html#4100
-
http://stackoverflow.com/questions/419796/explicit-serialversionuid-considered-harmful
-
http://www.javaworld.com/javaworld/jw-02-2006/jw-0227-control.html?page=1
-
http://www.java-forums.org/new-java/8196-serialversionuid.html