Du verwendest einen veralteten Browser. Es ist möglich, dass diese oder andere Websites nicht korrekt angezeigt werden. Du solltest ein Upgrade durchführen oder ein alternativer Browser verwenden.
Probleme wenn man keine serialVersionUID definiert?
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 .
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.
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.
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?
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.
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.
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.
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?
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.
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...
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...
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?
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
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?
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.
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:
Code:
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.
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
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.
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...
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.