在序列化对象时遇到一些问题(我正在使用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;
}
解决方法:
serialVersionUID不变.除非在源代码中显式分配值,否则它是在编译时分配的静态最终值(我认为是基于源代码的哈希值).
这里有更多关于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.
一旦我看到非文本流中涉及的字符集,我总是会感到怀疑,因为在解码过程中有可能在字节序列与字符集中的字符不对应的情况下修改流(见那些小方块).发生编码问题时出现的字符).我会尝试直接从writeRulesPackageEntry(JarOutputStream)中的java.io.InputStreamReader包装的java.io.ByteArrayInputStream读取字节.不必转换为char [].