Сериализация Java с несериализуемыми частями



Я:



class MyClass extends MyClass2 implements Serializable {
//...
}


в MyClass2-это свойство, которое не является сериализуемым. Как я могу сериализовать (и де-сериализовать) этот объект?



коррекция: MyClass2-это, конечно, не интерфейс, а класс.

651   10  

10 ответов:

как заметил кто-то еще, Глава 11 Джоша Блоха Эффективная Java является незаменимым ресурсом для сериализации Java.

пара пунктов из этой главы, относящихся к вашему вопросу:

  • предполагая, что вы хотите сериализовать состояние несериализуемого поля в MyClass2, это поле должно быть доступно для MyClass, либо напрямую, либо через геттеры и сеттеры. MyClass должен будет реализовать пользовательскую сериализацию, предоставив readObject и writeObject методы.
  • класс несериализуемого поля должен иметь API, позволяющий получить его состояние (для записи в поток объектов), а затем создать экземпляр нового экземпляра с этим состоянием (при последующем чтении из потока объектов.)
  • по пункту 74 эффективной Java, MyClass2 должны иметь конструктор no-arg, доступный для MyClass, в противном случае MyClass невозможно расширить MyClass2 и реализовать Упорядочиваемый.

Я написал быстрый пример ниже, иллюстрирующий это.


class MyClass extends MyClass2 implements Serializable{

  public MyClass(int quantity) {
    setNonSerializableProperty(new NonSerializableClass(quantity));
  }

  private void writeObject(java.io.ObjectOutputStream out)
  throws IOException{
    // note, here we don't need out.defaultWriteObject(); because
    // MyClass has no other state to serialize
    out.writeInt(super.getNonSerializableProperty().getQuantity());
  }

  private void readObject(java.io.ObjectInputStream in)
  throws IOException {
    // note, here we don't need in.defaultReadObject();
    // because MyClass has no other state to deserialize
    super.setNonSerializableProperty(new NonSerializableClass(in.readInt()));
  }
}

/* this class must have no-arg constructor accessible to MyClass */
class MyClass2 {

  /* this property must be gettable/settable by MyClass.  It cannot be final, therefore. */
  private NonSerializableClass nonSerializableProperty;

  public void setNonSerializableProperty(NonSerializableClass nonSerializableProperty) {
    this.nonSerializableProperty = nonSerializableProperty;
  }

  public NonSerializableClass getNonSerializableProperty() {
    return nonSerializableProperty;
  }
}

class NonSerializableClass{

  private final int quantity;

  public NonSerializableClass(int quantity){
    this.quantity = quantity;
  }

  public int getQuantity() {
    return quantity;
  }
}

MyClass2-это просто интерфейс, поэтому технически он не имеет свойств, только методы. Это, как говорится, если у вас есть переменные экземпляра, которые сами по себе не сериализуемы, единственный способ, который я знаю, чтобы обойти это, - объявить эти поля переходными.

ex:

private transient Foo foo;

при объявлении поля переходным оно будет игнорироваться в процессе сериализации и десериализации. Имейте в виду, что при десериализации объекта с переходным полем это поле значение всегда будет по умолчанию (обычно null.)

Примечание Вы также можете переопределить метод readResolve () вашего класса для инициализации переходных полей на основе другого состояния системы.

если возможно, несериализуемые части могут быть установлены как переходные

private transient SomeClass myClz;

в противном случае вы можете использовать Kryo. Kryo-это быстрая и эффективная структура сериализации графа объектов для Java(например, сериализация JAVA java.ОУ.Цвет требует 170 байт, Kryo только 4 байта), который может сериализовать также несериализуемые объекты. Kryo также может выполнять автоматическое глубокое и поверхностное копирование/клонирование. Это прямое копирование от объекта к объекту, а не object->bytes->object.

вот пример, как использовать kryo

Kryo kryo = new Kryo();
// #### Store to disk...
Output output = new Output(new FileOutputStream("file.bin"));
SomeClass someObject = ...
kryo.writeObject(output, someObject);
output.close();
// ### Restore from disk...
Input input = new Input(new FileInputStream("file.bin"));
SomeClass someObject = kryo.readObject(input, SomeClass.class);
input.close();

сериализованные объекты также могут быть сжаты путем регистрации точного сериализатора:

kryo.register(SomeObject.class, new DeflateCompressor(new FieldSerializer(kryo, SomeObject.class)));

Если вы можете изменить MyClass2, самый простой способ решить эту проблему-объявить свойство transient.

вам нужно будет реализовать writeObject() и readObject() и выполните ручную сериализацию / десериализацию этих полей. Смотрите страницу javadoc для java.io.Serializable для сведения. Джош блох Эффективная Java также есть несколько хороших глав по реализации надежной и безопасной сериализации.

зависит от того, почему этот член MyClass2 не сериализуется.

Если есть какая-то веская причина, почему MyClass2 не может быть представлен в сериализованной форме, то велика вероятность, что та же причина относится к MyClass, так как это подкласс.

можно написать пользовательскую сериализованную форму для MyClass путем реализации readObject и writeObject таким образом, чтобы состояние данных экземпляра MyClass2 в MyClass можно было соответствующим образом воссоздать из сериализованных данных. Это было бы так, если API MyClass2 исправлен, и вы не можете добавить сериализуемый.

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

вы можете начать, глядя в транзиторная ключевое слово, которое помечает поля как не являющиеся частью постоянного состояния объекта.

несколько возможностей выскочили, и я возобновляю их здесь:

  • реализовать writeObject () и readObject () как sk предложил
  • объявите свойство переходным, и оно не будет сериализовано, как сначала указано Хэнк
  • используйте XStream, как указано Борис-Терзича
  • используйте последовательный прокси, как указано Тома-Хотин-tackline

XStream это отличная библиотека для быстрого выполнения Java в XML сериализации для любого объекта независимо от того, является ли он Сериализуемым или нет. Даже если целевой формат XML вам не подходит, вы можете использовать исходный код, чтобы узнать, как это сделать.

полезный подход для сериализации экземпляров несериализуемых классов (или, по крайней мере, подклассов) известен последовательным Прокси. По сути, вы реализуете writeReplace для возврата экземпляра совершенно другого сериализуемого класса, который реализует readResolve для возврата копии исходного объекта. Я написал пример сериализации java.ОУ.Основной удар на Usenet

Comments

    Ничего не найдено.