Пользовательская Сериализация Java - PullRequest
60 голосов
/ 03 сентября 2011

У меня есть объект, который содержит несколько несериализуемых полей, которые я хочу сериализовать. Они из отдельного API, который я не могу изменить, поэтому сделать их Serializable не вариант. Основной проблемой является класс Location. Он содержит четыре вещи, которые можно сериализовать, все что нужно Как я могу использовать read / writeObject для создания собственного метода сериализации, который может делать что-то вроде этого:

// writeObject:
List<Integer> loc = new ArrayList<Integer>();
loc.add(location.x);
loc.add(location.y);
loc.add(location.z);
loc.add(location.uid);
// ... serialization code

// readObject:
List<Integer> loc = deserialize(); // Replace with real deserialization
location = new Location(loc.get(0), loc.get(1), loc.get(2), loc.get(3));
// ... more code

Как я могу это сделать?

Ответы [ 3 ]

62 голосов
/ 03 сентября 2011

Java поддерживает Пользовательская сериализация .Прочтите раздел Настройка протокола по умолчанию.

Цитата:

Однако есть странное, но хитрое решение.Используя встроенную функцию механизма сериализации, разработчики могут улучшить обычный процесс, предоставив два метода внутри своих файлов классов.Это следующие методы:

  • private void writeObject (ObjectOutputStream out) выбрасывает IOException;
  • private void readObject (ObjectInputStream in) выбрасывает IOException, ClassNotFoundException;

В этом методе вы можете сериализовать его в другие формы, если вам нужно, например, в ArrayList для местоположения, которое вы иллюстрировали, или в JSON или другой формат / метод данных и реконструировать его.обратно на readObject ()

В вашем примере вы добавите следующий код:



private void writeObject(ObjectOutputStream oos)
throws IOException {
    // default serialization 
    oos.defaultWriteObject();
    // write the object
    List loc = new ArrayList();
    loc.add(location.x);
    loc.add(location.y);
    loc.add(location.z);
    loc.add(location.uid);
    oos.writeObject(loc);
}

private void readObject(ObjectInputStream ois)
throws ClassNotFoundException, IOException {
    // default deserialization
    ois.defaultReadObject();
    List loc = (List)ois.readObject(); // Replace with real deserialization
    location = new Location(loc.get(0), loc.get(1), loc.get(2), loc.get(3));
    // ... more code

}

32 голосов
/ 03 сентября 2011

Аналогично ответу @ momo, но без использования значений List и auto-boxed int, что сделает его намного более компактным.

private void writeObject(ObjectOutputStream oos) throws IOException {
    // default serialization 
    oos.defaultWriteObject();
    // write the object
    oos.writeInt(location.x);
    oos.writeInt(location.y);
    oos.writeInt(location.z);
    oos.writeInt(location.uid);
}

private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
    // default deserialization
    ois.defaultReadObject();
    location = new Location(ois.readInt(), ois.readInt(), ois.readInt(), ois.readInt());
    // ... more code

}
0 голосов
/ 03 сентября 2011

Если это должна быть сериализация Java, единственный известный мне способ - переопределить readObject() и writeObject() во всех классах, имеющих ссылку на экземпляр Location, как показано в ответе Момо. Обратите внимание, что это не позволит вам сериализовать Location[] и потребует от вас подкласса всех Collection<Location>, присутствующих в вашем коде. Кроме того, требуется, чтобы поля типа Location были помечены как переходные, что исключит их определения из записи в поток сериализации, что может помешать обнаружению несовместимых изменений класса.

Лучше было бы просто переопределить ObjectOutputStream.writeObject. Увы, этот метод final. Вместо этого вы можете переопределить ObjectOutputStream.writeObjectOverride(), но этот метод не может делегировать реализацию по умолчанию, ObjectOutputStream.writeObject0(), потому что этот метод private. Конечно, вы можете вызывать приватный метод с помощью отражения, но ...

Поэтому я рекомендую проверить ваши ограничения. Это должна быть сериализация Java? Неужели вы не можете изменить определение класса Location?

Если у вас есть исходный код для класса Location, добавить implements Serializable и добавить его в свой путь к классу довольно тривиально. Да, вам придется делать это снова всякий раз, когда вы обновляете библиотеку, но это может быть лучше, чем альтернатива ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...