2009-07-07 7 views
3

Je suis confronté à quelques problèmes lors de la sérialisation des objets (j'utilise JBoss Drools, et je veux stocker une ArrayList de KnowledgePackage).ce qui pourrait modifier le SerialVersionUID tout en sérialisant et en stockant dans un Jarfile?

Lorsque je sérialise la liste, stocke le résultat dans un fichier et le désérialise, aucun problème ne se produit, donc cela fonctionne correctement.

Mais quand je sérialiser la liste, stocker le résultat dans un flux d'octets, puis enregistrez-le dans un fichier Jar, je ne peux pas alors désérialiser le résultat, en raison de cette erreur:

IOException during package import : java.util.ArrayList; local class incompatible: stream classdesc serialVersionUID = 8664875232659988799, local class serialVersionUID = 8683452581122892189 

Je pense donc la question est quand je sauve l'objet sérialisé dans une entrée Jarfile. Je pense que je fais cela correctement, car d'autres fichiers sauvegardés de la même manière dans le Jarfile peuvent être lus correctement. Et après avoir utilisé 'cmp' et 'hexdump', j'ai repéré que le sauver un pot provoque une variation d'un octet si l'uuid, sinon le contenu est le même.

Je suis vraiment déçu et ne peux pas indiquer où le problème peut être.

Que peut modifier le SerialVersionUID entre deux classes? autre qu'une autre version de vm?


ajouter le code source: exportToJar -> writeRulesPackageEntry -> writeEntry

/** 
* Writes content provided from a reader into a file contained in a jar. 
* 
* @param output the output stream to write on 
* @param entryName the name of the file that will contain reader data 
* @param contentReader 
* 
* @return the zip entry that has been created into the jar 
*/ 
ZipEntry writeEntry(JarOutputStream output, String entryName, ByteArrayInputStream input) { 
    if (output == null || entryName == null || entryName.trim().length() == 0 || input == null) { 
     throw new NullPointerException("Null argument passed"); 
    } 

    ZipEntry entry = new ZipEntry(entryName); 
    byte[] buffer = new byte[BUFFER_LENGTH]; 

    try { 
     output.putNextEntry(entry); 
     int nRead; 

     while ((nRead = input.read(buffer, 0, BUFFER_LENGTH)) > 0) { 
      output.write(buffer, 0, nRead); 
     } 

     output.closeEntry(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 

    return entry; 
} 

/** 
* Export rules files to a serialized object (ArrayList<KnowledgePackage>) into 
* an output stream, then write the output content as an entry of a jar. 
* 
* @param os the output jar to write in 
*/ 
void writeRulesPackageEntry(JarOutputStream os) { 
    // serialize objects and write them to the output stream 
    ByteArrayOutputStream output = new ByteArrayOutputStream(); 
    RulesPackaging rulesPackaging = new RulesPackaging(); 
    rulesPackaging.exportResources(this.rules, output); 

    // create a new input stream to read written objects from 
    ByteArrayInputStream input = new ByteArrayInputStream(output.toByteArray()); 
    this.writeEntry(os, Product.ENTRY_RULES_PACKAGE, input); 
} 

/** 
* Creates a JarFile containing resources. 
* 
* @param filename the exported jar filename 
* @return the jar as an object, null if an error occured 
*/ 
public JarFile exportToJar(String filename) { 
    FileOutputStream fOs; 
    JarOutputStream jOs; 
    JarFile jar = null; 

    try { 
     fOs = new FileOutputStream(filename); 
     jOs = new JarOutputStream(fOs); 

     this.writeRulesPackageEntry(jOs); 

     jOs.close(); 

     // construct a jar from the output jar 
     jar = new JarFile(new File(filename)); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 

    return jar; 
} 
+0

Ceci n'a rien à voir avec uuid qui est un sujet complètement séparé; J'ai édité votre question –

+0

à droite, je me suis confondu avec serialVersionUID et UUID. Merci pour l'édition. – ipingu

Répondre

3

Le serialVersionUID ne change pas. C'est un static final affecté au moment de la compilation (basé sur un hachage du code source, je pense) à moins qu'une valeur ne soit explicitement assignée dans le code source.

Il y a un peu plus à ce sujet ici http://mindprod.com/jgloss/serialization.html.

serialVersionUID pour java.util.ArrayList est 8683452581122892189L, qui est affecté explicitement dans le code source et est resté le même depuis que la classe a été introduite en 1.2.

Comme vous l'avez dit, il est très probable que l'erreur survienne lors de l'envoi d'un octet dans le JarFile - veuillez écrire le code que vous utilisez pour cela.

après le code CONT'D source a été publié

Je soupçonne que le problème réside dans l'utilisation du java.io.InputStreamReader.

De l'JavaDoc:

Un InputStreamReader est un pont de flux d'octets à des flux de caractères: Il lit les octets et les décode en caractères en utilisant un jeu de caractères spécifié. Le jeu de caractères utilisé peut être spécifié par son nom ou peut recevoir explicitement , ou le jeu de caractères par défaut de la plateforme peut être accepté.

Dès que je vois des jeux de caractères impliqués dans non-texte, je les ruisseaux se méfiant toujours parce qu'il est possible pour le flux à modifier lors du décodage est une séquence d'octets ne correspond pas à un personnage dans le caractère ensemble (vu ces petits caractères carrés qui se produisent lorsque des problèmes d'encodage se produisent). Je voudrais essayer de lire les octets tout de suite le java.io.ByteArrayInputStream que vous envelopper avec le java.io.InputStreamReader dans writeRulesPackageEntry(JarOutputStream). La conversion en char[] n'est pas nécessaire.

+0

Source a été modifiée et mise à jour, après votre idée. J'ai toujours le problème. Je vais essayer ce soir d'isoler plus le problème, je ne m'attendais pas à avoir ce genre de problèmes, je vais en lire plus sur les flux byte et char avant de faire des choses plus dangereuses. Merci d'aider) – ipingu

+0

Juste pour essayer d'isoler le problème avez-vous essayé de désérialiser de la java.io.ByteArrayInputStream? –

+0

Damné, j'ai été rapide dans mon essai. Ma classe de test qui reposait sur le Jar créé pour voir si elle était cohérente et utilisable n'était pas dans le même module, j'ai oublié de mettre à jour la dépendance ... Donc votre idée m'a définitivement aidé! Merci beaucoup, je vais rappeler de ne pas jouer avec char & bytes ... Problème résolu, ne pas encapsuler le byteArrayInputStream dans un InputStreamReader (avec n'est pas fiable pour les données de byte, mais char seulement) – ipingu

0

Comme Nick propose, le problème est probablement que vous ne traitez pas le flux comme des octets (qui ne sont jamais modifiés), mais comme des caractères (qui peuvent l'être). Cela dit, une autre ressource décente sur la sérialisation est un chapitre dédié d'un livre que j'ai écrit il y a un million d'années (1997), "Mastering JavaBeans". Heureusement, le chapitre 11, Sérialisation, est aussi pertinent aujourd'hui qu'il l'était alors. Télécharger les fichiers PDF gratuits à partir de http://ccd.uab.es/~srobles/manuals/JavaBeans

+0

Je vais lire votre pdf ce soir, merci pour la ressource. – ipingu

0

Y a-t-il une chance qu'une version antérieure ait été sérialisée dans JarFile, et les tentatives de sérialisation suivantes ne parviennent pas à l'écraser? Ensuite, vous récupérerez les données sérialisées d'une version antérieure de la classe, ce qui jetterait (correctement) l'erreur "incompatible". La raison pour laquelle je demande, c'est que j'ai vu des messages d'erreur similaires en utilisant mon système de mise en cache de choix (EHCache) quand j'ai mis à jour une classe sérialisée sans avoir abandonné l'ancien cache persistant.

+0

Ce serait certainement le cas, mais la classe à laquelle il échoue est java.util.ArrayList, qui à ma connaissance a eu le même serialVersionUID depuis son introduction en 1.2. –

Questions connexes