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


3.1 ObjectInputStream クラス

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

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 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 メソッドによって書き込まれたヘッダとバージョンを検査します。


: ObjectInputStream コンストラクタは、直列化ストリームヘッダの読み込みが完了するまでブロックされます。コードが ObjectInputStream の構築を待機しているときに、直列化ストリームに対して対応する ObjectOutputStream が作成されていない場合は、デッドロックが発生します。 ObjectInputStream コンストラクタは、ヘッダがそのストリームに書き込まれるまでブロックされ、ヘッダは、Object OutputStream コンストラクタが実行されるまでストリームに書き込まれないためです。この問題は、ObjectInpu tStream が構築される前に 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 がスローされます。このとき、停止を引き起こした例外が引数として指定されます。ストリームコンテキ ストは前に述べたようにリセットされます。

ストリームからフィールドおよびオブジェクトを読み込むには、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 のサブクラスによって非標準形式で記述されたクラス記述子が読み込むためのこのメソッドは、Ob jectInputStream のサブクラスによってオーバーライドされます。デフォルトでは、このメソッドは、「6.4 ストリーム形式の文法」で説明している形式に従ってクラス記述子を読み込みます。

resolveClass メソッドは、クラスが直列化復元されている間と、そのクラス記述子が読み込まれたあとで呼び出されま す。サブクラスは、このメソッドを拡張して、ObjectOutputStream の対応するサブクラスによって書き込まれたクラスの他の情報を読むことができます。このメソッドは、 与えられた名前と serialVersionUID を持つクラスを見つけ、返さなければなりません。デフォルトの実装では、このクラスは、クラスローダ を持つ readObject のもっとも近い呼び出し側のクラスローダを呼び出すことによって、見つけることができます。このクラ スが見つからないと、ClassNotFoundException が通常スローされます。JDKTM 1.1.6 より前のバージョンでは、resolveClass メソッドは、ストリーム内のクラス名と同じ、完全修飾クラス名を返す必要がありました。JDKTM 1.1.6 以降のバージョンでは、どのリリースでもパッケージの名前を変更できるようにするために、reso lveClass メソッドが返すのは、同じ基底クラス名と 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< /code> に private なデータを割り当てず、ファイナルの readObject メソッドは readObjectOverride メソッドを呼び出してから復帰することを示すフラグを設定します。ほかのすべての ObjectInputStream メソッドは、ファイナルではないので、サブクラスによって直接オーバーライドされます。



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