# Serialisierung Document - java.io.InvalidClassException



## Stefan S. (29. Apr 2009)

Hallo,

ich habe derzeit ein Problem mit einem Dokument (javax.swing.text.Document), eigentlich ein DefaultStyledDocument, das ich serialisiere und woanders wieder deserialisiere - genauer gesagt wird es zunächst über ein Netzwerk übertragen. Leider wirft mir der Interpreter die folgende Exception mit der logischen Begründung:


```
local class incompatible: stream classdesc serialVersionUID = 940485415728594881, local class serialVersionUID = 940485415728614849
```

Wie man sieht sind die zwei UIDs leicht verschieden, weshalb ich die Exception bei der Deserialisierung erhalte.

Die Daten habe ich bereits über einen Sha256 laufen lassen um die Datenintegrität bei der Übertragung sicherzustellen. Beide Hashes waren erwartungsgemäß gleich.


```
Erster Hash: 24F6139C406CD060A60EA2828988125F2BDA8BDE7A1E86A049B2CD935EADEBF5

Zweiter Hash: 24F6139C406CD060A60EA2828988125F2BDA8BDE7A1E86A049B2CD935EADEBF5
```

Irgendwo scheint die UID zu variieren, eventuell macht der Compiler hier auch faxen, wobei die UID immer bei beiden gleich verschieden bleiben, also immer die oberen longs.

Hat jemand einen Typ für die Fehlersuche oder vielleicht einen anderen Rat woran das liegen könnte? Irgendwo fehlen fehlt die UID, eventuell gleich eine eigene writeObject Implementierung?


----------



## Wildcard (29. Apr 2009)

Die Java Version auf der einen Seite ist eine andere als auf der anderen Seite. Die beiden Classfiles haben eine andere UID und sind daher binär inkompatibel.


----------



## Stefan S. (29. Apr 2009)

Wildcard hat gesagt.:


> Die Java Version auf der einen Seite ist eine andere als auf der anderen Seite. Die beiden Classfiles haben eine andere UID und sind daher binär inkompatibel.



Hallo! 

Daran habe ich auch schon gedacht, aber das kann nicht sein. Ich habe die Netzwerkapplikationen unter *localhost*, verschiedene Ports getestet - mit demselben Resultat.

Logischerweise läuft bei mir auf dem Rechner nur eine, nämlich dieselbe Java Version.   

Auf der offiziellen Seite steht folgendes.



> Warning:  Serialized objects of this class will not be compatible with future Swing releases. The current serialization support is appropriate for short term storage or RMI between applications running the same version of Swing. As of 1.4, support for long term storage of all JavaBeansTM  has been added to the java.beans package. Please see XMLEncoder.



Wie gesagt, das kann hier nicht das Problem sein, weil ich es auf demselben Computer getestet habe.


----------



## SlaterB (29. Apr 2009)

auf einem Computer können mehrere Java-Versionen installiert sein,
startest du beide Programme gleichartig? (verschieden wäre z.B. einmal per IDE wie Eclipse + einmal per Konsole)

teste erstmal nur mit einem laufenden Programm, welches sowohl einen ServerSocket aufmacht als auch in einem separaten Thread den Client spielt


----------



## Stefan S. (29. Apr 2009)

SlaterB hat gesagt.:


> auf einem Computer können mehrere Java-Versionen installiert sein,
> startest du beide Programme gleichartig? (verschieden wäre z.B. einmal per IDE wie Eclipse + einmal per Konsole)
> 
> teste erstmal nur mit einem laufenden Programm, welches sowohl einen ServerSocket aufmacht als auch in einem separaten Thread den Client spielt



Hi,

ich habe die Java Versionen bereits getestet, die beiden Applikationen starten mit exakt derselben Version, nämlich 1.6.0_13.

Ich habe testweise beide Netzwerkkomponenten kompiliert, mit derselben IDE und anschließend ausgeführt um sicherzustellen das es auch dieselbe JDK ist, mit der beide Programme kompiliert wurden.

Egal ob ich beide mit Netbeans über F6 oder direkt über Konsole starte, ich erhalte stets denselben Fehler.

