Serializacja Java z częściami Nie serializowanymi

Mam:

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

W MyClass2 jest właściwością, która nie jest serializowalna. Jak mogę serializować (i de-serializować) ten obiekt?

Poprawka: MyClass2 to oczywiście nie interfejs, ale Klasa.

Author: Burkhard, 2008-09-18

10 answers

Jak ktoś inny zauważył, Rozdział 11 efektywnej Javy Josha Blocha jest niezbędnym źródłem informacji na temat serializacji Javy.

Kilka punktów z tego rozdziału dotyczących Twojego pytania:

  • zakładając, że chcesz serializować stan pola nieserializowalnego w MyClass2, pole to musi być dostępne dla MyClass, bezpośrednio lub poprzez gettery i settery. MyClass będzie musiał zaimplementować niestandardową serializację, dostarczając readObject i writeobject metody.
  • klasa pola nieserializowalnego musi mieć API, aby umożliwić uzyskanie jego stanu (do zapisu do strumienia obiektu), a następnie utworzenie nowej instancji o tym stanie (podczas późniejszego odczytu ze strumienia obiektu.)
  • [8]}na poz. 74 efektywnej Javy, MyClass2 musi mieć konstruktor no-arg Dostępny dla MyClass, w przeciwnym razie MyClass nie może rozszerzyć MyClass2 i zaimplementować Serializable.

Napisałem szybki przykład poniżej ilustruje to.


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;
  }
}
 49
Author: Scott Bale,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-18 22:24:30

MyClass2 jest tylko interfejsem, więc technicznie nie ma żadnych właściwości, tylko metody. To powiedziawszy, jeśli masz zmienne instancji, które same nie są serializowalne, jedynym sposobem, o którym wiem, aby je obejść, jest zadeklarowanie tych pól jako transient.

Ex:

private transient Foo foo;

Gdy zadeklarujesz pole transient, zostanie ono zignorowane podczas procesu serializacji i deserializacji. Należy pamiętać, że po deserializacji obiektu z polem przejściowym wartość tego pola będzie zawsze jest domyślna (Zwykle null.)

Uwaga Możesz także nadpisać metodę readResolve () swojej klasy w celu zainicjowania pól przejściowych w oparciu o inny stan systemu.

 34
Author: Mike Deck,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-18 18:23:51

Jeśli to możliwe, Części nieseryjne mogą być ustawione jako przejściowe

private transient SomeClass myClz;

W przeciwnym razie możesz użyć Kryo . Kryo jest szybkim i wydajnym frameworkiem do serializacji grafów obiektowych dla języka Java(np.awt.Kolor wymaga 170 bajtów, Kryo tylko 4 bajty), które mogą serializować również obiekty nie serializowalne. Kryo może również wykonywać automatyczne głębokie i płytkie kopiowanie/klonowanie. Jest to bezpośrednie kopiowanie z obiektu do obiektu, a nie object->bytes->object.

Oto przykład użycia 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();

Serializowane obiekty mogą być również skompresowane przez zarejestrowanie dokładnego serializera:

kryo.register(SomeObject.class, new DeflateCompressor(new FieldSerializer(kryo, SomeObject.class)));
 15
Author: Radim Burget,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-27 10:12:27

Jeśli możesz zmodyfikować MyClass2, najprostszym sposobem rozwiązania tego problemu jest zadeklarowanie właściwości transient.

 11
Author: ykaganovich,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-07 18:45:45

Będziesz musiał zaimplementować writeObject() i readObject() i wykonać ręczną serializację / deserializację tych pól. Szczegóły można znaleźć na stronie javadoc dla java.io.Serializable. Josha Blocha Effective Java ma również kilka dobrych rozdziałów na temat implementacji solidnej i bezpiecznej serializacji.

 6
Author: sk.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-09 08:31:41

Zależy, dlaczego ten członek MyClass2 nie jest serializowalny.

Jeśli istnieje dobry powód, dla którego MyClass2 nie może być reprezentowany w formie serializowanej, to są duże szanse, że ten sam powód dotyczy MyClass, ponieważ jest to podklasa.

Możliwe jest napisanie niestandardowego formularza serializowanego dla MyClass poprzez implementację readObject i writeObject, w taki sposób, że stan danych instancji myclass2 w MyClass może być odpowiednio odtworzony z danych serializowanych. To będzie dobrze, jeśli Interfejs API MyClass2 jest naprawiony i nie można dodać Serializowalnego.

Ale najpierw powinieneś dowiedzieć się, dlaczego MyClass2 nie jest serializowalny, i może to zmienić.

 5
Author: Steve Jessop,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-19 00:39:26

Możesz zacząć od spojrzenia na słowo kluczowe transient , które oznacza pola jako nie będące częścią stanu trwałego obiektu.

 4
Author: Hank,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-18 18:20:39

Pojawiło się kilka możliwości i wznawiam je tutaj:

  • zaimplementuj writeobject() i readObject () jako SK zasugerowane
  • zadeklaruj właściwość transient i nie będzie ona serializowana jako pierwsza podana przez
  • Użyj XStream zgodnie z zapisem boris-terzic
  • Użyj seryjnego Proxy zgodnie z tom-hawtin-tackline
 4
Author: Burkhard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:54:50

XStream jest świetną biblioteką do szybkiej serializacji Java do XML dla dowolnego obiektu, bez względu na to, czy jest Serializowalny, czy nie. Nawet jeśli docelowy format XML Ci nie odpowiada, możesz użyć kodu źródłowego, aby dowiedzieć się, jak to zrobić.

 3
Author: Boris Terzic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-27 14:59:32

Użytecznym podejściem do serializacji instancji klas nieperializowalnych (lub przynajmniej podklas) jest znany Serial Proxy. Zasadniczo implementujesz writeReplace, aby zwrócić instancję zupełnie innej klasy serializowalnej, która implementuje readResolve, aby zwrócić kopię oryginalnego obiektu. Napisałem przykład serializacji Javy.awt.BasicStroke on Usenet

 2
Author: Tom Hawtin - tackline,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-19 10:21:58