【问题标题】:Error deserializing a BigDecimal反序列化 BigDecimal 时出错
【发布时间】:2018-05-17 09:06:36
【问题描述】:

当我尝试反序列化 java.math.BigDecimal 时出现以下错误:

java.io.InvalidClassException: java.math.BigDecimal; local class incompatible:
  stream classdesc serialVersionUID = 6108874887139371087,
  local class serialVersionUID      = 6108874887143696463

我知道如果你实现 Serializable 接口而不定义serialVersionUID,就会发生这个错误,但是我的类确实定义了它:

public class Foo implements java.io.Serializable {
    private static final long serialVersionUID = -2280646288949622888L;
    private int a;
    private long b;
    private java.lang.String c;
    private java.math.BigDecimal d;
}

此外,它还专门抱怨 BigDecimal,它是 JDK 的一部分,如果我信任 Eclipse 的反编译器,它还定义了 serialVersionUID

private static final long serialVersionUID = 6108874887143696463L;

我读过in some cases (such as using GWT),你可以有不同的 BigDecimal 类实现,具有不同的串行版本,这将避免正确的反序列化。它也可能发生在不同机器上具有相同类的不同版本。但就我而言,我在同一台机器上,在同一个 JBoss 实例中进行序列化和反序列化......

this similar question,估计我的序列化过程肯定有问题,但是想不通。这是我正在使用的代码:

static InputStream serialize(Foo[] array) throws IOException {
    ByteArrayOutputStream baos = null;
    ObjectOutputStream oos = null;
    try {
        baos = new ByteArrayOutputStream();
        oos = new ObjectOutputStream(baos);
        oos.writeObject(array);
        return new ByteArrayInputStream(baos.toByteArray());
    } finally {
        close(oos);
        close(baos);
    }
}

static Foo[] deserialize(InputStream is) throws IOException, ClassNotFoundException {
    ObjectInputStream ois = null;
    try {
        ois = new ObjectInputStream(is);
        return (Foo[]) ois.readObject();
    } finally {
        close(ois);
    }
}

编辑:我忘了提到数据在序列化后存储到磁盘,并在反序列化之前从那里读取。所以也许这就是它被破坏的地方。阅读我只使用new FileInputStream(file)。写,我用这个:

static void write(File file, InputStream is) throws IOException {
    FileWriter fw = null;
    InputStreamReader isr = null;
    try {
        fw = new FileWriter(file, true);
        isr = new InputStreamReader(is);
        char[] buffer = new char[8096];
        int bytesRead;
        while ((bytesRead = isr.read(buffer)) != -1) {
            fw.write(buffer, 0, bytesRead);
        }
    } finally {
        close(fw);
        close(isr);
    }
}

可能是因为我使用char[] 作为缓冲区,但输入流是从byte[] 生成的?这应该不是问题吧?

【问题讨论】:

  • byte[]char[] 的转换正是问题所在,请查看我的答案。切勿使用Writer 处理二进制数据。

标签: java serialization deserialization bigdecimal


【解决方案1】:

您的序列化数据在某处被错误地处理和损坏。

查看两个 serialVersionUID 值,很明显只有一个字节不同,这表明这不仅仅是类不匹配的情况。

您的信息流很可能已损坏。请注意,serialVersionUID 通常也“意外地”充当一种损坏检查,因为它是一个必须完全匹配的幻数。

十六进制的真实serialVersionUID是54C71557F981284F。您在信息流中拥有的是54C71557F93F284F。请注意,81 更改为 3F3F? 的 ASCII 码,它是 Java 中解码错误的默认替换字符。

这强烈表明您的数据在某些时候被错误地视为文本数据。由于正确数据中的值为81,因此用于错误“解码”数据的编码很可能是ISO-8859-1,它没有为该代码点分配任何内容。

tl;dr 在您将序列化数据转换为 String 并返回到 byte[] 的过程中,这是一个糟糕的想法,必须避免。将二进制数据视为二进制数据(使用byte[]InputStream/Outputstream)。避免使用任何处理文本数据的东西(即不要使用String,避免使用Reader/Writer)。

【讨论】:

  • 我在您发布此答案时更新了问题。我猜错误来自FileWriter,然后
  • 嗯,就是这样。我改变了我的文件写入方法like this,现在它可以工作了。我还比较了错误和正确的文件,不同之处恰好是一个? 字符,其中应该有一个空格。谢谢! :)
猜你喜欢
  • 2022-10-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多