cosa potrebbe modificare SerialVersionUID durante la serializzazione e l'archiviazione in un Jarfile?

StackOverflow https://stackoverflow.com/questions/1092255

Domanda

Sto riscontrando alcuni problemi durante la serializzazione degli oggetti (sto utilizzando JBoss Drools e desidero archiviare un ArrayList di KnowledgePackage).

Quando serializzo l'elenco, memorizzo il risultato in un file e lo deserializzo, non si verifica alcun problema, quindi funziona correttamente.

Ma quando serializzo l'elenco, memorizzo il risultato in un flusso di byte, quindi lo salvo in un JarFile, non posso deserializzare il risultato, a causa di questo errore:

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

Quindi penso che il problema sia quando salvo l'oggetto serializzato in una voce Jarfile.Penso di farlo bene, perché altri file salvati allo stesso modo nel Jarfile possono essere letti correttamente.E dopo aver usato 'cmp' e 'hexdump', ho notato che salvandolo in un jar provoca una variazione di un ottetto se l'uuid, altrimenti il ​​contenuto è lo stesso.

Sono davvero deluso e non so dire dove possa essere il problema.

Cosa può modificare SerialVersionUID tra due classi?diverso da un'altra versione di VM?


aggiungendo il codice sorgente: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;
}
È stato utile?

Soluzione

IL serialVersionUID non cambia.È un static final assegnato al momento della compilazione (basato su un hash del codice sorgente, credo) a meno che un valore non venga assegnato esplicitamente nel codice sorgente.

C'è qualcosa in più a riguardo qui http://mindprod.com/jgloss/serialization.html.

Con l'eccezione che stai vedendo quello corretto serialVersionUID per java.util.ArrayList è 8683452581122892189L, che è assegnato esplicitamente nel codice sorgente ed è rimasto lo stesso da quando la classe è stata introdotta nella 1.2.

Come hai detto, è molto probabile che l'errore si verifichi durante il flusso di byte su JarFile: pubblica il codice che stai utilizzando per farlo.

Continua dopo la pubblicazione del codice sorgente

Sospetto che il problema risieda nell'uso del file java.io.InputStreamReader.

Dal JavaDoc:

Un InputStreamReader è un ponte dai flussi di byte ai flussi di caratteri:Legge byte e li decodifica in caratteri usando un chatset specificato.Il chatset che utilizza può essere specificato per nome o può essere dato esplicitamente o il chatset predefinito della piattaforma può essere accettato.

Appena vedo set di caratteri coinvolti in flussi non testuali mi insospettisco sempre perchéèpossibile che il flusso venga modificato durante la decodifica se una sequenza di byte non corrisponde a un carattere nel set di caratteri (visti quei quadratini caratteri che si verificano quando si verificano problemi di codifica).Proverei a leggere i byte direttamente dal file java.io.ByteArrayInputStream che stai avvolgendo con il java.io.InputStreamReader In writeRulesPackageEntry(JarOutputStream).La conversione in a char[] non è necessario.

Altri suggerimenti

Come propone Nick, molto probabilmente il problema è che non stai trattando il flusso come byte (che non vengono mai alterati), ma come caratteri (che possono esserlo).

Detto questo, un'altra risorsa decente sulla serializzazione è un capitolo dedicato di un libro che ho scritto un milione di anni fa (1997), "Mastering JavaBeans".Fortunatamente il capitolo 11, Serializzazione, è rilevante oggi come lo era allora.Scarica i PDF gratuiti da http://ccd.uab.es/~srobles/manuals/JavaBeans

Esiste la possibilità che una versione precedente sia stata serializzata nel JarFile e che i successivi tentativi di serializzazione non riescano a sovrascriverla?Quindi recupererai i dati serializzati di una versione precedente della classe, che (correttamente) genererebbe l'errore "incompatibile".

Il motivo per cui lo chiedo è che ho visto messaggi di errore simili utilizzando il mio sistema di memorizzazione nella cache preferito (EHCache) quando ho aggiornato una classe serializzata ma non ho eliminato la vecchia cache persistente.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top