ホーム › シリアライズ・デシリアライズ › Ser-02
Ser-02: transient・serialVersionUID の役割
transient を使うと 特定のフィールドをシリアライズから除外できます。パスワードや秘密鍵など、 ファイルやネットワークに保存したくないセキュリティ情報に活用します。serialVersionUID は クラスのバージョン識別子で、クラス変更時の互換性を管理します。
いつ使うか
- パスワード・APIキー・セッションIDなど、永続化・送信すべきでないフィールドを除外するとき(transient)
- クラスにフィールドを追加・削除してもデシリアライズできるよう互換性を保ちたいとき(serialVersionUID)
- 計算で再現できる値(キャッシュ)はシリアライズを省略してサイズを削減したいとき(transient)
serialVersionUID の役割
| 状況 | 結果 |
|---|---|
| serialVersionUID を定義しない | コンパイラが自動生成。クラス変更で値が変わり、古いファイルを読むと InvalidClassException |
| serialVersionUID = 1L を定義 | クラスを変更しても同じ値が維持され、フィールド追加後も古いデータを読み込める |
| 互換性のない変更(フィールドの型変更など) | serialVersionUID が同じでも ClassCastException などの実行時エラーになる可能性あり |
サンプルコード
transient を付けたフィールドはシリアライズされず、デシリアライズ後は型のデフォルト値(参照型は null、int は 0 など)になります。パスワード・秘密鍵・セッションIDなどのセキュリティ情報は必ず transient にしましょう。static フィールドも同様にシリアライズされません。
よくあるミス・注意点
transient フィールドはデシリアライズ後 null(またはデフォルト値)になる
transient フィールドを持つオブジェクトを シリアライズ後にデシリアライズすると、そのフィールドは参照型ならnull、 int/long などプリミティブ型なら0、 boolean なら false になります。 デシリアライズ後に再設定が必要な場合はreadObject() メソッドをオーバーライドして初期化できます。
serialVersionUID を省略しても動作するが推奨されない
serialVersionUID を省略してもコンパイルは通ります。 しかしクラスにフィールドを1つ追加・削除するだけで自動生成される値が変わり、 古いシリアライズデータが読めなくなります。 長期保存するデータや複数システム間でやり取りするデータには必ず定義しましょう。
record には transient フィールドは書けない
Java 17 以降のrecord の コンポーネント(フィールド)にはtransient を付けられません。 record はすべてのコンポーネントがシリアライズされます。 特定フィールドを除外したい場合は通常の class に Externalizable を実装する方法(Ser-03 参照)か、 JSON など別のフォーマットへの変換を検討しましょう。
テストする観点
- transient フィールドが、デシリアライズ後に null になること(セキュリティ情報が漏洩しないこと)
- transient 以外のフィールドが、デシリアライズ後も元の値を保持していること
- 同じ serialVersionUID でクラスにフィールドを追加しても、旧データが読み込めること(境界値: フィールド追加・削除)
- 異なる serialVersionUID でシリアライズ・デシリアライズすると InvalidClassException がスローされること
- static フィールドが、デシリアライズ後にシリアライズ時の値ではなくクラスの現在の値になること