SerialVersionUID в стандартной библиотеке Java на разных JVM

На основе описания SerialVersionUID здесь: https://docs.oracle.com/javase/8/docs/platform/serialization/spec/class.html#a4100 представляется необходимым всегда включать SerialVersionUID во все создаваемые вами классы, чтобы JVM, используемая для сериализации, и различные JVM, используемые для десериализации, не будут автоматически назначать свои собственные SerialVersionUID, которые могут отличаться друг от друга из-за различий в JVM. Это хорошо работает для управления десериализацией моих собственных классов, но что, если я хочу убедиться, что классы в стандартной библиотеке, сериализованные с помощью JVM A, могут быть десериализованы с помощью JVM B?

Map<Integer, String> myMap = new HashMap<>();

HashMap определяет SerialVersionUID. Но:

  • Поскольку HashMap находится в стандартной библиотеке Java, есть ли у меня какие-либо гарантии того, что если я сериализую этот HashMap с помощью JVM A, JVM B сможет его десериализовать? А именно, разрешено ли JVM B указывать SerialVersionUID, отличный от JVM A, по крайней мере, если B является просто обновлением младшей версии от A?
  • Если это не гарантируется для классов стандартной библиотеки, действительно ли использование SerialVersionUID обеспечивает правильную десериализацию только для ваших собственных классов, которые никогда не касаются стандартной библиотеки Java? Например, класс, который выглядит так:

    public class NewClass implements Serializable
    {
        private static final long serialVersionUID = 1L;
    
        private final Map<Integer, String> myMap;
    
        public NewClass()
        {
            this.myMap = new HashMap<>();
        }
    }
    

    будет склонен к сбою, потому что десериализация зависит от HashMap, имеющего один и тот же SerialVersionUID, который может быть разным в разных JVM, верно?


person Nile    schedule 01.03.2018    source источник


Ответы (1)


Возможно да, вы правы.

На самом деле это случилось с нами некоторое время назад с некоторыми классами swing (я действительно не могу вспомнить, какие именно), но сериализация на jdkX и де-сериализация их на jdkX+1 (это было очень давно, извините за отсутствие этих деталей) , дела с InvalidClassException начали ломаться. В то время мы заплатили за поддержку и открыли вопрос - ответ был, ну, эти классы изменились таким образом, что было бы невозможно правильно их десериализовать - вы застряли с этой версией или обновитесь до jdk+1 и используйте это. С тех пор со мной ни разу такого не случалось, ни разу.

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

С другой стороны, HashMap имеет очень умный способ сериализации своих данных. Он сериализует (среди прочего, например, load_factor и т. д.) только свои ключи и значения и ничего больше. Таким образом, независимо от того, изменится ли реализация, их можно будет десериализовать. По этой причине некоторые из полей, которые были бы не нужны, отмечены как временные, например:

 transient int modCount;
 transient Set<Map.Entry<K,V>> entrySet;

Идея состоит в том, что он должен сериализовать данные и структуру.


Если HashMap изменится таким образом, что сериализация нарушится, например, в jdk-11, это разозлит многих разработчиков, я сомневаюсь, что это когда-либо будет выбрано (если только действительно не понадобится)

person Eugene    schedule 01.03.2018
comment
У каждого класса Swing есть предупреждение в Javadoc о том, что он потенциально несовместим с сериализацией в разных версиях JDK. - person user207421; 02.03.2018
comment
@EJP о! Теперь это имеет смысл... Спасибо - person Eugene; 02.03.2018