目次 | 前の項目 | 次の項目 Java オブジェクト直列化仕様


3.1 ObjectInputStream クラス

クラス ObjectInputStream は、オブジェクトの直列化復元を実装するためのものです。このクラスは、すでに直列化復元されたオブジェクトセットなどのストリームの状態を管理します。このクラスのメソッドを使えば、ObjectOutputStream によって書き込まれたストリームから、プリミティブ型やオブジェクトを読み込むことができます。このクラスは、それが参照するオブジェクトをストリームから復元します。

package java.io;

public class ObjectInputStream
    extends InputStream
    implements ObjectInput, ObjectStreamConstants
{
    public ObjectInputStream(InputStream in)
        throws StreamCorruptedException, IOException;
    public final Object readObject()
        throws OptionalDataException, ClassNotFoundException,
            IOException;

    public Object readUnshared()
        throws OptionalDataException, ClassNotFoundException,
            IOException;

    public void defaultReadObject()
        throws IOException, ClassNotFoundException,
            NotActiveException;

    public GetField readFields()
        throws IOException;

    public synchronized void registerValidation(
        ObjectInputValidation obj, int prio)
        throws NotActiveException, InvalidObjectException;

    protected ObjectStreamClass readClassDescriptor()
        throws IOException, ClassNotFoundException;

    protected Class resolveClass(ObjectStreamClass v)
        throws IOException, ClassNotFoundException;

    protected Object resolveObject(Object obj)
        throws IOException;

    protected boolean enableResolveObject(boolean enable)
        throws SecurityException;

    protected void readStreamHeader()
        throws IOException, StreamCorruptedException;

    public int read() throws IOException;

    public int read(byte[] data, int offset, int length)
        throws IOException

    public int available() throws IOException;

    public void close() throws IOException;

    public boolean readBoolean() throws IOException;

    public byte readByte() throws IOException;

    public int readUnsignedByte() throws IOException;

    public short readShort() throws IOException;

    public int readUnsignedShort() throws IOException;

    public char readChar() throws IOException;

    public int readInt() throws IOException;

    public long readLong() throws IOException;

    public float readFloat() throws IOException;

    public double readDouble() throws IOException;

    public void readFully(byte[] data) throws IOException;

    public void readFully(byte[] data, int offset, int size)
        throws IOException;

    public int skipBytes(int len) throws IOException;

    public String readLine() throws IOException;

    public String readUTF() throws IOException;

    // Class to provide access to serializable fields.
    static abstract public class GetField
    {
        public ObjectStreamClass getObjectStreamClass();

        public boolean defaulted(String name)
            throws IOException, IllegalArgumentException;

        public char get(String name, char default)
            throws IOException, IllegalArgumentException;

        public boolean get(String name, boolean default)
            throws IOException, IllegalArgumentException;

        public byte get(String name, byte default)
            throws IOException, IllegalArgumentException;

        public short get(String name, short default)
            throws IOException, IllegalArgumentException;

        public int get(String name, int default)
            throws IOException, IllegalArgumentException;

        public long get(String name, long default)
            throws IOException, IllegalArgumentException;

        public float get(String name, float default)
            throws IOException, IllegalArgumentException;

        public double get(String name, double default)
            throws IOException, IllegalArgumentException;

        public Object get(String name, Object default)
            throws IOException, IllegalArgumentException;
    }

    protected ObjectInputStream()
        throws StreamCorruptedException, IOException;

    protected readObjectOverride()
        throws OptionalDataException, ClassNotFoundException,
            IOException;
}
単一引数の ObjectInputStream コンストラクタには InputStream が必要です。このコンストラクタは、readStreamHeader を呼び出して読み込み、対応する ObjectOutputStream.writeStreamHeader メソッドによって書き込まれたヘッダとバージョンを検査します。セキュリティマネージャがインストールされている場合、このコンストラクタは、readFields メソッドまたは readUnshared メソッド、あるいはその両方をオーバーライドするサブクラスのコンストラクタによって直接または間接的に呼び出されたときに、"enableSubclassImplementation" SerializablePermission のチェックを行います。


