Ошибка десериализации BigDecimal - PullRequest
0 голосов
/ 17 мая 2018

При попытке десериализации файла 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, а также определяет serialVersionUID, если я доверяю декомпилятору Eclipse:

private static final long serialVersionUID = 6108874887143696463L;

Я читал, что в некоторых случаях (например, с использованием GWT) , у вас могут быть разные реализации класса BigDecimal с разными последовательными версиями, которые могут избежать правильной десериализации. Это также может случиться с разными версиями одного и того же класса на разных машинах. Но в моем случае я выполняю сериализацию и десериализацию на одной машине, в том же экземпляре JBoss ...

Глядя на этот похожий вопрос , я думаю, что должна быть проблема с моим процессом сериализации, но я не могу понять это. Это код, который я использую:

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[]? Это не должно быть проблемой, верно?

1 Ответ

0 голосов
/ 17 мая 2018

Где-то по пути, когда ваши сериализованные данные были неправильно обработаны и искажены.

Глядя на два значения serialVersionUID, становится ясно, что отличается только один байт, что говорит о том, что это не просто случай несовпадения классов.

Скорее всего, ваш поток поврежден.Обратите внимание, что serialVersionUID часто также «случайно» действует как своего рода проверка искажения, поскольку это магическое число, которое должно точно совпадать.

Реальный serialVersionUID в шестнадцатеричном формате равен 54C71557F981284F.Тот, который у вас есть в потоке, - 54C71557F93F284F.Обратите внимание, что 81 изменено на 3F.3F - это код ASCII для ?, который является символом замены по умолчанию для ошибок декодирования в Java.

Это убедительно свидетельствует о том, что в какой-то момент ваши данные были неправильно обработаны как текстовые данные.Поскольку значение в правильных данных равно 81, есть большая вероятность, что кодировка, используемая для неправильного «декодирования» ваших данных, была ISO-8859-1 , которой ничего не назначено этому кодуточка.

tl; dr где-то по пути, когда ваши сериализованные данные были преобразованы в String и обратно в byte[], и это ужасная идея, которую следует избегать.Обрабатывайте двоичные данные как двоичные данные (используйте byte[] и InputStream / Outputstream).Избегайте всего, что обрабатывает текстовые данные (т.е. не используйте String, избегайте Reader / Writer).

...