4

古いJavaコードのオブジェクトがあり、シリアル化されたオブジェクトコードを変更しました。古いファイルと新しいファイルの両方を読み取れるようにしたい。次のようなことを行うには、readObjectに分岐ステートメントが必要です。

if (next object is int -- just poking, it might be an Object)
{
    // we know we are in version 1
} else {
    // read new version of object
}

それは可能ですか?

4

4 に答える 4

2
if (object instanceof Integer) {
  ... Do stuff
} else {
  ... Do other stuff
}

編集:私はこれを拡張する必要があると思います。を使用してオブジェクトタイプを確認できますが、やなどinstanceofのプリミティブを操作できるかどうかはわかりません。intchar

于 2012-05-22T14:49:55.547 に答える
1

これを行う最も簡単な方法は、古いメンバー変数を古いタイプで保持し、新しいタイプの新しいメンバー変数を追加することです。また、クラスのserialVersionUIDを同じに保つ必要があります。次に、readObject()実装は、古いデータを新しいデータに変換するために必要な操作を実行できます。

元のオブジェクト:

public class MyObject {
   private static final long serialVersionUID = 1234L;

   private int _someVal;
}

新しいバージョン:

public class MyObject {
   private static final long serialVersionUID = 1234L;

   private int _someVal;  //obsolete
   private String _newSomeVal;

    private void readObject(java.io.ObjectInputStream in)
      throws IOException, ClassNotFoundException
    {
      in.defaultReadObject();

      if(_someVal != 0) {
        // translate _someVal to _newSomeVal
      }
    }
}

ObjectStreamField[] serialPersistentFieldsカスタム、、ObjectInputStream.GetFieldおよびを使用することで、より複雑なオプションも利用できると思いますObjectOutputStream.PutField

于 2012-05-22T15:39:42.833 に答える
1

ObjectInputStreamさて、基本的に問題は、「次のフィールドがプリミティブかオブジェクトかをどのように確認できるか」です。そして私が見る限りの答えは次のとおりです:あなたはできません。

つまり、下位互換性を維持するために私が見ることができる最善の解決策は、元のバージョンからプリミティブを削除しないことです。役に立たない情報を保持すると、サイズが少し大きくなりますが、それ以外の場合は簡単です。

新しいフィールドを追加するには、次の2つの方法があります。

  1. 以前のメッセージ形式を同じに保ち、最後に新しいオブジェクトのみを追加します。これにより、メッセージサイズによって異なるバージョンを簡単に区別できます(より正確には、v1オブジェクトを取得するときにv2のデータを読み取るときにIOExceptionが発生します)。これははるかに単純で、一般的に好まれます。

  2. オブジェクトをv1からv2に変更してから、簡単なinstanceofチェックを行うことができます。プリミティブを追加したい場合は、それらのラッパーバージョンを保存することです(つまり、Integer他)。数バイト節約できますが、Javaのシリアル化プロトコルはそもそも効率的ではなかったので、実際にはそれは不必要に複雑です。

于 2012-05-22T15:40:58.763 に答える
0

ObjectInputStream適切なクラスのインスタンスをロードして作成します。

object = ois.readObject();

if (object instanceof YourNewShiny ){
    // new style object
} else if (object instanceof YourOldBusted ){
    // convert YourOldBusted to YourNewShiny
} else {
    throw new ToyOutOfPram();
}

新しいクラスがある場合、これはすべて素晴らしいことですが、互換性のない方法でクラスを変更したためObjectInputStream、古いバージョンのクラスを新しい形式に逆シリアル化できません。これが事実であるならば、あなたはかなり詰め込まれています。

オプション:

  • 変更を元に戻し、互換性のある方法で実行します。つまり、serialVersionIdを追加し、フィールドの順序を変更せず、新しいフィールドのみを追加し、null以外の制約を想定しないでください。
  • 古いバージョンのコードを使用して、シリアル化されたデータを読み取り、それを中間形式(xml、csvなど)に変換してから、このデータを新しいクラス定義にインポートしてシリアル化します。
  • を手動で再実装しObjectInputStreamて、クラスタイプを検出します(serialVersionIdを使用してタイプをスティッフィングできます)

最初のものだけが私には良い考えのように思えます。

于 2012-05-22T15:42:45.937 に答える