注 - ObjectInputStream コンストラクタは、直列化ストリームヘッダの読み込みが完了するまでブロックされます。コードが ObjectInputStream の構築を待機しているときに、直列化ストリームに対して対応する ObjectOutputStream が作成されていない場合は、デッドロックが発生します。ObjectInputStream コンストラクタは、ヘッダがそのストリームに書き込まれるまでブロックされ、ヘッダは ObjectOutputStream コンストラクタが実行されるまでストリームに書き込まれないためです。この問題は、ObjectInputStream が構築される前に ObjectOutputStream を作成するか、ObjectInputStream の構築の完了および ObjectOutputStream の作成の間のタイミング依存関係を解除すると解決できます。
ストリームからオブジェクトを直列化復元するには、readObject メソッドを使用します。このメソッドは、このストリームを読んで、オブジェクトを再構築します。

  1. ObjectInputStream サブクラスが実装をオーバーライドしている場合は、readObjectOverride メソッドを呼び出し、戻します。実装し直す方法については、この節の最後で説明します。
  2. ブロックデータレコードがストリームにあると、BlockDataException をスローし、使用可能なバイト数を知らせます。
  3. ストリームのオブジェクトが null であれば、null を返します。
  4. ストリームのオブジェクトが前のオブジェクトに対するハンドルであれば、そのオブジェクトを返します。
  5. ストリームのオブジェクトが Class であれば、その ObjectStreamClass 記述子を読み、それとそのハンドルを、認識されているオブジェクトセットに追加し、対応する Class オブジェクトを返します。
  6. ストリームのオブジェクトが ObjectStreamClass であれば、その名前と serialVersionUID とフィールドを読み、そのオブジェクトとそのハンドルを、認識されているオブジェクトセットに追加します。このストリームに対し resolveClass メソッドを呼び出して、この記述子のローカルクラスを入手し、そのクラスが見つからないときは例外をスローします。ObjectStreamClass オブジェクトを返します。
  7. ストリームのオブジェクトが文字列であれば、その文字列の UTF エンコーディングを読み、そのオブジェクトとそのハンドルを既知のオブジェクトセットに追加し、手順 11 に進みます。
  8. ストリームのオブジェクトが配列であれば、その ObjectStreamClass と配列の長さを読みます。その配列を割り当て、そのオブジェクトとそのハンドルを、認識されているオブジェクトセットに追加します。型に適したメソッドを使って各要素を読み込み、配列に割り当てます。手順 11 に進みます。
  9. その他のオブジェクトの場合は、そのオブジェクトの ObjectStreamClass がストリームから読み込まれます。その ObjectStreamClass のローカルクラスが取り出されます。このクラスは、直列化可能か外部化可能でなければなりません。
  10. そのクラスのインスタンスが割り当てられます。そのインスタンスとそのハンドルが、認識されているオブジェクトセットに追加されます。内容が適切に復元されます。
    1. Serializable オブジェクトの場合、最初の直列化不能なスーパータイプの引数なしのコンストラクタが実行されます。Serializable クラスの場合、フィールドは、その型に適したデフォルト値に初期化されます。次に、クラス固有の readObject メソッドか、これらが定義されていなければ、defaultReadObject メソッドが呼び出されて、各クラスのフィールドが復元されます。直列化復元時には、直列化可能クラスに対して、フィールドの初期化子およびコンストラクタは実行されません。通常、このストリームを書き込んだクラスのバージョンは、このストリームを読み込むクラスと同じです。この場合、ストリームのオブジェクトのすべてのスーパータイプは、現在ロードされているクラスのスーパータイプと一致します。このストリームを書き込んだクラスのバージョンのスーパータイプが、ロードされているクラスのスーパータイプと異なる場合は、ObjectInputStream で異なるクラスの状態を復元したり、初期化したりする際、いっそうの注意が必要です。この場合には、すべてのクラスを調べて、ストリームにあるデータと、復元するオブジェクトのクラスとを比較する必要があります。ストリームにはあるがオブジェクトにはないクラスのデータは破棄されます。オブジェクトにはあるがストリームにはないクラスの場合には、そのクラスのフィールドが、デフォルトの直列化によってデフォルト値に設定されます。
    2. 外部化可能なオブジェクトの場合、そのクラスの引数なしのコンストラクタが実行されてから readExternal メソッドが呼び出され、そのオブジェクトの内容が復元されます。
  11. オブジェクトのクラス、または ObjectInputStream のサブクラスによって、置換を処理します。
    1. オブジェクトのクラスが適切な readResolve メソッドを定義する場合は、そのメソッドが呼び出され、オブジェクトが自らの置換を行うことを可能にします。
    2. enableResolveObject によって resolveObject メソッドが使用可能にされていれば、resolveObject メソッドが呼び出されます。これによって、ストリームのサブクラスがオブジェクトを調べ、それを置き換えることができます。前の手順で元のオブジェクトを置き換えた場合は、置換オブジェクトで resolveObject メソッドが呼び出されます。
置換が行われた場合、認識されているオブジェクトのテーブルが更新されるので、置換オブジェクトがハンドルに関連付けられます。そのあと、置換オブジェクトが readObject から返されます。

プリミティブ型を読むためのすべてのメソッドは、ストリームのブロックデータレコードからバイトだけを使用します。ストリームの次のアイテムがオブジェクトのときにプリミティブデータの読み込みが行われると、読み込みメソッドは -1 か EOFException のうちで適切な方を返します。プリミティブ型の値は、DataInputStream によってブロックデータレコードから読み込まれます。

