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' 之后,我发现如果 uuid 将其保存在 jar 中会导致一个八位字节的变化,否则内容是相同的。

我真的很失望,无法说明问题可能出在哪里。

什么可以修改两个类之间的 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

除了您看到serialVersionUIDjava.util.ArrayList 的正确值是 8683452581122892189L 之外,它是在源代码中显式分配的,并且自 1.2 中引入该类以来一直保持不变。

正如您所说,错误最有可能发生在字节流到 JarFile 时 - 请发布您用来执行此操作的代码。

源代码发布后继续

我怀疑问题出在使用java.io.InputStreamReader.

来自 JavaDoc:

InputStreamReader 是从字节流到字符流的桥梁:它读取字节并使用指定的字符集将它们解码为字符。它使用的字符集可以由名称指定,也可以显式给出,或者可以接受平台的默认字符集。

一旦我看到非文本流中涉及的字符集,我总是会怀疑,因为在解码过程中可能会修改流是字节序列与字符集中的字符不对应(看到那些小方块发生编码问题时出现的字符)。我会尝试直接读取java.io.ByteArrayInputStream你用java.io.InputStreamReaderin包装的字节writeRulesPackageEntry(JarOutputStream)char[]不需要转换为 a 。

于 2009-07-07T13:35:03.553 回答
0

就像尼克建议的那样,问题很可能是您没有将流视为字节(永远不会改变),而是视为字符(可以)。

Having said that, another decent resource on Serialization is a dedicated chapter from a book I wrote a million years ago (1997), "Mastering JavaBeans". Luckily chapter 11, Serialization, is as relevant today as it was then. Download the free PDFs from http://ccd.uab.es/~srobles/manuals/JavaBeans

于 2009-07-07T15:19:28.973 回答
0

Is there any chance that an earlier version was serialized into the JarFile, and subsequent serialization attempts are failing to overwrite it? Then you'd be retrieving the serialized data of an earlier version of the class, which would (correctly) throw the "incompatible" error.

The reason I ask, is that I've seen similar error messages using my caching system of choice (EHCache) when I've updated a serialized class yet haven't dropped the old persistent cache.

于 2009-07-07T15:38:49.377 回答