# Problem mit Serializable --> serialVersionUID



## jorgeHX (11. Juni 2007)

Hallo zusammen,
ich hab ein Problem mit dem Serializable.

Ich habe eine Import und Exportfunktion geschrieben, die auch soweit läuft. Allerdings tritt beim Importieren ein Fehler auf, wenn ich eine Datei von einer älteren Version in die neueste Version importieren möchte.


```
ava.io.InvalidClassException: import_export.objekte.Baum; local class incompatible: stream classdesc serialVersionUID = 8191912955886397793, local class serialVersionUID = 4087753089674047772
```

Wie kann ich diesen Fehler umgehen? Ich hab es schon mit 


```
static final long serialVersionUID = 4087753089674047772L;
```

versucht. Leider ohne Erfolg. Darüberhinaus will ich es lieber nicht statisch zuweisen, sondern eher jede VersionUID zulassen, solange das zu importierende Format stimmt.
Kann mir da jemand weiterhelfen? Hat jemand ein Beispiel?

Vielen Dank,
JP


----------



## jorgeHX (11. Juni 2007)

Niemand einen Idee?

Ich muss es noch heute irgendwie hinbekommen...

Danke


----------



## Thomas Darimont (11. Juni 2007)

Hallo,

das Problem hier ist, dass du versuchst alte Klassendefinition (altere SerialVersionId) mit einer neuen zu matchen... man sollte die SerialVersionId nur dann ändern, wenn man neue Attribute zu einer Klasse hinzugefügt bzw. geändetr hat. Sonst bekommt man schnell inkompatibilitäten 8wie in deinem Beispiel zu sehen). Das ist ein Problem der klassischen Objekt-Serialisierung in Java. Ich würde dir Raten die Daten in XML zu Exportieren/Importieren. Dann hast du keine solchen Probleme... (bzw. andere Probleme) ;-) Um die alten Daten zu migrieren würde ich mir (in einem separatem Projekt) die alten Objekte wieder deserialiseren (sprich Domain Klassen mit Kompatiblen SerialVersionId ausstatten) und einlesen. Dann entsprechend in einem anderen Format (XML) serialiseren.
Das gleiche macht man mit den aktuellen Daten. Anschließend benutzt man nur noch die XML basierte Serialisierung für Import / Export.

Gruß Tom


----------



## jorgeHX (11. Juni 2007)

Moin Thomas,
gibt es nicht noch ne andere Variante wie ich das regeln kann? Ich habe nämlich schon viele Dateien von der alten Version exportiert und will die nun wieder importieren. Allerdings kommt die bekannte Fehlermeldung.

Kann man nicht irgendwie "readObject()" überschreiben, so dass die VersionsUID nicht mehr geprüft wird beim importieren?