スローされた例外は、そのトラバースの間に起きたエラーか、基本のストリームで起きた例外を反映したものです。例外がスローされた場合、基本のストリームは不明で使用不能な状態のままです。

ストリームでリセットトークンが起こると、ストリームのすべての状態は破棄されます。認識されているオブジェクトセットはクリアされます。

ストリームで例外トークンが起こると、その例外が読み込まれ、新しい WriteAbortedException がスローされます。このとき、停止を引き起こした例外が引数として指定されます。ストリームコンテキストは前に述べたようにリセットされます。

ストリームから非共有オブジェクトを読み込むには、readUnshared メソッドを使用します。このメソッドは、後続の readObject および readUnshared の呼び出しが、元の readUnshared の呼び出しによって返された直列化復元インスタンスへの追加参照を返すことができない点を除いては、readObject と同じです。具体的には、次のようになります。

readUnshared を介してオブジェクトの直列化復元を行うと、返されたオブジェクトに関連付けられたストリームハンドルが無効になります。このこと自体は、readUnshared によって返された参照が一意であることを常に保証するものではありません。直列化復元されたオブジェクトは、readResolve メソッドを定義して、ほかの組織が見ることができるオブジェクトを返すことがあります。また、readUnshared が、ストリーム内のほかの場所や外部機関から取得可能な Class オブジェクトを返すこともあります。ただし、オブジェクトが java.lang.Class のインスタンスではなく、readResolve メソッドを定義しない場合は、readUnshared を使うことで、返されたオブジェクト参照が一意であること、および基になるデータストリームが処理済みであっても、それを作成した ObjectInputStream から再度取得されないことが保証されます。この保証は、readUnshared によって返される基本レベルのオブジェクトだけに適用され、返されたオブジェクトのグラフ内で一時的に参照されるサブオブジェクトには一切適用されません。

ストリームからフィールドおよびオブジェクトを読み込むには、defaultReadObject メソッドを使用します。このメソッドは、ストリームのクラス記述子を使って、名前と型による標準の順序でストリームからそれらのフィールドを読み込みます。それらの値は、名前によって現行クラスの対応するフィールドに代入されます。バージョン管理機構の詳細については、「5.5 互換性のある JavaTM の型展開」を参照してください。ストリーム内にないオブジェクトのフィールドは、そのデフォルト値に設定されます。ストリームにあるがオブジェクトにない値は、破棄されます。このような状態は主に、前のバージョンにはなかったフィールドを、クラスのあとのバージョンに追加で書き込んだ場合に起こります。このメソッドは、クラスのフィールドを復元している間に readObject メソッドからのみ呼び出すことができます。それ以外のときに呼び出すと、NotActiveException がスローされます。

readFields メソッドは、ストリームから直列化可能フィールドの値を読み取り、GetField クラスを使ってその値を使用できるようにします。readFields メソッドは、直列化可能クラスの readObject メソッド内からしか呼び出すことができません。また、このメソッドは、1 回しか呼び出すことができず、defaultReadObject がすでに呼び出されている場合は呼び出せません。GetFields オブジェクトは、現在のオブジェクトである ObjectStreamClass を使ってこのクラス用に取得できるフィールドを確認します。readFields によって返される GetFields オブジェクトは、そのクラスの readObject メソッドへの呼び出しの間だけ有効です。フィールドは、任意の順序で取得できます。追加データの読み込みは、readFields が呼び出されたあとに、ストリームから直接読み込む場合だけ可能です。

registerValidation メソッドを呼び出すと、オブジェクトが readObject の元の呼び出し側に返される前にグラフ全体が復元された場合に、コールバックを要求することができます。有効化コールバックの順序は、優先順次で制御することができます。高い値のコールバックは、低い値のものより前に呼び出されます。有効にされるオブジェクトは、ObjectInputValidation インタフェースをサポートし、validateObject メソッドを実装していなければなりません。有効化を登録するのは、クラスの readObject メソッドを呼び出す間でなければなりません。そうでないと、NotActiveException がスローされます。registerValidation に指定されたコールバックオブジェクトが null の場合、InvalidObjectException がスローされます。

JavaTM SDK, Standard Edition, v1.3 から、すべての ObjectStreamClass オブジェクトを読み込むときに readClassDescriptor メソッドが使用されています。直列化ストリーム内で ObjectInputStream の次の項目がクラス記述子の場合は、readClassDescriptor が呼び出されます。writeClassDescriptor メソッドをオーバーライドした ObjectOutputStream のサブクラスによって非標準形式で記述されたクラス記述子が読み込むためのこのメソッドは、ObjectInputStream のサブクラスによってオーバーライドされます。デフォルトでは、このメソッドは、「6.4 ストリーム形式の文法」で説明している形式に従ってクラス記述子を読み込みます。

