# Probleme wenn man keine serialVersionUID definiert?



## jago (10. Sep 2008)

Fuer serialisierbare Klassen kann man - oder sollte man sogar wenn man den Compiler Warnings glaubt - eine serialVersionUID definieren.


Weiss jemand warum? Hat das einen Vorteil wenn ich Objekte per ObjectOutput/InputStream speichere/lade?


Danke,
jago


----------



## The_S (10. Sep 2008)

Die serialVersionUID ist so ne Art Versions-Identifizierung. Wenn du also ein Objekt in einer alten Version (mit einer anderen serialVersionUID) abspeicherst, später die Klasse veränderst und somit eine neue serialVersionUID generiert hast und dann versucht das Objekt wieder zu laden, bekommst du eine Exception, weil die Klasse des Objekts in der Zwischenzeit verändert wurde. Kannst ja mal ausprobieren, was passiert, wenn du das nicht machst  .


----------



## FArt (10. Sep 2008)

http://java.sun.com/developer/technicalArticles/Programming/serialization/


----------



## EgonOlsen (10. Sep 2008)

Hobbit_Im_Blutrausch hat gesagt.:
			
		

> Kannst ja mal ausprobieren, was passiert, wenn du das nicht machst  .


Dasselbe, weil die ID automatisch erzeugt wird, wenn man sie nicht angibt. Mit der serialVersionUID kann man verhindern, dass jede Änderung zu einer ID-Änderung führt und damit die serialisierten Objekte bei unwesentlichen Änderungen der Klasse valide halten, was mit dem Automatismus nicht geht.


----------



## The_S (10. Sep 2008)

@Egon

jetzt lass den Threadsteller doch mal ein bisschen rumprobieren. Probieren geht über studieren  .


----------



## Guest (10. Sep 2008)

EgonOlsen hat gesagt.:
			
		

> Hobbit_Im_Blutrausch hat gesagt.:
> 
> 
> 
> ...



Ich versteh halt grade die Welt nicht. Ich bekomme folgende Exception.

java.io.InvalidClassException: net.java.dev.bla.bla.MyClass; local class incompatible: stream classdesc serialVersionUID = 8798340908999271826, local class serialVersionUID = -5073758291574902811


Ich kann mir das absolut nicht erklaeren warum mein Eclipse-Projekt ohne Probleme die Klasse deserialisiert. Wenn ich per ANT den Code compiliere und als Applet laufen lasse klappt das deserialisieren nicht mehr - siehe Fehler oben 

Du sagst: "dass jede Änderung zu einer ID-Änderung führt?" Reicht es wenn ich einmal die Klasse per Eclipse compiler compiliere und ein andesmal per Sun compiler damit die automatische ID Sache ausflippt?


Unabhaengig davon - wenn ich explizit eine ID setzte...und meine Klasse aendere...wie werde ich informiert, dass diese Aenderung noch ok ist oder die Serialisierung bricht?


----------



## Guest (10. Sep 2008)

Ich glaub es ja nicht. Ich habe grade die Serialisierten Objekte mit dem Code erstellt, den ich mit dem Sun-compiler compiliert hab. Nun kann er diese Objekte deserialisieren.

Nun kann ich denselben code, der aber durch Eclipse kompiliert wurde nicht mehr nutzen um die serialisierten Objekte von oben zu deserialisieren.


Fazit: Der selbe Sourcecode - einmal mit dem Sun und einmal dem Eclipse-compiler compiliert - erzeugt serialisierte Objekte die jeweils mit dem anderen code nicht mehr geladen werden koennen.

Was haltet ihr davon? Wuerde das setzen einer Serial-ID hier helfen?

Ich wuerde auch zum testen eine Serial-ID setzen - nur werden den betreffenden Sourcen eigentlich nicht von mir verwaltet - auch handelt es sich um viele Dateien.


Danke.


----------



## diggaa1984 (10. Sep 2008)

ob ne Änderung noch ok ist oder nicht, solltest nach Änderung der Klasse noch selbst abschätzen können, wenn du die serial selbst festlegst


----------



## Wildcard (10. Sep 2008)

> Fazit: Der selbe Sourcecode - einmal mit dem Sun und einmal dem Eclipse-compiler compiliert - erzeugt serialisierte Objekte die jeweils mit dem anderen code nicht mehr geladen werden koennen.


Das ist auch in Ordnung so. Deshalb sollst du ja eine ID setzen wenn du serialisierst, sonst muss der Compiler selbst eine auswählen und die Art wie er das aussucht, entscheidet er selbst. Selbst ein zusätzlicher Kommentar kann serialisierte Objekte daher ungültig machen.


