2016-09-08 8 views
2

私は、ドキュメントストアであるJavaアプリケーションを作成しています。私は自分のオブジェクトを作成し、シリアル化してディスクに保存します。Javaオブジェクトの保存と取得のベストプラクティスは何ですか?

ディスクからオブジェクトをロードしているときにエラーが発生しましたが、実際にはシリアル化していたベースオブジェクトが変更されました。

これはオブジェクトの格納を管理するための悪い方法のようです。基本オブジェクトの変更でソフトウェアを更新すると、ディスク上のすべてのオブジェクトが無効になります。

この問題を扱う際の指針またはベストプラクティスはありますか?それとも、私のデータを保存する良い方法がありますか?

+0

これは、保存するデータの種類とアクセス方法によって異なります。 https://en.wikipedia.org/wiki/Object-relational_mapping –

+0

JSON、XML、カスタムファイル形式、データベースなどを見てみたいかもしれません。あなたは選択肢があります。 –

答えて

3

あなたはJava Object Serialization Specification、特にCompatible Java Type Evolutionセクションとすぐに次のセクションで、シリアル化に影響を与えるタイプの変更を読むことをお勧めします。

セクション1.10状態:シリアライズ可能なオブジェクトの場合

、十分な情報は、クラスの実装の異なる(しかし互換性のある)バージョンが存在する場合でも、これらのオブジェクトを復元するために維持されます。

開発者は、クラスの変更が以前のシリアル化されたバージョンと競合しないようにする責任があります。あなたが思うほど難しいことではありません。ほとんどの場合、回避する必要がありますincompatible changes

  • フィールドを削除しないでください。使用されなくなった場合は、deprecateです。これは、インスタンスフィールドをstaticフィールドにすることを含み、静的フィールドはシリアル化されないため、シリアル化に関してはこれを削除するのと同じです。
  • フィールドのタイプを変更しないでください。

あなたのクラスにvoid writeObject(ObjectOutputStream)メソッドを追加することによって、追加のデータを保存することができ、あなたはvoid readObject(ObjectInputStream)メソッドを追加することによって、追加の初期化を実行することができます。これらは、documentation for Serializableに詳細に説明されています。これらのメソッドのコードの最初の行はそれぞれstream.defaultWriteObject()stream.defaultReadObject()であることに注意してください。

readObjectは、フィールドを初期化する場合は、クラスにフィールドを追加するときに重要です。たとえば、あなたは常にnull以外になりたい新しいフィールドがある場合:完全にその場で解除 - つまり、それはなり直列化復元され、そのフィールドなく本シリアル化された

private List<String> names = new ArrayList<>(); 

どれでも古いインスタンスを(明示的に初期化されていない限り、オブジェクトが作成されたときにすべてのオブジェクトフィールドがnullになるため)nullのままです。あなたはこのことを考慮するreadObjectを使用することができます。

private void readObject(ObjectInputStream stream) 
throws IOException, 
     ClassNotFoundException { 

    // First, do default serialization 
    stream.defaultReadObject(); 

    if (this.names == null) { 
     this.names = new ArrayList<>(); 
    } 
} 
0

あなたはXMLを使用しようとすることができますが、JDOMは、あなたのオプションがあり、あなたのストレージ要件に応じて、JAVA

2

にXMLおよびXMLにJAVAを解析するために、あなたに簡単なツールを提供しますが、これらに限定されない(最も難しい最も簡単に私の意見で) :

  • 埋め込みデータベースを使用し、それらのファイルを代わりにディスクに保存します。選択肢はたくさんあります。 Derby、HSQL、H2、Sqliteなどがあります。したがって、Flywayのような移行ツールを使用できるという利点があります。スキーマが変更されるたびに、スクリプトを作成し、アプリケーションの起動時にツールを実行するようにします。実際には非常に簡単ですが、これまでのことをすべて知っているわけではありません。あなたはここでも多くの柔軟性を持っています。

  • JSONまたはXMLにシリアル化します。繰り返しますが、たくさんのツールを選択できますが、一般的なJSONシリアル化の場合はJacksonをお勧めします。 JSONはuglified(1行にスペースを入れずに入れてください)して、ディスクスペースを少なくします。作業は非常に簡単ですが、柔軟性は低くなります。たとえば、クラスにフィールドを追加するだけでは、大したことは気にする必要はありませんが、階層を変更したり、より小さなクラスを抽出したりする瞬間があります。それであなたはあなた自身である。あなたはデータを移行する方法を考える必要があり、圧倒される可能性があります。

  • 前述のオプションと非常によく似ていますが、Avroのようなディスク効率の良いソリューションを使用できます。これには既に言及した欠点がすべてあります。

  • あなた自身で思いつくものは何でも。私はこれを行うことをお勧めしません。チャンスは、あなたがしばらくの間あなたの解決策に喜んでいることでしょう。より多くのコードをサポートしなければならず、効率とパフォーマンス(必要な場合)と多くの課題が必然的に発生します。やってはいけません。

1

おそらくあなたがオブジェクトにフィールド「バージョン」を格納する必要があります。

オブジェクトをシリアル化する場合:このフィールドには、最初のバージョンでは「1」などの特定の値を設定します。

シリアル化形式を変更する場合は、バージョン番号を増やします。

オブジェクトのシリアル化を解除するときは、バージョン番号を読み、このバージョンの予想される形式でシリアル化解除します。保存したバージョン以降にフィールドを追加した場合、このフィールドは正しく処理されます。フィールドを削除した場合は無視してください。

以前のすべてのバージョンのオブジェクトをシリアル化解除するには、ソースコードの機能を維持する必要があります。

protobufまたはgsonなどのライブラリを使用して、一部のフィールドで構成された書式を特定のバージョン番号で記述し、予想されるフィールドを自動的に処理することもできます。

関連する問題