「内部クラス(inner class)とは、明示的にも暗黙的にも static 宣言されていない入れ子クラスのことである」[JLS 2005]。内部クラス(ローカルあるいは匿名クラスを含む)をシリアライズすると間違いを犯しやすい。シリアライズに関する仕様には次のように記載されている[Sun 2006]。
- staticではないコンテキストで宣言された内部クラスは外部クラスへの transient 宣言されていない暗黙の参照を持っているため、そのような内部クラスをシリアライズすると、対応する外部クラスのインスタンスもシリアライズしてしまう。
- 内部クラスを実装するために Java コンパイラによって生成される合成フィールド(synthetic field)は実装に依存するため、コンパイラによって相違が生じることがある。この相違によって互換性が損われる可能性があり、また、デフォルトの serialVersionUID の値が衝突する危険もある。ローカルクラスや匿名の内部クラスにつけられる名前も実装に依存するため、コンパイラによって相違が生じる可能性がある。
- 内部クラスでは、コンパイル時に定数とならないフィールドを static 宣言できないので、 serialPersistentFields の仕組みを使ってシリアライズ可能なフィールドを指定することができない。
- 外部クラスのインスタンスに関連付けられた内部クラスは、引数なしのコンストラクタを持たないため、Externalizable を実装することはできない(そのような内部クラスのコンストラクタはそのクラスを囲むインスタンスを暗黙的に付加引数として受け取るため)。Externalizable インタフェースを実装するオブジェクトには、writeExternal() メソッドと readExternal() メソッドを使って状態の保存と復元を行うことが要求される。
したがって、内部クラスをシリアライズしてはならない。
static 宣言されたメンバクラスにはこのような問題はないため、シリアライズしてもよい。
違反コード
以下の違反コード例では、内部クラスをシリアライズするときに外部クラスに含まれているフィールドも一緒にシリアライズされてしまう。
public class OuterSer implements Serializable { private int rank; class InnerSer implements Serializable { protected String name; //... } }
適合コード
以下の適合コードでは、InnerSer クラスは Serializable を意図的に実装していない。
public class OuterSer implements Serializable { private int rank; class InnerSer { protected String name; //... } }
適合コード
メンバクラスを static 宣言することで、(それを囲むクラスをシリアライズするときに一緒に)シリアライズされることを防ぐことができる。また、static 宣言したメンバクラス自身が Serializable を実装することもできる。
public class OuterSer implements Serializable { private int rank; static class InnerSer implements Serializable { protected String name; //... } }
リスク評価
内部クラスをシリアライズ可能にすると、プラットフォーム依存なコードになる可能性がある。また、内部クラスをシリアライズすると、外部クラスのインスタンスも一緒にシリアライズされることがある。
ルール | 深刻度 | 可能性 | 修正コスト | 優先度 | レベル |
---|---|---|---|---|---|
SER05-J | 中 | 高 | 中 | P12 | L1 |
自動検出
Serializable を実装した内部クラスの検出は容易である。
関連ガイドライン
MITRE CWE | CWE-499, "Serializable Class Containing Sensitive Data" |
参考文献
[API 2006] | Interface Externalizable |
Interface Serializable | |
[Bloch 2008] | Item 74: "Implement serialization judiciously" |
[JLS 2005] | Section 8.1.3, Inner Classes and Enclosing Instances |
[Sun 2006] | "Serialization specification", Section 1.10 The Serializable Interface |
翻訳元
これは以下のページを翻訳したものです。
SER05-J. Do not serialize instances of inner classes (revision 63)