61 votes

Sérialisation personnalisée Java

J'ai un objet qui contient quelques champs non sérialisables que je veux sérialiser. Ils proviennent d'une API distincte que je ne peux pas modifier. Par conséquent, les rendre Serializable n'est pas une option. Le problème principal est la classe Location. Il contient quatre éléments pouvant être sérialisés dont j’aurais besoin, tous les éléments. Comment puis-je utiliser read / writeObject pour créer une méthode de sérialisation personnalisée pouvant effectuer quelque chose comme ceci:

 // writeObject:
List<Integer> loc = new ArrayList<Integer>();
loc.add(location.x);
loc.add(location.y);
loc.add(location.z);
loc.add(location.uid);
// ... serialization code

// readObject:
List<Integer> 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?

63voto

momo Points 7728

Java supporte la Sérialisation Personnalisée. Lisez la section Personnaliser le Protocole par Défaut.

Pour citer:

Il est, cependant, un étrange encore astucieux solution. Par l'aide d'un fonctionnalité du mécanisme de sérialisation, les développeurs peuvent améliorer la processus normal par le biais de deux méthodes à l'intérieur de leurs fichiers de classe. Ces méthodes sont:

  • private void writeObject(ObjectOutputStream out) throws IOException;
  • private void readObject(ObjectInputStream en) throws IOException, ClassNotFoundException;

Dans cette méthode, ce que vous pourriez faire est de sérialiser dans d'autres formes si vous avez besoin tels que la liste de tableaux pour l'Emplacement que vous illustrés ou JSON ou d'un autre format des données/méthode et de le reconstruire à l'arrière sur les méthodes 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

}

33voto

Peter Lawrey Points 229686

Semblable à la réponse de @ momo mais sans utiliser une liste et des valeurs int automatiques, ce qui le rendra 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

}
 

0voto

meriton Points 30447

Si elle doit être la sérialisation Java, la seule façon que je connaisse est de redéfinir l' readObject() et writeObject() dans toutes les classes ayant une référence à une instance d' Location comme indiqué dans la réponse de Momo. Notez que cela ne vous permettra pas de sérialiser un Location[], et vous obliger à la sous-classe tous Collection<Location> figurant dans votre code. En outre, il exige que les champs de type Location à être marqué transitoire, ce qui permettra d'exclure leurs définitions sur la sérialisation des flux, de la possible de déjouer la détection de l'incompatibilité des changements de classe.

Une meilleure façon est de simplement remplacer ObjectOutputStream.writeObject. Hélas, cette méthode est - final. Vous pourriez remplacer ObjectOutputStream.writeObjectOverride() au lieu de cela, mais cette méthode ne peut pas déléguer la mise en œuvre par défaut, ObjectOutputStream.writeObject0() , car cette méthode est - private. Bien sûr, vous pouvez appeler la méthode privée à l'aide de la réflexion, mais ...

Par conséquent, je vous recommandons de vérifier vos contraintes. A-t-elle à la sérialisation Java? Pouvez-vous vraiment pas changer la définition de la classe Location?

Si vous avez le code source de la classe Location, il est assez facile d'ajouter implements Serializable et l'ajouter à votre classpath. Oui, vous aurez à le faire à nouveau en cas de mise à niveau de la bibliothèque, mais il pourrait être mieux que l'alternative ...

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X