Как бороться с сериализованным объектом Java, пакет которого изменился? - PullRequest
17 голосов
/ 15 марта 2011

У меня есть класс Java, который хранится в объекте HttpSession, который сериализуется и передается между серверами в кластерной среде.Для целей этого объяснения давайте назовем этот класс «Person».

В процессе улучшения кода этот класс был перемещен из «com.acme.Person» в «com.acme.entity».Человек".Внутри класс остается точно таким же (те же поля, те же методы, все то же самое).

Проблема в том, что у нас есть два набора серверов, на которых одновременно работает старый код и новый код.Серверы со старым кодом сериализовали объект HttpSession, и когда новый код десериализует его, он генерирует исключение ClassNotFoundException, поскольку не может найти старую ссылку на com.acme.Person.На данный момент с этим легко справиться, потому что мы можем просто воссоздать объект, используя новый пакет.Тогда возникает проблема, что HttpSession на новых серверах будет сериализовать объект с новой ссылкой на com.acme.entity.Person, и когда это не будет сериализовано на серверах, выполняющих старый код, будет выдано другое исключение.На данный момент мы больше не можем иметь дело с этим исключением.

Какова наилучшая стратегия для таких случаев?Есть ли способ указать новым серверам сериализовать объект со ссылкой на старый пакет и отменить сериализацию ссылок на старый пакет на новый?Как бы нам перейти на использование нового пакета и забыть о старом, когда все серверы запустят новый код?

Ответы [ 4 ]

16 голосов
/ 15 марта 2011

Я нашел это сообщение в блоге , в котором утверждается, что у него есть решение, хотя оно и не дает четкого определения.

На самом деле это означает, что вы создаете подкласс:ObjectInputStream, который переопределяет метод readClassDescriptor, чтобы сделать что-то вроде этого:

@Override
protected java.io.ObjectStreamClass readClassDescriptor() 
        throws IOException, ClassNotFoundException {
    ObjectStreamClass desc = super.readClassDescriptor();
    if (desc.getName().equals("oldpkg.Widget")) {
        return ObjectStreamClass.lookup(newpkg.Widget.class);
    }
    return desc;
};

Вы также должны посмотреть на этот ТАК вопрос и его ответы , которые охватывают некоторые изна том же основании, что и ваш вопрос.

Мой совет: не поддерживает случай, когда старые версии программного обеспечения считывают данные, сериализованные новой версией.

  • Это хорошая возможность побудить (фактически заставить) людей перейти на последнюю версию базы кода.Вообще говоря, в интересах всех , чтобы это произошло раньше, а не позже.

  • Если преждевременно заставлять людей обновляться по другим причинам, то (ИМО) вы должны серьезно рассмотреть вопрос об отмене ваших изменений в именах классов / пакетов.Подождите, пока у вас не будет четкой стратегии / плана модернизации, которая 1) технически обоснована и 2) приемлема для всех заинтересованных сторон.

3 голосов
/ 15 марта 2011

Это всегда большая головная боль с сериализацией Java. Пока вы все равно переносите свои классы, я бы рекомендовал перейти на другой механизм сериализации, такой как XStream. Есть интересная статья об этом в JavaLobby.

2 голосов
/ 28 октября 2011

В некоторых случаях у вас нет доступа к ObjectInputStream, и вы не можете переопределить readClassDescriptor(). Например, другая подсистема сериализует и десериализует эти объекты. В нашем случае у нас были устаревшие экземпляры, сериализованные в карты данных задания Quartz.

В этом случае вы должны поддерживать поверхностное определение старого класса. Вы можете реализовать методы readResolve() и writeReplace() старого класса.

class OldClass{
  private int aField;
  private Object readResolve() throws ObjectStreamException {
     return new NewClass(aField);
  }
  private Object writeReplace() throws ObjectStreamException {
     return new NewClass(aField);
  }
}
2 голосов
/ 15 марта 2011

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

...