Ich hab allerdings keine Ahnung wie das gehen könnte :-(

Grüße,
JP


----------



## jorgeHX (12. Juni 2007)

Kann mir jemand verraten, warum es nicht funktioniert, wenn ich


```
static final long serialVersionUID = 4087753089674047772L;
```

vorab definiere? Gibt es generell die Möglichkeit die serialVersionUID während der laufzeit zu verändern?

Schon jetzt vielen Dank,
JP


----------



## Thomas Darimont (12. Juni 2007)

Hallo,

ändern könnte man die schon zur Laufzeit über Reflection, aber dann gäbs unter umständen Probleme wenn du zwischendurch Elemente mit einer anderen SerialVersionId laden willst... da müsstest du jedes mal umswitchen, oder für jede Klassen Version einen eigenen ClassLoader verwenden, so dass du unterschiedliche Versionen / Repräsentationen der Klasse gleichzeitig Laden kannst... das macht die Arbeit damit aber sehr kompliziert.... wie gesagt ich würde die alten Objekte einfach wieder einlesen (einfach SerialiVersionId auf den alten wert setzen und diese wieder in einem evolutionsfreundlicherem Format (XML) abspeichern).

Gruß Tom


----------



## jorgeHX (12. Juni 2007)

Ähm, wie meinst du das mit dem einlesen. Wenn ich das Object einlese, kommt direkt die oben gezeigte Fehlermeldung.
Ich würde ja gerne die alte Datei einlesen und dann einfach die alte ID ignorieren. Geht das nicht einfach? 

Sorry, wenn die Frage dumm klingt 

Grüße


----------



## zerix (12. Juni 2007)

Hallo,

also wenn ich Tom richtig verstanden habe, sollst du einfach in deiner Klasse die SerialVersionUID wieder zurück auf den alten Wert setzen, die alten Objecte dann auslesen und mit der von ihm genannten API wieder abspeichern und so hättest du das Problem aus der Welt geschafft.

MFG

zEriX


----------



## Thomas Darimont (12. Juni 2007)

Hallo,

alte version:

```
/**
 * 
 */
package de.tutorials;

import java.io.Serializable;

/**
 * @author Thomas.Darimont
 *
 */
public class SerializableObject implements Serializable{
    /**
     * 
     */
    private static final long serialVersionUID = 37289463820437L;
    
    int intValue;
    String stringValue;
    
    
    
    
    /**
     * 
     */
    public SerializableObject() {
        super();
        // TODO Auto-generated constructor stub
    }
    /**
     * @param intValue
     * @param stringValue
     */
    public SerializableObject(int intValue, String stringValue) {
        super();
        this.intValue = intValue;
        this.stringValue = stringValue;
    }
    /**
     * @return the intValue
     */
    public int getIntValue() {
        return intValue;
    }
    /**
     * @param intValue the intValue to set
     */
    public void setIntValue(int intValue) {
        this.intValue = intValue;
    }
    /**
     * @return the stringValue
     */
    public String getStringValue() {
        return stringValue;
    }
    /**
     * @param stringValue the stringValue to set
     */
    public void setStringValue(String stringValue) {
        this.stringValue = stringValue;
    }
    
    @Override
    public String toString() {
        return this.intValue +" " + this.stringValue;
    }
}
```

Serialisieren / Deserialisieren:

```
/**
 * 
 */
package de.tutorials;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

/**
 * @author Thomas.Darimont
 * 
 */
public class SerialVersionIdIgnoringObjectInputStreamExample {

    /**
     * @param args
     */
    public static void main(String[] args) throws Exception {
        File objectStore = new File("c:/objectStore.ser");
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(
                new FileOutputStream(objectStore));
        objectOutputStream.writeObject(new SerializableObject(4711, "bubu"));
        objectOutputStream.close();

        ObjectInputStream objectInputStream = new ObjectInputStream(
                new FileInputStream(objectStore));
        SerializableObject serializableObject = (SerializableObject) objectInputStream
                .readObject();
        objectInputStream.close();
        System.out.println(serializableObject);

    }

}
```

Ausgabe:

```
4711 bubu
```

Neue Version:

```
/**
 * 
 */
package de.tutorials;

import java.io.Serializable;

/**
 * @author Thomas.Darimont
 *
 */
public class SerializableObject implements Serializable{
    /**
     * new
     */
    private static final long serialVersionUID = -6518072243425999514L;
    
    /**
     * old 
     */
    //private static final long serialVersionUID = 37289463820437L;
    
    
    int intValue;
    String stringValue;
    double doubleValue;
    
    
    
    
    /**
     * 
     */
    public SerializableObject() {
        super();
        // TODO Auto-generated constructor stub
    }
    /**
     * @param intValue
     * @param stringValue
     */
    public SerializableObject(int intValue, String stringValue) {
        super();
        this.intValue = intValue;
        this.stringValue = stringValue;
    }
    
    /**
     * @param intValue
     * @param stringValue
     * @param doubleValue
     */
    public SerializableObject(int intValue, String stringValue,
            double doubleValue) {
        super();
        this.intValue = intValue;
        this.stringValue = stringValue;
        this.doubleValue = doubleValue;
    }
    /**
     * @return the intValue
     */
    public int getIntValue() {
        return intValue;
    }
    /**
     * @param intValue the intValue to set
     */
    public void setIntValue(int intValue) {
        this.intValue = intValue;
    }
    /**
     * @return the stringValue
     */
    public String getStringValue() {
        return stringValue;
    }
    /**
     * @param stringValue the stringValue to set
     */
    public void setStringValue(String stringValue) {
        this.stringValue = stringValue;
    }
    /**
     * @return the doubleValue
     */
    public double getDoubleValue() {
        return doubleValue;
    }
    /**
     * @param doubleValue the doubleValue to set
     */
    public void setDoubleValue(double doubleValue) {
        this.doubleValue = doubleValue;
    }

    @Override
    public String toString() {
        return this.intValue +" " + this.stringValue + " " + this.doubleValue;
    }
    
}
```

Diesmal nur auslesen:

```
/**
 * 
 */
package de.tutorials;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

/**
 * @author Thomas.Darimont
 * 
 */
public class SerialVersionIdIgnoringObjectInputStreamExample {

    /**
     * @param args
     */
    public static void main(String[] args) throws Exception {
        File objectStore = new File("c:/objectStore.ser");
//        ObjectOutputStream objectOutputStream = new ObjectOutputStream(
//                new FileOutputStream(objectStore));
//        objectOutputStream.writeObject(new SerializableObject(4711, "bubu"));
//        objectOutputStream.close();

        ObjectInputStream objectInputStream = new ObjectInputStream(
                new FileInputStream(objectStore));
        SerializableObject serializableObject = (SerializableObject) objectInputStream
                .readObject();
        objectInputStream.close();
        System.out.println(serializableObject);

    }

}
```

Ergibt:

```
Exception in thread "main" java.io.InvalidClassException: de.tutorials.SerializableObject; local class incompatible: stream classdesc serialVersionUID = 37289463820437, local class serialVersionUID = -6518072243425999514
    at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:562)
    at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1583)
    at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1496)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1732)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:351)
    at de.tutorials.SerialVersionIdIgnoringObjectInputStreamExample.main(SerialVersionIdIgnoringObjectInputStreamExample.java:31)
```

Setzt man nun die SerialVersionId des SerializableObjects wieder auf die alte Id:
    /**
     * new
     */
    //private static final long serialVersionUID = -6518072243425999514L;

    /**
     * old 
     */
    private static final long serialVersionUID = 37289463820437L;

So kann man die alten Objekte wieder deserialisieren.


```
4711 bubu 0.0
```
Jedoch bleiben dann die neuen Attribute (die damals nicht mitserialisiert wurden) mit ihren default Werten initialisiert. Das wär dann mal eine Möglichkeit die Daten für eine Migration wieder einzulesen ...



> also wenn ich Tom richtig verstanden habe, sollst du einfach in deiner Klasse die SerialVersionUID wieder zurück auf den alten Wert setzen, die alten Objecte dann auslesen und mit der von ihm genannten API wieder abspeichern und so hättest du das Problem aus der Welt geschafft.


So ganz unproblematisch ist dieser Ansatz nicht... die SerialVersionId ist eine Art hashCode einer serialisierbaren Klasse wenn man ander Klasse was ändert sollte man auch die SerialVersionId neu erstellen. Binärkompatibilität sollte man eher auf einem anderen Level erreichen...

Gruß Tom


----------



## jorgeHX (12. Juni 2007)

Hallo,
erstmal danke für das Beispiel. 

Gibt es denn in Java auch eine Methode um aus einer File f die SerialVersionUID auszulesen?

Das würde mir nämlich am ehesten weiterhelfen.

Danke vielmals,
JP


----------



## Thomas Darimont (12. Juni 2007)

Hallo,

na klar: serialver
http://java.sun.com/javase/6/docs/technotes/tools/windows/serialver.html

Gruß Tom


----------



## jorgeHX (12. Juni 2007)

Hi,
also ID kann ich jetzt von der aktuellen Klasse lesen. 
Wie schaffe ich es allerdings die VersionsID von der gespeicherten Datei zu lesen?
Das ist ja mein Hauptproblem.
Schon jetzt danke für die Hilfe. ich weiß es zu schätzen,
JP


----------



## Thomas Darimont (12. Juni 2007)

Hallo,

ganz spontan würd ich sagen...  einfach versuchen einzulesen und schauen was in der Exception steht...

Gruß Tom


----------



## jorgeHX (12. Juni 2007)

also die exception gibt mir immer das gleich aus. Z.b.

```
java.io.InvalidClassException: import_export.objekte.Spieler; local class incompatible: stream classdesc serialVersionUID = 4087753089674047772, local class serialVersionUID = 4242541931837216997

	at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:519)

	at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1546)

	at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1460)

	at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1693)

	at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1299)

	at java.io.ObjectInputStream.readObject(ObjectInputStream.java:339)

	at import_export.Importierer.leseObjekte(Importierer.java:113)
```

Kannst du damit was anfangen


----------



## jorgeHX (12. Juni 2007)

Die Problematik ist ja, dass ich die Methode readObject() angesprochen wird u. die Kontrolliere ich ja nicht.
Irgendwie erhalte ich nie die VersionsID die mir in der Fehlermeldung als alte ID angepriesen wird.
Welches Objekt muss ich denn für die alte Datei ansprechen, um dessen ID zu erhalten?


----------

