web-dev-qa-db-ja.com

java.io.InvalidClassException:ローカルクラスの非互換性:

クライアントとサーバーを作成し、シリアル化のためにクライアント側にクラスを追加し、ハードドライブのクライアントのフォルダーに移動して、サーバーに対応する場所にコピーペーストします。両方ともclassname.classおよびclassname.Javaそれぞれ。

自分のラップトップではうまく機能しましたが、他のシステムで作業を続けたい場合、プロジェクトフォルダーを開いたときに、クライアントがサーバーに接続しようとすると、次のエラーが表示されます。

Exception in thread "main" Java.io.InvalidClassException: projectname.clasname; local class incompatible: stream classdesc serialVersionUID = -6009442170907349114, local class serialVersionUID = 6529685098267757690
    at Java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.Java:562)
    at Java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.Java:1582)
    at Java.io.ObjectInputStream.readClassDesc(ObjectInputStream.Java:1495)
    at Java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.Java:1731)
    at Java.io.ObjectInputStream.readObject0(ObjectInputStream.Java:1328)
    at Java.io.ObjectInputStream.readObject(ObjectInputStream.Java:350)

何が起こっている?古いバージョンのIDEでプログラムを実行したためですか?

編集

import Java.io.Serializable;
import Java.net.URL;

public class KeyAdr implements Serializable {
  private static final long serialVersionUID = 6529685098267757690L;

  public URL adr;
  public String key;
}
24
lonesome

クラスがコードでprivate static final long serialVersionUIDを明示的に定義しない場合、クラスは自動生成され、異なるマシンが同じIDを生成する保証はありません。それがまさに起こったことのように見えます。また、クラスが何らかの方法で異なる場合(クラスの異なるバージョンを使用)、自動生成されたserialVersionUIDsも異なります。

Serializableインターフェイスの docs から:

シリアライズ可能クラスがserialVersionUIDを明示的に宣言しない場合、シリアライゼーションランタイムは、Java(TM)Object Serialization Specificationで説明されているように、クラスのさまざまな側面に基づいて、そのクラスのデフォルトserialVersionUID値を計算します。ただし、デフォルトのserialVersionUID計算は、コンパイラーの実装によって異なる可能性のあるクラスの詳細に非常に敏感であり、したがって、逆シリアル化中に予期しないserialVersionUID値になるため、すべてのシリアライズ可能クラスが明示的にInvalidClassExceptions値を宣言することは強く推奨です。したがって、異なるJavaコンパイラー実装間で一貫したserialVersionUID値を保証するには、シリアライズ可能なクラスが明示的なserialVersionUID値を宣言する必要があります。また、明示的なserialVersionUID宣言は可能な限りprivate修飾子を使用することを強くお勧めしますこのような宣言は、すぐに宣言するクラスにのみ適用されます-serialVersionUIDフィールドは継承されたメンバーとしては有用ではありません。配列クラスは明示的なserialVersionUIDを宣言できないため、常にデフォルトの計算値を持ちますが、配列クラスではserialVersionUID値と一致する必要はありません。

クラス定義でserialVersionUIDを定義する必要があります。例:

class MyClass implements Serializable {
    private static final long serialVersionUID = 6529685098267757690L;
    ...
41
trutheality

起こりうることの1つ:

  • 1:指定されたライブラリA(バージョンX)でシリアル化されたデータを作成します
  • 2:次に、同じライブラリA(ただしバージョンY)でこのデータを読み取ろうとします

したがって、バージョンXのコンパイル時に、JVMは最初のシリアルID(バージョンX用)を生成し、他のバージョンY(別のシリアルID)と同じことを行います。

プログラムがデータを逆シリアル化しようとすると、2つのクラスが同じシリアルIDを持たず、2つのシリアル化されたオブジェクトが同じクラス形式に対応することをプログラムが保証しないため、できません。

その間にコンストラクタを変更したと仮定すると、これはあなたにとって理にかなっているはずです。

2
belka

例外メッセージは、クラスメタデータも含むクラスバージョンが時間とともに変化したことを明確に示しています。つまり、シリアル化中のクラス構造は、逆シリアル化中と同じではありません。これがおそらく「進行中」です。

これは、クライアントとサーバーで同じクラスの異なるバージョンを使用しているために発生すると考えています。異なるデータフィールドまたはメソッドにすることができます

0
Mark Bramnik

Oc4jを使用してearを展開している場合。

プロジェクトにdeploy.home =の正しいパスを設定してください。

Common.propertiesファイルでdeploy.homeを見つけることができます

Oc4jは、サーバークラスとクライアントクラスが同じserialVersionUIDを持つように、耳に新しく作成されたクラスをリロードする必要があります

0
Mr Big

Javaでのシリアル化は、長期の永続性またはトランスポート形式を意味するものではありません。これには脆弱すぎます。タスクのJSONデータバインディング( XStream は高速で使いやすく、多数の代替手段があります)

0