Частичная (де)сериализация объектов Java

Допустим, у нас есть 3 класса:

class foo { // not a singleton
    String s;
}
class bar {
    foo f;
    int i;
}
class baz {
    foo sameF;
}

Теперь мы создаем экземпляры

foo onlyFoo = new foo("the only one");
bar theBar = new bar(onlyFoo, 123);
baz theBaz = new baz(onlyFoo);

После этого мы хотим сохранить их последовательно в файле. Если мы десериализуем theBaz, изменим onlyFoo и снова десериализуем theBaz в файл, то theBar по-прежнему будет содержать исходный onlyFoo, поэтому есть две разные версии onlyFoo.

Вместо этого я хочу, чтобы я хранил theBaz и theBar без onlyFoo, хранил три объекта отдельно, и как только кто-то десериализует theBaz, я также хочу дать ему только Foo. Если он снова десериализует измененный onlyFoo, у Baz и theBar будет то же измененное onlyFoo, поэтому, если кто-то запрашивает объект (например, theBar), он получает полный сериализованный объект со всеми объектами, на которые ссылаются (onlyFoo) как нормальный процесс сериализации вернется.

Я знаю, что мне нужно хранить объекты и сохранять ссылки вручную и отдельно, потому что сериализация по умолчанию не может справиться с этой проблемой. Чего я не знаю, так это того, как частично сериализовать/десериализовать объекты Java? Мне нужно отделить примитивы и их оболочки от «высших» объектов и хранить эти объекты отдельно.

Обновить

  1. Я не могу изменить классы.
  2. Я не знаю все классы. Он должен работать со всеми сериализуемыми объектами, о которых я, возможно, никогда не слышал (они могут быть или не быть окончательными)

person Community    schedule 30.11.2012    source источник
comment
класс открыт для расширения? Я имею в виду, это окончательно или нет?   -  person Narendra Pathai    schedule 30.11.2012
comment
Обновлен вопрос: «Я не знаю всех классов. Он должен работать со всеми сериализуемыми объектами, о которых я, возможно, никогда не слышал». Я вижу, если они окончательные, это тоже может быть большой проблемой.   -  person    schedule 30.11.2012
comment
Пожалуйста, примите (отметьте галочкой) один из ответов   -  person AlexWien    schedule 05.12.2012


Ответы (3)


Если вам нужен больший контроль, вы можете перезаписать writeObject() и readObject() и сериализовать себя.

class bar {
    ...

    private void writeObject(ObjectOutputStream stream) throws IOException {
      // let version 1, later when you need to have versioning. 
      stream.writeInt(version);
      stream.writeInt(i);
      // leave out 
      // stream.writeObject(foo);

    }
}
// read object the analog, see 

http://docs.oracle.com/javase/6/docs/platform/serialization/spec/output.html#861

person AlexWien    schedule 30.11.2012
comment
Хм, я не могу модифицировать сами классы, но я мог бы обернуть их в прокси. Эти прокси будут перезаписывать writeObject таким образом, что они сериализуют объект, для которого они созданы, а не себя. Затем я просто сериализую прокси. Для этого им нужно использовать отражение, но проблема, которую я вижу, заключается в том, что оно должно работать со всеми сериализуемыми объектами, даже если я никогда о них не слышал. - person ; 30.11.2012
comment
Я отметил это как правильный ответ, потому что это мне очень помогло. Я создаю рабочий прототип, и я опубликую / свяжу его здесь, когда это будет сделано. - person ; 06.12.2012
comment
Полностью забудьте о моем прототипе: gist.github.com/maklemenz/4515273865853b46fac1 - person ; 13.12.2013

Отметьте ссылки, которые вы не хотите сериализовать, с помощью переходного ключевого слова.

person Nemanja    schedule 30.11.2012
comment
Вы правы, но я не могу изменить определения foo, bar или baz. Идея состоит в том, что он работает со всеми сериализуемыми объектами. - person ; 30.11.2012
comment
Затем вам нужно установить ссылки на null вручную. Если вам нужно общее решение, это можно сделать с помощью java.reflection. - person Nemanja; 30.11.2012
comment
Хм, если я получу еще один указатель на объект и установлю для поля значение null, я смогу десериализовать первый объект позже и установить второй объект в поле после десериализации первого. Спасибо, это должно сработать. Есть ли еще вариант? Я хочу, чтобы вызывающая сторона моего метода также могла получить полный сериализованный объект, и я не хочу сериализовать его сразу после десериализации, чтобы заархивировать это. - person ; 30.11.2012

Вы можете сделать foo transient, как показано ниже.

class bar {
    transient foo f;
    int i;
}
person Bhavik Ambani    schedule 30.11.2012
comment
Правильно, но, как уже упоминалось в другом комментарии, я не могу изменять эти классы. - person ; 30.11.2012