Java

直列化の変更と拡張
J2SETM 1.4

ドキュメントの目次
ここでは、Java 2 プラットフォームのバージョン 1.4 の直列化機能について説明します。 以前のリリースで拡張された機能についての概要は「以前のリリースでの拡張機能」を参照してください。
非共有オブジェクトの直列化復元のサポート
データ直列化ストリームで非共有オブジェクトの直列化復元も、直列化でサポートするようになりました。 この新しいサポートは、パッケージ java.io に次のような API を追加することにより提供されます。
ObjectInputStream.readUnshared()

ObjectOutputStream.writeUnshared(Object obj)

ObjectStreamField(String name, Class type, boolean unshared)

以前は、セキュリティを重視するプログラマは、非公開内部オブジェクトの直列化復元を行なったあと、それらを複製する必要がありました。これは、直列化ストリームへのアクセス権を持つ外部パーティが、機密オブジェクトに偽のバックハンドルを付加することにより、直列化復元中に外部からの参照が可能になることを避けるためです。 ただし、このようにするとパフォーマンスが低下しメモリを浪費します。つまり、単一の使用可能なオブジェクトへの一意の参照を確保するために、オブジェクトを 2 つ作成し、複製操作を呼び出す必要があります。 新しく追加された API ではより効率的な解決法が提供されています。受信側で非共有オブジェクトを読み取って無効にし、サードパーティが以後のストリームで発生するオブジェクトのバックハンドルを間接参照できないようにします。

putFields、readFields のオーバーライドに必要なセキュリティアクセス権
J2SE 1.4.0 から、ObjectOutputStream.putFields または ObjectOutputStream.writeUnshared をオーバーライドするサブクラスで ObjectOutputStream の引数を 1 つ取る public のコンストラクタを直接的または間接的に呼び出す場合、"enableSubclassImplementation" SerializablePermission が必要になりました。

同様に、J2SE 1.4.0 から、ObjectInputStream.putFields または ObjectInputStream.writeUnshared をオーバーライドするサブクラスで ObjectInputStream の public one-argument constructor を直接的または間接的に呼び出す場合にも、"enableSubclassImplementation" SerializablePermission が必要になりました。

このような変更は、アプリケーションの大部分には影響がありません。 ただし、putFields または readFields メソッドをオーバーライドするが直列化インフラストラクチャの残りの部分はオーバーライドしない ObjectInputStream サブクラスや ObjectOutputStream サブクラスは影響を受けます。

クラス定義メソッド readObjectNoData のサポート
クラス定義メソッドの writeObject()readObject() のほかにも、直列化によってクラス定義メソッドの readObjectNoData() がサポートされます。 それぞれのクラス定義メソッド readObjectNoData() には、次のシグニチャーが必要です。
private void readObjectNoData() throws ObjectStreamException;
readObjectNoData() はクラス定義メソッド readObject() と似ています。ただし、定義されている場合は、直列化復元中のオブジェクトのスーパークラスのクラス記述子およびそのクラス記述子で記述されるオブジェクトデータが、直列化ストリームにない場合に呼び出されるという点が異なります。 つまり、以下のとおりです。
クラス C のオブジェクト O が直列化復元中で、O を直列化復元している VM 内の C のスーパークラスが S である場合、O の直列復元中に ObjectInputStream によって S.readObjectNoData() が呼び出されるのは、次の条件が成立する場合だけです。
  1. S が java.io.Serializable を直接的または間接的に実装する
  2. S が前述のシグニチャーを使って readObjectNoData() メソッドを定義する
  3. O を含む直列化ストリームが、C のスーパークラス記述子のリストに S のクラス記述子を含まない
クラス定義メソッド readObject() の呼び出しが可能な場合は、readObjectNoData() が呼び出されることはありません。ただし、直列化可能クラスの実装を行う際に、初期化コードをまとめる手段として、readObject() から readObjectNoData() を呼び出すことができます。

詳細は、ObjectInputStream の API 仕様でクラス記述子を参照してください。

バグの修正: プリミティブ型の Class オブジェクトの直列化復元エラー
以前のリリースでは、プリミティブ型の Class オブジェクトの直列化復元をしようとすると ClassNotFoundException エラーになりました (バグ 4171142)。 これは、プリミティブ型の ObjectStreamClass 記述子には ObjectInputStream.resolveClass() を使用できないためです。J2SE 1.4.0 ではこのバグは修正されました。

バグの修正: public 以外のインタフェースで ObjectInputStream.resolveProxyClass がエラーになることがある
以前のリリースでは、1 つまたは複数のプロキシインタフェースが public でない場合、ObjectInputStream.resolveProxyClass はプロキシクラスを定義するクラスローダを正しく選択するとは限りませんでした。 このリリースでは、ObjectInputStream.resolveProxyClass が public 以外のインタフェースを検出すると、実装するプロキシクラスをインタフェースと同じクラスローダに定義しようとし、競合する場合は例外をスローします。これは、プロキシがインタフェースを実装するために必要です。

バグの修正: 無効な serialPersistentFields のフィールド名による NullPointerException の発生
以前のリリースでは、デフォルトの直列化を使用するが実際のクラスフィールドにマップされていない serialPersistentField エントリを宣言するオブジェクトを直列化すると、NullPointerExceptions がスローされました (バグ 4387368)。 このリリースでは、そのような場合、直列化は InvalidClassExceptions をスローします。デフォルトの直列化を使用するのであれば、そのような「サポートされない」serialPersistentFields を定義する必要はないからです。

バグの修正: スキップされたオブジェクトでの ClassNotFoundException による直列化エラー
以前のリリースでは、「スキップされた」オブジェクト (直列化復元パーティによってロードされたクラスにないフィールドに関連付けられたオブジェクト) により ClassNotFoundExceptions が発生すると、オブジェクトグラフ全体の直列化復元エラーとなりました。これは、スキップされた値がグラフに含まれていない場合も同様でした。 今回のリリースの直列化では、このようなスキップされたオブジェクトに関連付けられた ClassNotFoundExceptions を無視し、不要な直列化復元エラーのクラスを排除することで問題に対処しています。 直列化復元中に発生する ClassNotFoundExceptions に関連して、直列化全体を堅牢にするための変更がこのほかにも行われています。

Copyright © 2001 Sun Microsystems, Inc.All Rights Reserved.
コメントの送付先:rmi-comments@java.sun.com
Sun