Сериализация Java: readFields() помимо readObject()?

ObjectInputStream.readFields() подходит только для метода private void readObject(ObjectInputStream).

public ObjectInputStream.GetField readFields() throws IOException, ClassNotFoundException {
  SerialCallbackContext ctx = curContext;
  if (ctx == null) {
    throw new NotActiveException("not in call to readObject");
  }
...

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

Любые идеи?

Если кто-то хочет узнать больше. Имена полей в некоторых моих классах были переименованы (например, обфускатором) в a, b, c и т. д. Такие классы были сериализованы с переименованными полями с использованием сериализации Java по умолчанию. Мне нужно десериализовать их в исходные классы (я знаю пары имен полей для каждого класса; a=> fieldName, b=> age, c=>gender и т. д.).


person FoxyBOA    schedule 31.07.2015    source источник
comment
Ваши пожелания — это одно, но по каким причинам вы не реализуете readObject()?   -  person user207421    schedule 31.07.2015
comment
Я не подвергаю сомнению ваш выбор, но не будет ли проще реализовать readObject(), который делегирует вызов пользовательскому обработчику? Таким образом, даже если вам нужно реализовать метод в каждом классе, это будет всего лишь один вызов метода.   -  person biziclop    schedule 31.07.2015
comment
@EJP 16: у меня есть несколько сотен таких классов. Их можно будет добавить/удалить в будущем. Я не желаю никому в dev. команда даже думает о проблемах сериализации/десериализации. Один из вариантов, что я должен использовать инструментарий байт-кода (например, Javassist), чтобы добавить метод readObject() во время процесса сборки, но я хотел бы использовать более простое решение.   -  person FoxyBOA    schedule 31.07.2015
comment
@biziclop: Да, я обдумываю это решение, но с инструментами байт-кода. Надежда существует проще.   -  person FoxyBOA    schedule 31.07.2015
comment
@FoxyBOA Я бы сказал, что, вероятно, нет более простого решения. Но это всего лишь предположение, основанное на общем способе работы сериализации, может быть маловероятная ловушка, к которой вы можете привязать эту логику.   -  person biziclop    schedule 31.07.2015
comment
@biziclop: другое (возможно, более простое) решение может заключаться в том, чтобы вообще не использовать сериализацию Java ради Kryo (code.google.com/p/kryo/wiki/V1Benchmarks), XStream (x-stream .github.io) или другую облегченную библиотеку сериализации.   -  person FoxyBOA    schedule 31.07.2015
comment
@FoxyBOA Я думал, что предпосылка в том, что у вас уже есть сериализованные данные, которые вы не можете изменить. (Такие классы были сериализованы с переименованными полями с использованием сериализации Java по умолчанию.)   -  person biziclop    schedule 31.07.2015
comment
@biziclop: Нет, я могу выбрать практически любой механизм сериализации. Мы используем db4o прямо сейчас. К сожалению, проект мертв, и я ищу альтернативное решение. Я предполагаю, что нативная сериализация Java может делать то, что мы сейчас делаем. Я застрял с переименованными полями. У Db4o есть даже специальный API для такого сценария...   -  person FoxyBOA    schedule 31.07.2015
comment
@FoxyBOA XStream также довольно гибок в этом отношении.   -  person biziclop    schedule 31.07.2015
comment
Как, черт возьми, вы попали в ситуацию, когда вам нужна собственная сериализация для сотен классов?   -  person user207421    schedule 31.07.2015
comment
@EJP: Долгая история. Мы используем сериализацию (только нативную) для модуля транспортировки между производственной средой и средой разработки. В продакшене наши классы обрабатываются (то есть запутываются), а в dev. среда нам нужна оригинальная (например, для тестов). У нас сложная иерархия объектов и только обфускатор знает, что (и как) он переименует в следующий раз.   -  person FoxyBOA    schedule 31.07.2015


Ответы (1)


Чтобы переименовать поля из потока объектов, необходимо переопределить метод ObjectInputStream.readClassDescriptor, который возвращает ObjectStreamClass.

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

  • Описывает поля сериализуемого класса, работающего в текущем экземпляре JVM. Найдите эти экземпляры через ObjectStreamClass.lookup.
  • Описывает поля сериализуемого класса, представленные в конкретном сериализованном потоке. Эти экземпляры возвращаются реализациями ObjectInputStream.readClassDescriptor.

В вашем вызове переопределения super.readClassDescriptor. Это будет считывать данные из потока. Замените значение из потока значением с новыми именами полей, если это интересующий вас класс.

Как создать свой ObjectStreamClass? Запишите фиктивный экземпляр интересующих вас классов в файл ObjectOutputStream. Вы можете сделать это как часть встроенного, просто сохранив двоичные данные. Прочитайте с другим ObjectInputStream с переопределением readClassDescriptor, чтобы спрятать дескрипторы.

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

person Tom Hawtin - tackline    schedule 15.07.2019
comment
Я бы написал код для этого, но сейчас я занимаюсь другими вещами. Вероятно, немного поздно для оригинального плаката, а также для сериализации Java. / (Изначально я опубликовал этот ответ на неправильные вопросы, потому что я идиот.) - person Tom Hawtin - tackline; 15.07.2019
comment
вы можете использовать отражение, чтобы назначить переменную, проверить мое решение - person Archmede; 14.08.2019