явный serialVersionUID считается вредным? - PullRequest
25 голосов
/ 07 января 2009

Я, вероятно, рискую понизить это.

Мне кажется, что явно указывать serialVersionUID для новых классов плохо. Рассмотрим два случая, когда не нужно менять его, когда макет должен был быть изменен, и менять его, когда этого не должно быть.

Не изменяется, когда это должно было быть изменено, происходит почти только тогда, когда это явно. В этом случае это приводит к некоторым очень тонким, трудно обнаруживаемым ошибкам. Особенно во время разработки, когда макет класса часто меняется. Но если он не был явно указан, он изменится, и десериализация будет громко прервана, что, скорее всего, решится путем очистки хранилища.

Изменение этого значения, когда оно не должно происходить, происходит почти только тогда, когда оно неявно. Это редкий случай, когда макет класса изменился, но мы все еще хотим десериализовать из старых сериализованных BLOB-объектов. Это, вероятно, будет обнаружено во время QA ( Странные ошибки после обновления с 5.2 до 5.2.1, см. Прилагаемую трассировку стека ) и может быть тривиально исправлено путем установки явного значения.

Комментарии

Ответы [ 6 ]

19 голосов
/ 07 января 2009

Изменение, когда оно не должно происходить по причинам, отличным от изменений макета класса - проблема в том, что это зависит от реализации компилятора. Если вы выполняете отладку в Eclipse, но производите сборку с помощью javac, вы можете получить два несовместимых набора данных.

5 голосов
/ 07 января 2009

На моей работе мы явно запрещаем указывать serialVersionUID, именно из-за проблем, которые вы поднимаете.

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

4 голосов
/ 07 января 2009

, чтобы еще больше подчеркнуть сказанное Джоном Скитом и опровергнуть комментарий:

«Если вам это не нужно (т. Е. Вы всегда сериализуете и десериализуете одну и ту же версию класса), то вы можете спокойно пропустить явное объявление»

Даже если вы не выполняете сериализацию в течение длительного времени и используете ту же версию класса, у вас все равно могут быть проблемы . если вы пишете клиент-серверный код и клиентский код может работать с версией / реализацией jvm, отличной от серверной, у вас могут возникнуть те же проблемы с несовместимыми serialversionuids.

Подводя итог, можно сказать, что только время, когда «безопасно» не указывать serialversionuids, - это когда вы не сериализуете долгосрочно, и вам гарантировано, что все потребители сериализованных данных будут использовать один и тот же jvm реализация и версия как оригинальный производитель.

короче, не с использованием serialversionuid, как правило, более опасная ситуация.

2 голосов
/ 07 января 2009

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

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

Если вам это не нужно (т. Е. Вы всегда сериализуете и десериализуете с одной и той же версией класса), то вы можете спокойно пропустить явное объявление, поскольку вычисленное значение обеспечит правильную версию.

1 голос
/ 16 января 2012

Если вы просто используете сериализацию для удаленного вызова метода, например вызов EJB, где классы клиента и сервера и jvm одинаковы, что, как я подозреваю, является наиболее распространенным использованием, а затем явная установка serialVersionUID (как, например, предлагает eclipse), вероятно, причинит вам значительную боль в виде случайного необъяснимые ошибки, когда несовместимые экземпляры классов рассматриваются как совместимые из-за фиксированного serialVersionUID. Удаленные вызовы будут молча работать во время низкоуровневой сериализации, и проблема возникнет только позже, когда состояние вашего объекта будет несовместимым. Вы обнаружите источник проблемы только тогда, когда поймете, что ваши клиентские и серверные классы как-то различаются (хотя serialVersionUID, конечно, нет). По моему опыту установка serialVersionUID по этой причине приносит больше вреда, чем пользы.

Если, с другой стороны, вы явно настроили serialVersionUID для чтения старых данных, вы по определению читаете в несовместимой версии и, скорее всего, в конечном итоге получите объект в несогласованном или неполном состоянии. В этом случае настройка serialVersionUID является обходным решением для другой проблемы.

1 голос
/ 07 января 2009

Независимо от того, выбираете ли вы serialVersionUID или нет (я предлагаю вам это сделать), вам следует подумать о создании всеобъемлющего набора тестов для последовательной совместимости.

Также стоит тщательно разработать серийный формат. Это по сути публичный API.

...