Comment exclure du champ de la classe de sérialisation dans runtime?
Comment exclure champ de la classe de processus de sérialisation dans runtime ?
Il est transitoire modificateur pour la compilation, mais qu'en exécution ?
Je veux dire commune de sérialisation java avec ObjectOutputStream, pas gson ou quelque chose.
Désolé, je crois que je n'ai pas d'expliquer à droite. Ce n'est pas exactement sur la sérialisation , mais sur de-sérialisation. J'ai des lots de fichiers existants et de les gérer comme ceci:
public class Deserialize {
/**
* @param args
* @throws IOException
* @throws ClassNotFoundException
*/
public static void main(String[] args) throws ClassNotFoundException, IOException {
File file = new File("/home/developer/workspace/DDFS/some.ddf");
HackedObjectInputStream in = new HackedObjectInputStream(new GZIPInputStream(new FileInputStream(file)));
System.out.println("Attempt to open " + file.getAbsolutePath());
Object obj = in.readObject();
in.close();
}
static class HackedObjectInputStream extends ObjectInputStream
{
/**
* Migration table. Holds old to new classes representation.
*/
private static final Map<String, Class<?>> MIGRATION_MAP = new HashMap<String, Class<?>>();
static
{
MIGRATION_MAP.put("DBOBExit", Exit.class);
}
/**
* Constructor.
* @param stream input stream
* @throws IOException if io error
*/
public HackedObjectInputStream(final InputStream stream) throws IOException
{
super(stream);
}
@Override
protected ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException
{
ObjectStreamClass resultClassDescriptor = super.readClassDescriptor();
for (final String oldName : MIGRATION_MAP.keySet())
{
if (resultClassDescriptor.getName().equals(oldName))
{
resultClassDescriptor = ObjectStreamClass.lookup(MIGRATION_MAP.get(oldName));
}
}
return resultClassDescriptor;
}
}
}
Ce code fonctionne très bien pour la plupart des fichiers , mais certains fichiers jette
Exception in thread "main" java.lang.ClassCastException: cannot assign instance of java.awt.Polygon to field Exit.msgbackPt of type java.awt.Point in instance of Exit
at java.io.ObjectStreamClass$FieldReflector.setObjFieldValues(ObjectStreamClass.java:2053)
en raison des différentes versions de la Sortie de la classe . La nouvelle version a de nouveaux champs.
Erreur disparaît lorsque j'ajoute transitoire à de nouveaux champs, mais un autre des fichiers commence à lancer une exception (fichiers les plus récents).
Je peux donc ajouter transitoire de ces nouveaux champs dans l'exécution si j'détecter les anciens serilized fichier ?
Peut-être que la réflexion ou quelque chose ?
- Vous devez soit mettre en œuvre
writeObject()
etreadObject()
vous-même, ou peut-être utiliserExternalizable
au lieu deSerializable
qui est censé vous donner le plein contrôle sur le processus: docs.oracle.com/javase/7/docs/platform/serialization/spec/... (et d'autres parties de cette spécification.) Notez cependant que vous devrez probablement correctement dé-sérialiser l'ensemble de votre classe, et que vous devrez gérer de déterminer quels sont les domaines que vous avez écrit lors de la sérialisation quand deserialising. (En écrivant un tas de drapeaux ou avant les données.) - Pourquoi? Ce qui est censé arriver à l'autre bout?
- En regardant les edit: je pense que vous avez votre travail de vous. Builtin de la sérialisation est un vraiment, vraiment maladroit choix si vous souhaitez persister vos données et de faire évoluer son schéma.
- J'ai trouvé la solution de façon simple stackoverflow.com/a/14608062/1085787
Vous devez vous connecter pour publier un commentaire.
La la documentation de ObjectOutputStream dit:
Lorsque vous déclarez une variable comme transitoire, il doit être ignoré par ObjectOutputStream. Assurez-vous que vous utilisez le
transient
mot clé et non un@Transient
annotation. Ces annotations sont utilisées par certains frameworks ORM pour marquer les champs qui ne sont pas censés être enregistrées dans des bases de données. Ils sont vides de sens pour le bâtiment de la sérialisation cadre.Vous pouvez utiliser le 'transitoire' modificateur:
http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.3.1.3
La représentation sérialisée d'une classe spécifique à la classe elle-même, vous ne pouvez pas changer de l'extérieur, le plus proche que vous pouvez obtenir est de définir une sous-classe avec la sérialisation personnalisée de comportement, mais qui n'affecte que les objets de cette sous-classe, les objets du type parent.
Si vous ne pouvez pas modifier la classe en question à tous, alors votre seule option est de la sous-classe ObjectOutputStream et remplacer
replaceObject
pour remplacer l'objet de problème lors de l'écriture du temps avec une autre qui contient uniquement les données que vous souhaitez, et le miroir de l'image du processus à un temps de lecture (sous-classe ObjectInputStream et remplacerresolveObject
).writeObject()
ouwriteReplace()
.Vous êtes à creuser le mauvais trou ici. Au lieu de messagerie autour avec de l'exécution des décisions sur les champs à sérialisé et dominante readClassDescriptor(), vous devriez chercher à passer outre readResolve().