----------



## FArt (10. Sep 2008)

Anonymous hat gesagt.:
			
		

> Fazit: Der selbe Sourcecode - einmal mit dem Sun und einmal dem Eclipse-compiler compiliert - erzeugt serialisierte Objekte die jeweils mit dem anderen code nicht mehr geladen werden koennen.



Glaube ich tatsächlich nicht. Auch Eclipse kocht nur mit Wasser (und kompiliert mit dem Compiler von SUN).
Hast du denn beide male die selbe Version des JDK verwendet, bzw. bist du sicher, dass dein Testszenario passt?
Die ID wird über die Signatur der Klasse gebildet... so lange sich diese nicht ändert, ändert sich auch die ID nicht.


----------



## Wildcard (10. Sep 2008)

FArt hat gesagt.:
			
		

> Glaube ich tatsächlich nicht. Auch Eclipse kocht nur mit Wasser (und kompiliert mit dem Compiler von SUN).


Nö. Inkrementeller IBM Compiler.


----------



## Guest (10. Sep 2008)

diggaa1984 hat gesagt.:
			
		

> ob ne Änderung noch ok ist oder nicht, solltest nach Änderung der Klasse noch selbst abschätzen können, wenn du die serial selbst festlegst



bei dem Link oben heisst es:

die serialuid - it is just the hash code of the object by default

Was heisst das? Von einer Instanz der Klasse oder von dem Klassenfile selbst der Hash?


Vor allem - kann mir einer erklaeren warum sich der automatic Hash aendert, wenn ich einmal mit dem Eclipse-Compiler und einmal mit dem Sun-Compiler die Klasse kompiliere?

Wird das Hash also aus dem class-file generiert oder warum ist er jeweils anderst?


----------



## Guest (10. Sep 2008)

FArt hat gesagt.:
			
		

> Anonymous hat gesagt.:
> 
> 
> 
> ...



Nein. Eclipse hat einen eigenen Compiler. Hat ueberhaupt nix mit Sun zu tun und ist 100% in Java geschrieben.

Die Signatur der Klasse? Meinst du einen einfachen Hash ueber die class-Datei oder ein Hash ueber die fields, oder was heisst Signatur?


Ich bin echt verwirrt.


----------



## Wildcard (10. Sep 2008)

Anonymous hat gesagt.:
			
		

> die serialuid - it is just the hash code of the object by default


Ich wüsste nicht, das die JLS dazu etwas vorschreibt.



> Nein. Eclipse hat einen eigenen Compiler. Hat ueberhaupt nix mit Sun zu tun und ist 100% in Java geschrieben.


Der von SUN ist auch 100% Java, so aussergewöhnlich ist das also nicht  :wink:


----------



## FArt (10. Sep 2008)

Anonymous hat gesagt.:
			
		

> Nein. Eclipse hat einen eigenen Compiler. Hat ueberhaupt nix mit Sun zu tun und ist 100% in Java geschrieben.



Ok, dann ist alles klar. Unterschiedliche Compiler generieren auch u.U. unterschiedlichen Bytecode.
Merkt man, dass ich nicht mit Eclipse arbeite, sondern mit einer richtigen IDE, gell ;-) *duck und weg*

Die Signatur ist nicht ganz richtig... es geht um die Signatur, die Attribute, ... müsste zu ergoogeln sein...


----------



## Wildcard (10. Sep 2008)

FArt hat gesagt.:
			
		

> Merkt man, dass ich nicht mit Eclipse arbeite, sondern mit einer richtigen IDE, gell ;-) *duck und weg*


Deine IDE (welche das auch immer ist) passt locker als PlugIn in Eclipse  :bae:


----------



## Guest (10. Sep 2008)

FArt hat gesagt.:
			
		

> Anonymous hat gesagt.:
> 
> 
> 
> ...



Bitte langsam. Bin wie gesagt sehr verwirrt.

Wozu ratet ihr mir?

1. Ich soll also erstmal serialUIDs erstellen fuer alle meine serialisierbaren Klassen anstatt das AutoUID zuzulassen?

2. Da kann ich irgendeinen Long nehmen?

3. Wenn sich die Struktur der Klasse aendert warnt mich der Compiler, dass die UID nun nicht mehr stimmt? Zumindest der Eclipse-Compiler meckert gar nicht wenn ich z.B. meine Klasse von einer anderen ableite.

4. Zu den verschiedenen Compilern hat noch keiner was gesagt. Warum kommen die zu einem unterschiedlichen Ergebnis? Ist dieser Unterschied egal, wenn ich eine UID per Hand erstelle?

