1

If Serializable class has no serialVersionUID defined, there is a risk that (!for the same class!) JVM which do serialization will calculate different version than JVM which do deserialization. The recommended solution is calculate version Id with serialver tool and put manually to the source code.

It is stupid IMHO. It would be much better that javac automatially calculate serialVersionUID and put to bytecode if not defined in source code.

Is there any possible problem related with automatic calculation in compile time?

I know there is something like compiler plugin javac -Xplugin. Is it possible create plugin which do the automatization? Or maybe such plugin is already created?

Please do not give me false duplicate with Why isn't the serialVersionUID automatically generated? There are discussed case when different version of classes are compatible for Serialization. I'm interesting a case when the same class is expected to always pass serialization and different versions of class should fail.

michaldo
  • 4,195
  • 1
  • 39
  • 65
  • what the compiler should generate if you pass exactly the same file for a second time? how compiler should know actually two different classes are compatible in serialization sense? – Jason Hu Mar 16 '15 at 15:53
  • @HuStmpHrrr compiler should take serialver output – michaldo Mar 16 '15 at 16:40
  • AFAIK it's specified how to calculate the default serialVersionUID and every compliant JVM should implement this correctly: http://docs.oracle.com/javase/8/docs/platform/serialization/spec/class.html#a4100 Why do you think there is a problem with the same class file in different JVM regarding to the default serialVersionUID? – Puce Mar 16 '15 at 16:48
  • @Puce In doc you linked is a sentence: Note - It is strongly recommended that all serializable classes explicitly declare serialVersionUID values, since the default serialVersionUID computation is highly sensitive to class details that may vary depending on compiler implementations, and can thus result in unexpected serialVersionUID conflicts during deserialization, causing deserialization to fail. So if 'every compliant JVM should implement this correctly' there is won't be unexpected serialVersionUID conflicts. But there are – michaldo Mar 16 '15 at 17:10
  • @michaldo You don't appear to understand the sources you're ciiting. The conflicts arise because the class has changed, which changes the output of the algorithm. That algorim is implemented by the `serialver` tool, and by `ObjectInputStream` and friends. Implementing the same algorithm in the compiler wouldn't change anything, or solve anything. – user207421 Mar 17 '15 at 09:27
  • @EJP Yes my understanding was not correct. But you are not precise here. The conflict may happen because 2 different compilers may produce 2 different *.class file (from the same *.java file). But once class is compiled, serialver in any JVM will calculate the same value. I wrongly thought that different serialver can calculate different serialVersionUID – michaldo Mar 17 '15 at 10:19

3 Answers3

1

Because ObjectInputStream and friends do it. It's not a piece of functionality that belongs in the compiler, and it wouldn't solve any problem if it did. The compiler can't do anything different from what is already done.

I'm interested in a case when the same class is expected to always pass serialization and different versions of class should fail.

That case already works. No solution required.

user207421
  • 305,947
  • 44
  • 307
  • 483
1

So the Serializable class Javadoc states:

If a serializable class does not explicitly declare a serialVersionUID, then the serialization runtime will calculate a default serialVersionUID value for that class based on various aspects of the class, as described in the Java(TM) Object Serialization Specification. However, it is strongly recommended that all serializable classes explicitly declare serialVersionUID values, since the default serialVersionUID computation is highly sensitive to class details that may vary depending on compiler implementations, and can thus result in unexpected InvalidClassExceptions during deserialization. Therefore, to guarantee a consistent serialVersionUID value across different java compiler implementations, a serializable class must declare an explicit serialVersionUID value.

Now the Java Serialization Specification states:

The serialVersionUID is computed using the signature of a stream of bytes that reflect the class definition. The National Institute of Standards and Technology (NIST) Secure Hash Algorithm (SHA-1) is used to compute a signature for the stream. The first two 32-bit quantities are used to form a 64-bit hash. A java.lang.DataOutputStream is used to convert primitive data types to a sequence of bytes. The values input to the stream are defined by the Java Virtual Machine (VM) specification for classes. Class modifiers may include the ACC_PUBLIC, ACC_FINAL, ACC_INTERFACE, and ACC_ABSTRACT flags; other flags are ignored and do not affect serialVersionUID computation. Similarly, for field modifiers, only the ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC, ACC_FINAL, ACC_VOLATILE, and ACC_TRANSIENT flags are used when computing serialVersionUID values. For constructor and method modifiers, only the ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC, ACC_FINAL, ACC_SYNCHRONIZED, ACC_NATIVE, ACC_ABSTRACT and ACC_STRICT flags are used. Names and descriptors are written in the format used by the java.io.DataOutputStream.writeUTF method.

So the serialVersionUID is computed in the runtime based on "the signature of a stream of bytes that reflect the class definition", so based on compiler's output. I believe that's why they say "it is strongly recommended that all serializable classes explicitly declare serialVersionUID values, since the default serialVersionUID computation is highly sensitive to class details that may vary depending on compiler implementations".

But anyway, if you're using the same JDK runtime, the same compiler etc. this situation should not happen (unless there's a bug in JDK of course).

Sebastian Łaskawiec
  • 2,667
  • 15
  • 33
0

If Serializable class has no serialVersionUID defined, there is a risk that (!for the same class!) JVM which do serialization will calculate different version than JVM which do deserialization.

AFAIK it's specified how to calculate the default serialVersionUID and every compliant JVM should implement this correctly: http://docs.oracle.com/javase/8/docs/platform/serialization/spec/class.html#a4100

In doc you linked is a sentence: Note - It is strongly recommended that all serializable classes explicitly declare serialVersionUID values, since the default serialVersionUID computation is highly sensitive to class details that may vary depending on compiler implementations, and can thus result in unexpected serialVersionUID conflicts during deserialization, causing deserialization to fail. So if 'every compliant JVM should implement this correctly' there is won't be unexpected serialVersionUID conflicts. But there are

No, it is highly sensitive to class details that may vary depending on compiler implementations, but for a given class file the class details don't change once it is compiled. But if you compile the same java file with two different compilers you might end up with two class files with a different default serialVersionUID.

It wouldn't change anything in this regard if the compilers would add the default serialVersionUID to the class file.

Puce
  • 37,247
  • 13
  • 80
  • 152
  • Thanks, now clear. I was confused how serialVersionUID is calculated. Now is obviois to me that when Java class is compiled to bytecode then tool serialver will return the same value on any JVM. I wrongly thought is depends on JVM – michaldo Mar 16 '15 at 17:54