Die Deserialisierung funktioniert innehalb des eigenen Programmes fehlerfrei. Dort lässt sich der byte[] buffer wieder in ein DefaultStyledDocument Object deserialisieren.

Merkwürdig bleibt das die UID immer dieselben oben bleiben, selbst wenn ich ein drittes Sample Programm erstelle.

Die deserialisierten Bytes sind bei beiden Programmen identisch, die haben denselben Hash. Die Daten sind also einwandfrei.

Irgendwo macht mir die UID einen Strich durch die Rechnung.


----------



## Stefan S. (29. Apr 2009)

*Nachtrag:* Ich habe es jetzt tatsächlich mal einfach an mich selbst geschickt, also App über Socket an sich selbst und dann versucht zu serialisieren. Ich erhalte nun auch den Fehler bei der Deserialisierung. 

Wenn ich den serialiserten byte[] buffer aber gleich deserialisere ohne ihn über Socket zu senden funktioniert es.

Und jetzt kommts.

Sowohl vor dem Senden ... als auch nach Empfang der Nachricht hat der byte[] buffer dieselbe Länge und die Daten darin liefern denselben Hash!

Bei der Übertragung fand also kein Fehler statt. 

Ich tappe momentan wirklich im Dunkeln...


----------



## SlaterB (29. Apr 2009)

wenn du schon so detailliert dabei bis, könntest du auch versuchen, ein kleines Testprogramm zu posten,

alles außer dem Objekt der fraglichen Klasse könnte sofort raus, die Klasse selber, falls eine eigene oder anoynme innere Klasse,
so einfach wie möglich


----------



## Stefan S. (29. Apr 2009)

SlaterB hat gesagt.:


> wenn du schon so detailliert dabei bis, könntest du auch versuchen, ein kleines Testprogramm zu posten,



Das ist leider nur bedingt möglich. Das minimale Beispielprpgramm basiert auf einer umfangreichen Netzwerkbibliothek mit über 50 Klassen. 



SlaterB hat gesagt.:


> alles außer dem Objekt der fraglichen Klasse könnte sofort raus, die Klasse selber, falls eine eigene oder anoynme innere Klasse,
> so einfach wie möglich



Ich habe das Problem identifiziert. :lol:

Es liegt an der Konvertierung!

Ich hatte zunächst folgendes gemacht.


```
buffer_ = IOUtil.serialize( jTextPane1.getDocument() );
```

Allerdings hatte ich es nun zunächst in einen String gewandelt.


```
String test = new String( buffer_ );
```

Nun testete ich den Hash:


```
Utility.getSha256( test.getBytes() )
```

Und nun transferierte ich es über das Netzwerk.


```
peer.sendToUser(pid, MessageType.ChatM.toString(), test, false);
```

Anschließend nahm ich erneut den Hash und bekam denselben heraus. Offensichtlich war die Übertragung fehlerfrei.

Mein Fehler war den Hash erst nach der Konvertierung in den String zu ziehen.

Ich habe ihn nun am Anfang direkt aus dem byte[] Array gezogen. Nun ist er zuvor und danach unterschiedlich! Genauer gesagt:


```
System.out.println( "Hash: " + Utility.getSha256( buffer_ ) );
```

liefert ein anderes Ergebnis als


```
System.out.println( "Hash: " + Utility.getSha256( new String( buffer_ ).getBytes() ) );
```

:autsch:

Und wegen dieser Kleinigkeit verschwendete ich gestern 2 Stunden.

Sehr unerwartet... ich dachte diese Form der Konvertierung wäre sicher? ???:L

Ich tippe darauf dass das serialisierte Objekt eine bestimmte Enkodierung enthält, die bei der Konstruktion über String mit dem Standardencoding beschädigt wird.


----------



## Stefan S. (29. Apr 2009)

Achja, ein Abschlussbericht für alle die auf ein ähnliches Problem stoßen. Ich mag keine Forenbeiträge ohne Lösung. 

Falls sensible Bytedaten, beispielsweise ein serialisiertes Objekt, in ein String konvertiert werden soll, solltet ihr es zunächst in *Base 64* konvertieren. Anschließend kann man leicht String.getBytes() verwenden ohne Angst haben zu müssen dass die Daten falsch en/dekodiert wurden.


----------

