Sérialisation Java personnalisée

J’ai un object qui contient quelques champs non sérialisables que je veux sérialiser. Ils proviennent d’une API distincte que je ne peux pas changer, donc les rendre sérialisables n’est pas une option. Le problème principal est la classe Location. Il contient quatre éléments qui peuvent être sérialisés et dont j’ai besoin, tous les ints. Comment utiliser read / writeObject pour créer une méthode de sérialisation personnalisée capable de faire quelque chose comme ceci:

// writeObject: List loc = new ArrayList(); loc.add(location.x); loc.add(location.y); loc.add(location.z); loc.add(location.uid); // ... serialization code // readObject: List loc = deserialize(); // Replace with real deserialization location = new Location(loc.get(0), loc.get(1), loc.get(2), loc.get(3)); // ... more code 

Comment puis-je faire ceci?

Java prend en charge la sérialisation personnalisée . Lisez la section Personnaliser le protocole par défaut.

Citer:

Il existe cependant une solution étrange mais astucieuse. En utilisant une fonctionnalité intégrée du mécanisme de sérialisation, les développeurs peuvent améliorer le processus normal en fournissant deux méthodes dans leurs fichiers de classe. Ces méthodes sont:

  • private writeObject (ObjectOutputStream out) émet une exception IOException;
  • readObject privé vide (ObjectInputStream dans) lève IOException, ClassNotFoundException;

Dans cette méthode, vous pouvez le sérialiser sous d’autres formes, par exemple ArrayList for Location que vous avez illustré ou JSON ou un autre format / méthode de données et le reconstruire sur readObject ().

Avec votre exemple, vous ajoutez le code suivant:

 private void writeObject(ObjectOutputStream oos) throws IOException { // default serialization oos.defaultWriteObject(); // write the object List loc = new ArrayList(); loc.add(location.x); loc.add(location.y); loc.add(location.z); loc.add(location.uid); oos.writeObject(loc); } private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException { // default deserialization ois.defaultReadObject(); List loc = (List)ois.readObject(); // Replace with real deserialization location = new Location(loc.get(0), loc.get(1), loc.get(2), loc.get(3)); // ... more code } 

Semblable à la réponse de @momo mais sans utiliser de valeurs de type List et int qui le rendront beaucoup plus compact.

 private void writeObject(ObjectOutputStream oos) throws IOException { // default serialization oos.defaultWriteObject(); // write the object oos.writeInt(location.x); oos.writeInt(location.y); oos.writeInt(location.z); oos.writeInt(location.uid); } private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException { // default deserialization ois.defaultReadObject(); location = new Location(ois.readInt(), ois.readInt(), ois.readInt(), ois.readInt()); // ... more code } 

S’il doit s’agir d’une sérialisation Java, la seule façon de le savoir est de redéfinir readObject() et writeObject() dans toutes les classes ayant une référence à une instance de Location comme indiqué dans la réponse de Momo. Notez que cela ne vous permettra pas de sérialiser un Location[] et vous obligera à sous-classer toutes les Collection apparaissant dans votre code. De plus, il faut que les champs de type Location soient marqués comme transitoires, ce qui empêchera leurs définitions d’être écrites dans le stream de sérialisation, empêchant éventuellement la détection de modifications de classes incompatibles.

Un meilleur moyen serait de simplement remplacer ObjectOutputStream.writeObject . Hélas, cette méthode est final . Vous pouvez remplacer ObjectOutputStream.writeObjectOverride() place, mais cette méthode ne peut pas déléguer l’implémentation par défaut, ObjectOutputStream.writeObject0() car cette méthode est private . Bien sûr, vous pouvez appeler la méthode privée en utilisant la reflection, mais …

Par conséquent, je vous recommande de vérifier vos contraintes. Doit-il s’agir d’une sérialisation Java? Pouvez-vous vraiment ne pas changer la définition de la classe Location ?

Si vous avez le code source dans la classe Location , il est assez sortingvial d’append des implements Serializable et de les append à votre classpath. Oui, vous devrez recommencer à chaque fois que vous mettez à niveau la bibliothèque, mais cela peut être mieux que l’alternative …