J'ai:
class MyClass extends MyClass2 implements Serializable {
//...
}
Dans MyClass2 est une propriété qui n'est pas sérialisable. Comment puis-je sérialiser (et désérialiser) cet objet?
Correction: MyClass2 n'est bien sûr pas une interface mais une classe.
Comme quelqu'un d'autre l'a noté, le chapitre 11 de Josh Bloch Effective Java est une ressource indispensable sur Java Serialization.
Quelques points de ce chapitre pertinents à votre question:
J'ai écrit un exemple rapide ci-dessous pour illustrer cela.
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 n'est qu'une interface, donc techniquement, elle n'a pas de propriétés, seulement des méthodes. Cela étant dit, si vous avez des variables d'instance qui ne sont pas elles-mêmes sérialisables, le seul moyen que je connaisse pour le contourner est de déclarer ces champs transitoires.
ex:
private transient Foo foo;
Lorsque vous déclarez un champ transitoire, il sera ignoré pendant le processus de sérialisation et de désérialisation. Gardez à l'esprit que lorsque vous désérialisez un objet avec un champ transitoire, la valeur de ce champ sera toujours sa valeur par défaut (généralement nulle).
Notez que vous pouvez également remplacer la méthode readResolve () de votre classe afin d'initialiser les champs transitoires en fonction d'un autre état du système.
Si possible, les parties non sérialisables peuvent être définies comme transitoires
private transient SomeClass myClz;
Sinon, vous pouvez utiliser Kryo . Kryo est un cadre de sérialisation de graphes d'objets rapide et efficace pour Java (par exemple Java sérialisation de Java.awt.Color nécessite 170 octets, Kryo seulement 4 octets), qui peut sérialiser également des objets non sérialisables. Kryo peut également effectuer une copie/clonage automatique profond et superficiel. Il s'agit d'une copie directe d'un objet à un autre, pas object->bytes->object
.
Voici un exemple d'utilisation de 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();
Les objets sérialisés peuvent également être compressés en enregistrant le sérialiseur exact:
kryo.register(SomeObject.class, new DeflateCompressor(new FieldSerializer(kryo, SomeObject.class)));
Si vous pouvez modifier MyClass2, la façon la plus simple de résoudre ce problème est de déclarer la propriété transitoire.
Vous devrez implémenter writeObject()
et readObject()
et effectuer une sérialisation/désérialisation manuelle de ces champs. Voir la page javadoc pour Java.io.Serializable
pour plus de détails. Effective Java de Josh Bloch contient également de bons chapitres sur l'implémentation d'une sérialisation robuste et sécurisée.
Dépend pourquoi ce membre de MyClass2 n'est pas sérialisable.
S'il y a une bonne raison pour laquelle MyClass2 ne peut pas être représentée sous une forme sérialisée, alors les chances sont bonnes, la même raison s'applique à MyClass, car c'est une sous-classe.
Il peut être possible d'écrire un formulaire sérialisé personnalisé pour MyClass en implémentant readObject et writeObject, de telle manière que l'état des données d'instance MyClass2 dans MyClass puisse être recréé de manière appropriée à partir des données sérialisées. Ce serait la voie à suivre si l'API de MyClass2 est corrigée et que vous ne pouvez pas ajouter Serializable.
Mais vous devez d'abord comprendre pourquoi MyClass2 n'est pas sérialisable, et peut-être le changer.
Vous pouvez commencer par examiner le mot clé transitoire, qui marque les champs comme ne faisant pas partie de l'état persistant d'un objet.
Plusieurs possibilités sont apparues et je les résume ici:
XStream est une excellente bibliothèque pour faire rapidement Java à la sérialisation XML pour tout objet, qu'il soit sérialisable ou non. Même si le format cible XML ne convient pas vous, vous pouvez utiliser le code source pour apprendre à le faire.
Une approche utile pour sérialiser des instances de classes non sérialisables (ou au moins des sous-classes de) est connue comme un proxy série. Essentiellement, vous implémentez writeReplace pour renvoyer une instance d'une classe sérialisable complètement différente qui implémente readResolve pour renvoyer une copie de l'objet d'origine. J'ai écrit un exemple de sérialisation de Java.awt.BasicStroke sur senet