# Problem beim serialisieren/deserialisieren einer ArrayList



## Angel4585 (8. Jan 2009)

Hallo,

ich habe folgende Struktur:

eine Klasse SFMatch welche zwei Objekte vom Typ SFTeam beinhaltet.
Jedes SFTeam wiederum beinhaltet eine ArrayList<SFPlayer> .
SFMatch, SFTeam sowie SFPlayer haben das Interface Serializable implementiert.
die serialVersionUID ist auch jeweils vergeben.

Wenn ich nun mit folgenden Methoden ein SFMatch Objekt in einen String speichere und wieder auslese bekomme ich folgenden Fehler:

Die Methoden:


```
public static String getSerializedMatch(SFMatch match)throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream objOut = new ObjectOutputStream(baos);
        objOut.writeObject(match);
        objOut.close();
        return baos.toString();
    }

    public static SFMatch setSerializedMatch(String match)throws IOException, ClassNotFoundException {
        ByteArrayInputStream bais = new ByteArrayInputStream(match.getBytes());
        ObjectInputStream objIn = new ObjectInputStream(bais);
        return (SFMatch)objIn.readObject();
    }
```

Der Fehler:

java.io.InvalidClassException: java.util.ArrayList; local class incompatible: stream classdesc serialVersionUID = 8664875232659988799, local class serialVersionUID = 8683452581122892189
        at java.ibjectStreamClass.initNonProxy(ObjectStreamClass.java:562)
        at java.ibjectInputStream.readNonProxyDesc(ObjectInputStream.java:1583)
        at java.ibjectInputStream.readClassDesc(ObjectInputStream.java:1496)
        at java.ibjectInputStream.readOrdinaryObject(ObjectInputStream.java:1732)
        at java.ibjectInputStream.readObject0(ObjectInputStream.java:1329)
        at java.ibjectInputStream.defaultReadFields(ObjectInputStream.java:1945)
        at java.ibjectInputStream.readSerialData(ObjectInputStream.java:1869)
        at java.ibjectInputStream.readOrdinaryObject(ObjectInputStream.java:1753)
        at java.ibjectInputStream.readObject0(ObjectInputStream.java:1329)
        at java.ibjectInputStream.defaultReadFields(ObjectInputStream.java:1945)
        at java.ibjectInputStream.readSerialData(ObjectInputStream.java:1869)
        at java.ibjectInputStream.readOrdinaryObject(ObjectInputStream.java:1753)
        at java.ibjectInputStream.readObject0(ObjectInputStream.java:1329)
        at java.ibjectInputStream.readObject(ObjectInputStream.java:351)
        at sfgame.data.SFMatch.setSerializedMatch(SFMatch.java:37)
        at sfgame.SFCalc.main(SFCalc.java:26)


ich mache das Ganze in NetBeans , compiliere, führe aus, serialisiere, und deserialisiere den String direkt wieder.
Wenn ich die ArrayList weglasse geht es ohne Probleme, die Spieler sind dann halt nicht dabei.
Wenn ich nur ArrayList deklariere ohne SFPlayer kommt der gleiche Fehler.

Kann mir jemand sagen was ich da falsch mache?


----------



## SlaterB (8. Jan 2009)

ich hab mal bisschen bei google geschaut (nur 8664875232659988799 eintippen, da ich weiß, dass 8683452581122892189 die richtige Id ist  )

http://forums.sun.com/thread.jspa?threadID=698782&start=0
->
http://forums.sun.com/thread.jspa?threadID=630143&messageID=3627417
->


> You're actually corrupting the serialized form by converting from a stream of bytes into a String, and then back again.
> 
> As a general rule, you cannot convert a random array of bytes into a String and back again and expect to have what you started with. In your particular case, it's altered the serialization identifier for the ArrayList class, but there's no predicting what it might do.
> 
> ...


hätte ich auch selber sehen können..


----------



## Angel4585 (9. Jan 2009)

ahhh sehr gut, das funzt: 


```
public static byte[] getSerializedMatch(SFMatch match)throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream objOut = new ObjectOutputStream(baos);
        objOut.writeObject(match);
        return baos.toByteArray();
    }

    public static SFMatch setSerializedMatch(byte[] match)throws IOException, ClassNotFoundException {
        ByteArrayInputStream bais = new ByteArrayInputStream(match);
        ObjectInputStream objIn = new ObjectInputStream(bais);
        return (SFMatch)objIn.readObject();
    }
```
Wird halt nicht mit nem String gearbeitet


----------



## Spacerat (10. Jan 2009)

Wenns denn unbedingt ein String werden soll, ist die "toString()"-Methode des ByteArrayOutputStreams die falsche Wahl. Diese erstellt den String nämlich durch folgenden Konstruktor dieser Klasse:

```
... Klasse String Auszug
    public String(byte bytes[], int offset, int length) {
        checkBounds(bytes, offset, length);
        char[] v  = StringCoding.decode(bytes, offset, length);
        this.offset = 0;
        this.count = v.length;
        this.value = v;
    }
```
Dort erfolgt zur Bildung des char-Arrays wiederum ein Aufruf zu "StringCoding.decode()". Dadurch werden meistens einige Bytes "verfälscht", damit sie für die voreingestellte Location lesbar werden. Das ist für Strings, die Binärdaten enthalten natürlich völlig inakzeptabel. Deswegen muß das byte-Array vorher von Hand in ein char-Array umgewandelt werden und damit anschliessend der String erstellt werden. Etwa so:

```
byte[] b = baos.toByteArray();
char[] c = new char[b.length];
for(int n = 0; n < b.length; n++) c[n] = (char) (b[n] & 0xFF);
return new String(c);
```
Für das Wiedereinlesen in ein Objekt kann man die "getBytes()"-Methode dann ebenfalls vergessen, da dort "StringCoding.encode()" verwendet wird. Deswegen muß Analog zum Schreiben, das char-Array geholt und in ein byte-Array gewandelt werden.

mfg Spacerat


----------