resolveClass メソッドは、直列化復元されている間と、そのクラス記述子が読み込まれたあとで呼び出されます。サブクラスは、このメソッドを拡張して、ObjectOutputStream の対応するサブクラスによって書き込まれたクラスの他の情報を読むことができます。このメソッドは、与えられた名前と serialVersionUID を持つクラスを見つけ、返さなければなりません。デフォルトの実装では、このクラスは、クラスローダを持つ readObject のもっとも近い呼び出し側のクラスローダを呼び出すことによって、見つけることができます。このクラスが見つからないと、ClassNotFoundException がスローされます。JDKTM 1.1.6 より前のバージョンでは、resolveClass メソッドは、ストリーム内のクラス名と同じ、完全指定されたクラス名を返す必要がありました。JDK 1.1.6 以降のバージョンでは、リリースごとにパッケージの名前を変更できるようにするために、resolveClass メソッドは、同じ基底クラス名および SerialVersionUID を持つクラスを返すことだけが必要です。

resolveObject メソッドは、直列化復元の際に、あるオブジェクトを別のオブジェクトの代わりにモニターしたり、あるオブジェクトと別のオブジェクトを置換したりするために、信頼できるサブクラスによって使用されます。解釈処理する最初のオブジェクトに対して readObject を呼び出す前に、enableResolveObject を呼び出して、オブジェクトの解析処理を明示的に使用可能にしなければなりません。オブジェクトの解析処理を使用可能にすると、それぞれの直列化可能オブジェクトが readObject から最初に返される直前に、resolveObject は一度だけ呼び出されます。resolveObject メソッドは、特別に処理されるクラスである ClassObjectStreamClassString、および配列のオブジェクトに対しては呼び出されません。サブクラスの resolveObject の実装では、オリジナルの代わりに代入されたり返されたりする置換オブジェクトが返される場合があります。返されるオブジェクトは、一貫性があり、元のオブジェクトの参照に必ず代入できる型のものでなければなりません。そうでないと、ClassCastException が返されます。すべての代入では型の検査が行われます。ストリームにおける元のオブジェクトへのすべての参照は、置換オブジェクトへの参照によって置き換えられます。

enableResolveObject メソッドは、直列化復元の際に、あるオブジェクトを別のオブジェクトの代わりにモニターしたり、あるオブジェクトで別のオブジェクトを置換することを可能にするために、ObjectOutputStream の信頼できるサブクラスによって呼び出されます。オブジェクトの置換は、enableResolveObject が true 値で呼び出されるまでは、オフになっています。また、使用可能にしたあとで、false に設定して、使用不可にされる場合があります。前の設定が返されます。enableResolveObject メソッドは、直列化の際にストリームが置換を要求する権限があるかどうかを検査します。オブジェクトの private 状態が意図せずに変更されることのないように、信頼できるストリームだけしか resolveObject を使用することはできません。信頼できるクラスとは、クラスローダが null に等しいか、置換を有効にすることを許可するセキュリティ保護ドメインに属するクラスのことです。

ObjectInputStream のサブクラスがシステムドメインの一部でないとみなされる場合は、enableResolveObject を呼び出すための許可を ObjectInputStream のサブクラスに与える行を、セキュリティポリシーファイルに追加する必要があります。追加する SerializablePermission は、"enableSubstitution" です。ObjectStreamClass のサブクラスの保護ドメインに、enableResolveObject の呼び出しによる "enableSubstitution" の権限がない場合は、AccessControlException がスローされます。セキュリティモデルの詳細は、JavaTM セキュリティアーキテクチャ (JDKTM 1.2) のドキュメントを参照してください。

readStreamHeader メソッドは、ストリームのマジック番号とバージョンを読み込み、検査します。それらが一致しないと、StreamCorruptedMismatch がスローされます。

直列化復元の実装をオーバーライドするには、ObjectInputStream のサブクラスは、保護された引数なしの ObjectInputStream コンストラクタを呼び出す必要があります。SerializablePermission "enableSubclassImplementation" の引数なしのコンストラクタ内にはセキュリティチェックがあり、信頼できるクラスだけにデフォルトの実装のオーバーライドを許可します。このコンストラクタは、ObjectInputStream に private なデータを割り当てず、ファイナルの readObject メソッドは readObjectOverride メソッドを呼び出してから復帰することを示すフラグを設定します。ほかのすべての ObjectInputStream メソッドは、ファイナルではないので、サブクラスによって直接オーバーライドされます。



目次 | 前の項目 | 次の項目
Copyright © 1997-2001 Sun Microsystems, Inc. All Rights Reserved.