JDK-4365406 : Regression: Calculation of serialVersionUID changed from 1.3 to 1.4
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.text
  • Affected Version: 1.4.0
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: solaris_2.6,windows_nt
  • CPU: x86,sparc
  • Submitted: 2000-08-24
  • Updated: 2000-10-31
  • Resolved: 2000-10-17
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
1.4.0 betaFixed
Related Reports
Duplicate :  
Description

Name: ooR10001			Date: 08/24/2000


Serialization of java.text.AttributedCharacterIterator.Attribute class has 
compatibility problem because serialVersionUID for this class has been changed 
from kestrel to merlin:

%/set/java/jdk1.4/solaris/bin/serialver 
java.text.AttributedCharacterIterator.Attribute
java.text.AttributedCharacterIterator.Attribute:    static final long 
serialVersionUID = -1514471214376796190L;
%/set/java/jdk1.3/solaris/bin/serialver 
java.text.AttributedCharacterIterator\$Attribute
java.text.AttributedCharacterIterator$Attribute:    static final long 
serialVersionUID = -9142742483513960612L;
%

======================================================================

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: merlin-beta FIXED IN: merlin-beta INTEGRATED IN: merlin-beta
14-06-2004

EVALUATION The Attribute class hasn't changed since May 1999. Further testing shows that the problem is in the calculation of the serialVersionUID itself - the result depends on the version of the tool, but not on the version of the class or how the class name is specified: % /usr/local/java/jdk1.3/solaris/bin/serialver -classpath /usr/local/java/jdk1.3/solaris/jre/lib/rt.jar java.text.AttributedCharacterIterator\$Attribute java.text.AttributedCharacterIterator$Attribute: static final long serialVersionUID = -9142742483513960612L; % /usr/local/java/jdk1.3/solaris/bin/serialver -classpath /usr/local/java/jdk1.4/solaris/jre/lib/rt.jar java.text.AttributedCharacterIterator\$Attribute java.text.AttributedCharacterIterator$Attribute: static final long serialVersionUID = -9142742483513960612L; % /usr/local/java/jdk1.4/solaris/bin/serialver -classpath /usr/local/java/jdk1.3/solaris/jre/lib/rt.jar java.text.AttributedCharacterIterator\$Attribute java.text.AttributedCharacterIterator$Attribute: static final long serialVersionUID = -1514471214376796190L; % /usr/local/java/jdk1.4/solaris/bin/serialver -classpath /usr/local/java/jdk1.4/solaris/jre/lib/rt.jar java.text.AttributedCharacterIterator\$Attribute java.text.AttributedCharacterIterator$Attribute: static final long serialVersionUID = -1514471214376796190L; % /usr/local/java/jdk1.4/solaris/bin/serialver -classpath /usr/local/java/jdk1.3/solaris/jre/lib/rt.jar java.text.AttributedCharacterIterator.Attribute java.text.AttributedCharacterIterator.Attribute: static final long serialVersionUID = -1514471214376796190L; % /usr/local/java/jdk1.4/solaris/bin/serialver -classpath /usr/local/java/jdk1.4/solaris/jre/lib/rt.jar java.text.AttributedCharacterIterator.Attribute java.text.AttributedCharacterIterator.Attribute: static final long serialVersionUID = -1514471214376796190L; norbert.lindenberg@Eng 2000-08-24 The conclusion drawn in the above comment is not accurate. The class java.text.AttributedCharacterIterator$Attribute is loaded from the bootclasspath; hence, specifying -classpath does not actually cause it to be loaded from the intended location. In other words, in the tests above, the 1.3 version of serialver loaded java.text.AttributedCharacterIterator$Attribute from /usr/local/java/jdk1.3/solaris/jre/lib/rt.jar, while the 1.4 version of serialver loaded it from /usr/local/java/jdk1.4/solaris/jre/lib/rt.jar. The reason this is significant is that the class files for the 1.3 and 1.4 versions of java.text.AttributedCharacterIterator$Attribute differ even though the source did not change between 1.3 and 1.4. This change is due to differences between the 1.3 and 1.4 versions of javac (I've appended a detailed explanation to the end of this comment, for the terminally curious). These differences between the 1.3 and 1.4 generated code for AttributedCharacterIterator$Attribute affect the serialVersionUID computation and result in a different serialVersionUID value for the two versions of the class. The (unfortunate) sensitivity of the serialVersionUID computation to synthetic class elements that may be generated differently by different compilers has already been noted in bug 4169272 ("serialVersionUID computation can be unreliable across releases & implementations"). Though the serialVersionUID computation algorithm is known to be flawed, it cannot be changed at this point without breaking compatibility with past JDKs. It's unreasonable to ask that javac be changed to revert to its 1.3 behavior since the code that 1.4 javac generates is still valid with respect to the JLS/JVMS. The only possible work around (as noted in the bug report for 4169272) is for java.text.AttributedCharacterIterator$Attribute to declare an explicit serialVersionUID (equal in value to the 1.3 default). Therefore, I'm refiling this bug under java/classes_text. (An explanation of the generated code change between 1.3 and 1.4 javac follows:) To allow for lazy resolution of classes, explicit ".class" references in java source files are compiled into synthetic field/methods pairs. For example, the following java source: class Foo { void func() { Class cl = Integer.class; } } ...results in the following class file in both 1.3 and 1.4 (javap output shown): class Foo extends java.lang.Object { static java.lang.Class class$java$lang$Integer; Foo(); void func(); static java.lang.Class class$(java.lang.String); } Note that two synthetic class members--the static field class$java$lang$Integer and static method class$()--have been added by javac. The static field is used to hold the value of Integer.class once it has been obtained (lazily); the static method is used to look up Integer.class via a call to Class.forName(): Method void func() 0 getstatic #7 <Field java.lang.Class class$java$lang$Integer> 3 ifnonnull 18 6 ldc #8 <String "java.lang.Integer"> 8 invokestatic #9 <Method java.lang.Class class$(java.lang.String)> 11 dup 12 putstatic #7 <Field java.lang.Class class$java$lang$Integer> 15 goto 21 18 getstatic #7 <Field java.lang.Class class$java$lang$Integer> 21 astore_1 22 return Method java.lang.Class class$(java.lang.String) 0 aload_0 1 invokestatic #1 <Method java.lang.Class forName(java.lang.String)> 4 areturn 5 astore_1 6 new #3 <Class java.lang.NoClassDefFoundError> 9 dup 10 aload_1 11 invokevirtual #4 <Method java.lang.String getMessage()> 14 invokespecial #5 <Method java.lang.NoClassDefFoundError(java.lang.Strin g)> 17 athrow Exception table: from to target type 0 5 5 <Class java.lang.ClassNotFoundException> Things get trickier when an explicit ".class" reference occurs within a nested class. In 1.3, the following code: class Foo { class Bar { void func() { Class cl = Integer.class; } } } Compiles into the following two classes: class Foo extends java.lang.Object { Foo(); class Foo. Bar extends java.lang.Object /* ACC_SUPER bit NOT set */ { static java.lang.Class class$java$lang$Integer; Foo.Bar(Foo); void func(); static java.lang.Class class$(java.lang.String); } } Note that the synthetic static field and method are added to the inner class. 1.4 javac compiles the same code into the following classes: class Foo extends java.lang.Object { static java.lang.Class class$java$lang$Integer; Foo(); static java.lang.Class class$(java.lang.String); class Foo. Bar extends java.lang.Object /* ACC_SUPER bit NOT set */ { Foo.Bar(Foo); void func(); } } Note that the synthetic static field/method have been added to the outer class, instead of the inner class. This change in itself is enough to affect serialVersionUID values if either Foo or Foo$Bar happen to be serializable (the serialVersionUID computation involves the signatures of all fields except those that are private static or private transient, as well as the signatures of all non-private methods). In the case of java.text.AttributedCharacterIterator$Attribute, this discrepancy is pushed a step further: since the outer entity (java.text.AttributedCharacterIterator) is an interface, it cannot accomodate the sythetic field/method pair that javac wishes to add; consequently, the synthetic members are placed in a new synthetic class. To illustrate, the code: interface Foo { class Bar { void func() { Class cl = Integer.class; } } } ...gets compiled into the following *three* classes: interface Foo /* ACC_SUPER bit NOT set */ { public static class Foo. Bar extends java.lang.Object /* ACC_SUPER bit NOT set */ { public Foo.Bar(); void func(); } } class Foo$1 extends java.lang.Object { static java.lang.Class class$java$lang$Integer; static java.lang.Class class$(java.lang.String); } 1.3 javac does not need to perform this extra transformation since it adds the synthetic field/method pair to the inner class, which can legally accomodate the members. Needless to say, the transformations effected by 1.4 javac also result in changed serialVersionUID values (if the affected classes happen to be serializable). michael.warres@east 2000-09-15 This change in the compiled binary and the resulting change in the serial version represents a source incompatibility - recompiling existing sources may no longer result in binaries that behave as before. Steve.Wilson@eng decided that this source incompatibility is acceptable, and it will be documented in the Merlin compatibility documentation. The Attribute class will receive an explicit serialVersionUID in order to remain compatible with 1.3. norbert.lindenberg@Eng 2000-10-04
04-10-2000

SUGGESTED FIX java.text.AttributedCharacterIterator$Attribute should declare a serialVersionUID value equal to the default value under 1.3/1.2: private static final long serialVersionUID = -9142742483513960612L; See evaluation for details. michael.warres@east 2000-09-15
15-09-2000