java - 什么可以在序列化和存储在 Jarfile 中时修改 SerialVersionUID?

标签 java serialization jar drools

我在序列化对象时遇到了一些问题(我正在使用 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?除了另一个虚拟机版本?


添加源代码: 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;
}

最佳答案

serialVersionUID 不会改变。它是在编译时分配的 static final(我认为基于源代码的哈希),除非在源代码中明确分配了一个值。

这里有更多关于它的信息 http://mindprod.com/jgloss/serialization.html .

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

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

源代码发布后继续

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

来自 JavaDoc:

An InputStreamReader is a bridge from byte streams to character streams: It reads bytes and decodes them into characters using a specified charset. The charset that it uses may be specified by name or may be given explicitly, or the platform's default charset may be accepted.

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

关于java - 什么可以在序列化和存储在 Jarfile 中时修改 SerialVersionUID?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1092255/

相关文章:

java - Java 中的不变参数

java - 使用 Jacoco 的离线工具进行多模块 Maven 项目,使用 Surefire 覆盖率

ruby - 如何反转 Hash.inspect 或 Array.inspect? (又名 .to_s)在 Ruby 中

java - 我应该如何在 Spring MVC 中创建 Groovy Controller

java - 关于Java中的正则表达式(很简单,但我不知道为什么它不起作用

c# - RavenDB 自定义序列化器和反序列化器

c# - 关闭/忽略 xsd 代码生成中指定的字段后缀

java - 如何从 JAR 中获取文件引用

java - 使用不同的 jar 运行?

java - 在 jdk 9 中打包为 jar 时出现没有 module-info.class 错误的 --module-version 或 --hash-dependencies 之一