3

オブジェクトのシリアル化中にいくつかの問題に直面しています (JBoss Drools を使用しており、KnowledgePackage の ArrayList を保存したいと考えています)。

リストをシリアル化し、結果をファイルに保存し、逆シリアル化すると、問題は発生しないので問題なく動作します。

しかし、リストをシリアル化し、結果をバイトストリームに保存してから、JarFile に保存すると、このエラーのために結果を逆シリアル化できません:

IOException during package import : java.util.ArrayList; local class incompatible: stream classdesc serialVersionUID = 8664875232659988799, local class serialVersionUID = 8683452581122892189

したがって、シリアル化されたオブジェクトを Jarfile エントリに保存するときに問題があると思います。Jarfileに同じ方法で保存された他のファイルを正しく読み取ることができるので、私はこれを正しく行っていると思います。そして、「cmp」と「hexdump」を使用した後、jar に保存すると、uuid の場合は 1 オクテットの変動が生じ、それ以外の場合は内容が同じであることがわかりました。

私は本当にがっかりしており、問題がどこにあるのかを述べることができません.

2 つのクラス間で SerialVersionUID を変更できるものは何ですか? 別の vm バージョン以外の ?


ソースコードの追加: exportToJar -> writeRulesPackageEntry -> writeEntry

/**
 * Writes content provided from a reader into a file contained in a jar.
 * 
 * @param output the output stream to write on
 * @param entryName the name of the file that will contain reader data
 * @param contentReader 
 * 
 * @return the zip entry that has been created into the jar
 */
ZipEntry writeEntry(JarOutputStream output, String entryName, ByteArrayInputStream input) {
    if (output == null || entryName == null || entryName.trim().length() == 0 || input == null) {
        throw new NullPointerException("Null argument passed");
    }

    ZipEntry entry = new ZipEntry(entryName);
    byte[] buffer = new byte[BUFFER_LENGTH];

    try {
        output.putNextEntry(entry);
        int nRead;

        while ((nRead = input.read(buffer, 0, BUFFER_LENGTH)) > 0) {
            output.write(buffer, 0, nRead);
        }

        output.closeEntry();
    } catch (IOException e) {
        e.printStackTrace();
    }

    return entry;
}

/**
 * Export rules files to a serialized object (ArrayList<KnowledgePackage>) into 
 * an output stream, then write the output content as an entry of a jar.
 * 
 * @param os the output jar to write in
 */
void writeRulesPackageEntry(JarOutputStream os) {
    // serialize objects and write them to the output stream
    ByteArrayOutputStream output = new ByteArrayOutputStream();
    RulesPackaging rulesPackaging = new RulesPackaging();
    rulesPackaging.exportResources(this.rules, output);

    // create a new input stream to read written objects from
    ByteArrayInputStream input = new ByteArrayInputStream(output.toByteArray());
    this.writeEntry(os, Product.ENTRY_RULES_PACKAGE, input);
}

/**
 * Creates a JarFile containing resources. 
 * 
 * @param filename the exported jar filename
 * @return the jar as an object, null if an error occured
 */
public JarFile exportToJar(String filename) {
    FileOutputStream fOs;
    JarOutputStream jOs;
    JarFile jar = null;

    try {
        fOs = new FileOutputStream(filename);
        jOs = new JarOutputStream(fOs);

        this.writeRulesPackageEntry(jOs);

        jOs.close();

        // construct a jar from the output jar
        jar = new JarFile(new File(filename));
    } catch (IOException e) {
        e.printStackTrace();
    }

    return jar;
}
4

3 に答える 3

3

serialVersionUID変わらない。ソースコードで値が明示的に割り当てられていない限り、コンパイル時にstatic final割り当てられます(ソースコードのハッシュに基づいていると思います)。

これについては、 http://mindprod.com/jgloss/serialization.htmlでもう少し詳しく説明しています。

例外を除いて、java.util.ArrayList の正しいserialVersionUID値は 8683452581122892189L です。これはソース コードで明示的に割り当てられており、クラスが 1.2 で導入されて以来同じままです。

あなたが言ったように、JarFile へのバイト ストリーム時にエラーが発生する可能性が最も高いです。それを行うために使用しているコードを投稿してください。

ソースコード掲載後の続き

問題はの使用にあると思いますjava.io.InputStreamReader

JavaDoc から:

InputStreamReader は、バイト ストリームから文字ストリームへのブリッジです。指定された文字セットを使用して、バイトを読み取り、文字にデコードします。使用する文字セットは、名前で指定するか、明示的に指定するか、プラットフォームのデフォルトの文字セットを受け入れることができます。

テキスト以外のストリームに文字セットが含まれているのを見るとすぐに、デコード中にストリームが変更される可能性があるため、常に疑わしくなります。これは、一連のバイトが文字セット内の文字に対応していないためです (これらの小さな四角が表示されます)。エンコーディングの問題が発生したときに発生する文字)。in でjava.io.ByteArrayInputStreamラップしているバイトを直接読み取ってみます。への変換は必要ありません。java.io.InputStreamReaderwriteRulesPackageEntry(JarOutputStream)char[]

于 2009-07-07T13:35:03.553 に答える
0

以前のバージョンがJarFileにシリアル化され、その後のシリアル化の試行で上書きに失敗する可能性はありますか?次に、以前のバージョンのクラスのシリアル化されたデータを取得することになります。これにより、(正しく)「互換性のない」エラーがスローされます。

私が尋ねる理由は、シリアル化されたクラスを更新したが、古い永続キャッシュを削除していないときに、選択したキャッシュシステム(EHCache)を使用して同様のエラーメッセージが表示されるためです。

于 2009-07-07T15:38:49.377 に答える
0

Nickが提案しているように、問題は、ストリームをバイト(変更されることはない)としてではなく、文字(変更される可能性がある)として扱っている可能性が高いです。

そうは言っても、シリアル化に関するもう1つの適切なリソースは、私が100万年前(1997年)に書いた本「MasteringJavaBeans」の専用の章です。幸いなことに、第11章のシリアル化は、当時と同じように今日でも関連性があります。http://ccd.uab.es/~srobles/manuals/JavaBeansから無料のPDFをダウンロードします

于 2009-07-07T15:19:28.973 に答える