Подтвердить что ты не робот

Сериализация Java - java.io.InvalidClassException локальный класс несовместим

У меня есть открытый класс, который реализует Serializable, который расширяется несколькими другими классами. Только эти подклассы были сериализованы раньше - никогда супер класс.

Суперкласс определил serialVersionUID.

Я не уверен, если это имеет значение, но оно не было выделено частным, а скорее оно имело защиту по умолчанию - вы могли бы сказать, что он защищен пакетом

static final long serialVersionUID = -7588980448693010399L;

Суперкласс или любой из подклассов, однако реализованный readObject или writeObject, и ни один из подклассов не имел явно определенного serialVersionUID. Я полагал, что один, определенный в суперклассе, будет достаточным.

Несмотря на все это, все было замечательно, если было прочитано ранее сериализованных объектов до тех пор, пока новая переменная экземпляра, List/ArrayList и новый метод не были добавлены в суперкласс, а некоторые частные переменные экземпляра были добавлены к одному его подклассов.

Теперь, когда вы пытаетесь прочитать ранее сериализованные объекты, генерируется исключение. Аналогично этому:

com.SomeCompany.SomeSubClass; local class incompatible: stream classdesc serialVersionUID = 1597316331807173261, local class serialVersionUID = -3344057582987646196

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

Были бы оценены предложения о том, как выйти из этой дилеммы. Я предполагаю, что мне нужно реализовать readObject и writeObject, но кроме вызова defaultReadObject() и defaultWriteObject(), я не совсем уверен, что мне нужно делать. Я также не знаю, нужно ли добавлять serialVerisonUID во все подклассы, или если readObject и writeObject должны быть реализованы каждым подклассом или если я могу просто реализовать их один раз, предполагая, что мне вообще нужно, в суперклассе.

4b9b3361

Ответ 1

@DanielChapman дает хорошее объяснение serialVersionUID, но никакого решения. решение таково: запустите программу serialver на всех ваших старых классах. поместите эти значения serialVersionUID в ваши текущие версии классов. если текущие классы совместимы со старыми версиями, вы должны быть в порядке. (обратите внимание на будущий код: вы всегда должны иметь serialVersionUID для всех классов Serializable)

если новые версии не совместимы с последовательностью, вам нужно сделать магию с помощью специальной readObject реализации (вам понадобится только пользовательский writeObject, если бы вы пытались написать новые данные класса, которые были бы совместимы с старый код). вообще говоря, добавление или удаление полей классов не делает класс последовательным несовместимым. обычно меняется тип существующих полей.

Конечно, даже если новый класс совместим с последовательностью, вам все равно может понадобиться реализация readObject. вам может понадобиться это, если вы хотите заполнить любые новые поля, отсутствующие в данных, сохраненных из старых версий класса (например, у вас есть новое поле List, которое вы хотите инициализировать в пустой список при загрузке данных старого класса).

Ответ 2

Короткий ответ здесь - это серийный идентификатор, который вычисляется через хэш, если вы его не укажете. (Статические элементы не наследуются - они статичны, там только (1) и принадлежит классу).

http://docs.oracle.com/javase/6/docs/platform/serialization/spec/class.html

Метод getSerialVersionUID возвращает serialVersionUID этого класс. Обратитесь к разделу 4.6 "Потоковые уникальные идентификаторы". Если не указанный классом, возвращаемое значение является хешем, вычисленным из имя класса, интерфейсы, методы и поля с помощью Secure Hash Алгоритм (SHA), определенный Национальным институтом стандартов.

Если вы измените класс или его иерархию, ваш хеш будет другим. Это хорошая вещь. Теперь ваши объекты разные, и у них разные члены. Таким образом, если вы прочитаете его обратно из его сериализованной формы, это на самом деле другой объект - таким образом, исключение.

Длительный ответ - сериализация чрезвычайно полезна, но, вероятно, ее нельзя использовать для сохранения, если нет другого способа сделать это. Его опасный путь специально из-за того, что вы испытываете. Вы должны рассмотреть базу данных, XML, формат файла и, возможно, JPA или другую структуру сохранения для чистого Java-проекта.

Ответ 3

Для меня я забыл добавить серийный идентификатор по умолчанию.

private static final long serialVersionUID = 1L;

Ответ 4

Это сработало для меня:

Если вы написали объект класса Serialized в файл, затем внесли некоторые изменения в файл и скомпилировали его, а затем попытаетесь прочитать объект, тогда это произойдет.

Итак, напишите необходимые объекты для повторного файла, если класс изменен и перекомпилирован.

PS: Это НЕ РЕШЕНИЕ; должно было быть обходным путем.