5. gibt es ein Java-Programm (nicht Kommandozeile), dass UIDs errechnet?


----------



## Wildcard (10. Sep 2008)

1. unbedingt
2. ja, oder einfach von Eclipse generieren lassen
3. nein, tut er nicht
4. ist doch egal, ein Implementierungsdetail. Völlig egal wenn du eine eigene ID erstellst (wie man es immer tun sollte)
5. ja, aber eigentlich brauchst du das wirklich nicht und würde wohl auch nicht zu den Ergebnissen des Eclipse Compilers passen


----------



## Guest (10. Sep 2008)

Wildcard hat gesagt.:
			
		

> 1. unbedingt
> 2. ja, oder einfach von Eclipse generieren lassen
> 3. nein, tut er nicht
> 4. ist doch egal, ein Implementierungsdetail. Völlig egal wenn du eine eigene ID erstellst (wie man es immer tun sollte)
> 5. ja, aber eigentlich brauchst du das wirklich nicht und würde wohl auch nicht zu den Ergebnissen des Eclipse Compilers passen




Eigentlich soll die UID ja dazu da sein, dass man die Klasse veraendern kann aber alte serialisierte Instanzen trotzdem noch geladen werden koennen, oder?

The version control works great as long as the changes are compatible. Compatible changes include adding or removing a method or a field. Incompatible changes include changing an object's hierarchy or removing the implementation of the Serializable interface. A complete list of compatible and incompatible changes is given in the Java Serialization Specification. 

Also irgendwie haette ich gerne eine Kontrolle - z.B. UIDs, sodass der Compiler mir sagt, falls ich die Klasse so veraendert habe das serialisierte Instanzen nicht mehr ladbar sind. Wenn ich beim Veraendern alles glatt geht sollte der Compiler nicht meckern.

Also ich raff das ganze Konzept der SerialUID immer noch nicht wie es scheint. Wo ist der Vorteil sowas zu haben wenn ich es nicht mal als Sicherheitskontrolle nutzen kann und der Compiler mich vor inkompatiblen Aenderungen warnt?


----------



## Wildcard (10. Sep 2008)

Da ein Compiler sich die vergebenen UIDs nirgends merken kann, kann dich auch niemand warnen. Die UID dient als Kontrolle zur Laufzeit. Wenn sie nicht passt, bekommst du eine Exception.
Und um das Klarzustellen, Serialisierung ist keine sinnvolle Persistierung. Wenn es dir darum geht Anwendungsdaten flexibel zu speichern, ist Serialisierung nicht das Mittel der Wahl. Serialisierung wird eigentlich nur zur Kurzzeitspeicherung verwendet (Clipboard, Netzwerk, RMI,...), nicht um Geschäftsdaten abzulegen.


----------



## FArt (11. Sep 2008)

Das Thema hat mir keine Ruhe gelassen, denn jagos Behauptung hat mich an Java zweifeln lassen.

Ich habe mir also mal die Zeit genommen, jagos Behauptung zu wiederlegen. Dazu habe ich mir sogar Eclipse installiert (keine Angst, ist schon wieder deinstalliert ;-) )

Ich habe eine Testklasse geschrieben und auf verschiedene Art und Weise unter verschiedensten Voraussetzungen eine ID generieren lassen:

```
package test;

import java.io.Serializable;

public class Test implements Serializable {

//  private static final long serialVersionUID = -1843941483498187456L; // generiert mit Eclipse Ganidingsbums (1.6 compliant)

//  private static final long serialVersionUID = -1843941483498187456L; // generiert mit IntelliJ 8 Plugin (1.5 compliant, SUN JDK)

//  static final long serialVersionUID = -1843941483498187456L; // generiert mit serialver.exe aus dem JDK 5 unter Windows

  private int intValue;

	private long longValue;

	private String text;

  public Test(int intValue, long longValue, String text) {
		this.intValue = intValue;
		this.longValue = longValue;
		this.text = text;
	}

	public int getIntValue() {
		return intValue;
	}

	public long getLongValue() {
		return longValue;
	}

	public String getText() {
		return text;
	}

}
```

Die sehen verdammt ähnlich aus, oder?

Danach habe ich (nur noch der Vollständigkeit halber) die Klasse aus Eclipse (nach obiger Info irgend ein Compiler von IBM (?)) geschrieben und über IntelliJ (SUN JRE 5) gelesen. Das ganze *ohne* explizit die servialVersionUID vorher an der Klasse generiert zu haben. Hat erwartungsgemäß geklappt.

