35

実行時にシリアル化プロセスからクラスフィールドを除外する方法は? コンパイル時間には一時的な修飾子がありますが、ランタイムはどうですか? gson などではなく、ObjectOutputStream を使用した一般的な Java シリアル化を意味します。

申し訳ありませんが、私は正しく説明していないと思います。これは正確にはシリアライゼーションではなく、シリアライゼーションに関するものです。レガシーファイルのバッチがあり、次のように処理します。

public class Deserialize {

/**
 * @param args
 * @throws IOException 
 * @throws ClassNotFoundException 
 */
public static void main(String[] args) throws ClassNotFoundException, IOException {
    File file = new File("/home/developer/workspace/DDFS/some.ddf");
    HackedObjectInputStream in = new HackedObjectInputStream(new GZIPInputStream(new FileInputStream(file)));

    System.out.println("Attempt to open " + file.getAbsolutePath());
    Object obj = in.readObject();
    in.close();


}

 static class HackedObjectInputStream extends ObjectInputStream
    {

        /**
         * Migration table. Holds old to new classes representation.
         */
        private static final Map<String, Class<?>> MIGRATION_MAP = new HashMap<String, Class<?>>();

        static
        {
            MIGRATION_MAP.put("DBOBExit", Exit.class);
        }

        /**
         * Constructor.
         * @param stream input stream
         * @throws IOException if io error
         */
        public HackedObjectInputStream(final InputStream stream) throws IOException
        {
            super(stream);
        }

        @Override
        protected ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException
        {
            ObjectStreamClass resultClassDescriptor = super.readClassDescriptor();

            for (final String oldName : MIGRATION_MAP.keySet())
            {
                if (resultClassDescriptor.getName().equals(oldName))
                {
                    resultClassDescriptor = ObjectStreamClass.lookup(MIGRATION_MAP.get(oldName));   
                }
            }

            return resultClassDescriptor;
        }

    }

}

このコードはほとんどのファイルで正常に機能しますが、一部のファイルでスローされます

Exception in thread "main" java.lang.ClassCastException: cannot assign instance of java.awt.Polygon to field Exit.msgbackPt of type java.awt.Point in instance of Exit
at java.io.ObjectStreamClass$FieldReflector.setObjFieldValues(ObjectStreamClass.java:2053)

Exit クラスのバージョンが異なるためです。新しいバージョンには新しいフィールドがあります。新しいフィールドにトランジェントを追加するとエラーが消えますが、別のファイルが例外をスローし始めます (最新のファイル)。

従来のシリアル化されたファイルを検出した場合、実行時にこれらの新しいフィールドに一時的なものを追加できますか? 多分反射か何か?

4

4 に答える 4

60

ObjectOutputStreamのドキュメントには次のように書かれています。

オブジェクトのデフォルトのシリアライゼーション メカニズムは、オブジェクトのクラス、クラス シグネチャ、すべての非一時的および非静的フィールドの値を書き込みます。他のオブジェクトへの参照 (一時フィールドまたは静的フィールドを除く) により、それらのオブジェクトも書き込まれます。

そのため、変数を一時的として宣言すると、ObjectOutputStream によって無視されます。注釈transientではなくキーワードを使用していることを確認してください。@Transientこのような注釈は、データベースに保存されるべきではないフィールドをマークするために、一部の ORM フレームワークで使用されます。これらはビルトインのシリアライゼーション フレームワークでは意味がありません。

private transient String foo; // Field gets ignored by ObjectOutputStream
@Transient private String bar; // Treated normally by ObjectOutputStream (might mean something for some other framework)
于 2013-01-29T12:09:39.303 に答える
3

transient修飾子を使用できます:

http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.3.1.3

于 2013-01-30T01:12:50.483 に答える
0

特定のクラスのシリアル化された表現は、クラス自体次第です。外部から変更することはできません。取得できる最も近いものは、カスタムのシリアル化動作を持つサブクラスを定義することですが、親のオブジェクトではなく、そのサブクラスのオブジェクトにのみ影響しますタイプ。

問題のクラスをまったく変更できない場合、唯一のオプションは ObjectOutputStream をサブクラス化し、オーバーライドreplaceObjectして、書き込み時に問題のオブジェクトを必要なデータのみを含む別のオブジェクトに置き換え、読み取り時にミラー イメージ プロセスを実行することです。 (サブクラス ObjectInputStream および override resolveObject)。

于 2013-01-29T12:11:18.533 に答える
0

ここで間違った穴を掘っています。どのフィールドをシリアライズしてオーバーライドするかについて実行時の決定をいじる代わりに、オーバーライドreadClassDescriptor()を検討する必要がありますreadResolve()

于 2013-01-30T00:50:30.773 に答える