Somit saß der Fehler doch davor, das Testszenario von jago war nicht sauber.


----------



## gizmo (11. Sep 2008)

Die serialVersionUID wird für daselbe Classfile immer dieselbe sein. Es ist spezifiziert, wie sie generiert werden soll. Standardkonforme JVMs (nicht Compiler) werden also immer dieselbe UID generieren. Die UID wird nicht beim Compilen erzeugt, sondern zur Laufzeit errechnet.
Das Problem ist, dass sich synthetic Methoden auf die UID auswirken. Es ist nicht genau spezifiziert wann und wie die synthetic Methoden generiert werden. Der Sun Compiler macht dies anders als der Eclipse Compiler. -> Unterschiedliche UID


----------



## FArt (11. Sep 2008)

gizmo hat gesagt.:
			
		

> Die serialVersionUID wird für daselbe Classfile immer dieselbe sein. Es ist spezifiziert, wie sie generiert werden soll. Standardkonforme JVMs (nicht Compiler) werden also immer dieselbe UID generieren. Die UID wird nicht beim Compilen erzeugt, sondern zur Laufzeit errechnet.
> Das Problem ist, dass sich synthetic Methoden auf die UID auswirken. Es ist nicht genau spezifiziert wann und wie die synthetic Methoden generiert werden. Der Sun Compiler macht dies anders als der Eclipse Compiler. -> Unterschiedliche UID



Es wurde nicht erwartet, dass die UID vom Compiler generiert wird, aber dass die generierte UID der entspricht, die auch zur Laufzeit gebildet wird (wenn nicht explizit gesetzt).

Ich behaupte ja immer noch, dass die UID zur Compilezeit bestimmt werden kann, denn auch die synthetischen Methoden stehen da bereits fest, oder sehe ich das falsch? 

Dein Einwand klingt nach profundem Wissen. Kannst du die Behauptung mit externen Quellen belegen oder zumindest ein Beispiel erbringen? In der JLS ist dies nämlich nicht erwähnt bzw. ich habe nichts passendes gefunden... klar, ist ja wohl auch nicht spezifiziert, obwohl es auch gute Specs gibt, in denen expliztit auf (wichtige) nicht spezifizierte Bereiche eingegangen wird.


----------



## gizmo (11. Sep 2008)

Ich sage nicht, die UID könnte nicht zur Compilezeit bestimmt werden, ich sage nur, dass sie dies nicht wird. Tut aber nichts zur Sache.
Schau dir ObjectStreamClass#_computeSerialVersionUID dort wird die UID generiert. Die angewendeten Regeln sind hier definiert: http://java.sun.com/j2se/1.3/docs/guide/serialization/spec/class.doc6.html#4100.

Ich denke, es ist nicht spezifiziert, dass javac die UID nicht generieren soll, da aber auch nicht spezifiziert ist, dass er sie generieren soll, wird dies nicht gemacht. Ansonsten müsste man bei einer Software immer auch alles spezifizieren, was sie nicht macht...

Siehe auch hier: http://wiki.eclipse.org/FAQ_Why_doe...eate_a_different_serialVersionUID_from_javac?


----------



## FArt (11. Sep 2008)

Danke, das ist der wichtige Satz aus der Spec: 


> different implementations of compilers could use different names for synthetic members.






			
				gizmo hat gesagt.:
			
		

> Ansonsten müsste man bei einer Software immer auch alles spezifizieren, was sie nicht macht...


Müssen nicht, aber ein gute Spec legt nicht nur fest, was durch sie garantiert ist, sondern auch was nicht garantiert wird... Abgrenzungen.


----------



## jago (11. Sep 2008)

FArt hat gesagt.:
			
		

> Danke, das ist der wichtige Satz aus der Spec:
> 
> 
> > different implementations of compilers could use different names for synthetic members.
> ...




Alles was ich sagen kann ist, dass ich 20 Klassen habe bei denen Eclipse und Sun beide keine Probleme machen. Bei 2 Klassen machen sie halt Probleme. Diese 2 Klassen sind sehr complex mit einer langen Vererbungshierarchie und vielen Interfaces.

Vielleicht liegt es daran.


----------



## gizmo (12. Sep 2008)

-> Alles mit demselben Compiler compilen.


----------



## FArt (12. Sep 2008)

jago hat gesagt.:
			
		

> Vielleicht liegt es daran.


Eigentlich nicht. Denn die Spec spricht nur von inneren Klassen oder Klassen, die innere Klassen beinhalten.


----------

