serialized lambda and no serialVersionUID?

2019-04-07 22:01发布

I'm trying to learn how the serialization works with Java and its lastest version. I'm trying to serialize a lambda like this :

Runnable r = (Runnable & Serializable)() -> {System.out.println("This is a test");};

But I notice that I have no warning about the absence of a serialVersionUID variable. Is it normal ?

I know it will be generated at the runtime however it is strongly recommended to define it : https://docs.oracle.com/javase/8/docs/api/java/io/Serializable.html

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. It is also strongly advised that explicit serialVersionUID declarations use the private modifier where possible, since such declarations apply only to the immediately declaring class--serialVersionUID fields are not useful as inherited members. Array classes cannot declare an explicit serialVersionUID, so they always have the default computed value, but the requirement for matching serialVersionUID values is waived for array classes.

What should I do ? How can I define it in my Lambda ?

Thanks

1条回答
Fickle 薄情
2楼-- · 2019-04-07 22:32

The serialVersionUID is only relevant to classes which generate a stream identifier. This is not the case if the serializable class has a writeReplace() method (also described in the Serializable documentation) that returns a substitute object of a different class, as such a representation is fully decoupled from the original class. This is what happens with serializable lambda instances, see SerializedLambda:

Implementors of serializable lambdas, such as compilers or language runtime libraries, are expected to ensure that instances deserialize properly. One means to do so is to ensure that the writeReplace method returns an instance of SerializedLambda, rather than allowing default serialization to proceed.

So it’s an instance of SerializedLambda that ends up on the stream and thus the responsibility of that class to have a stable serialized representation. Unfortunately that doesn’t protect you from possible incompatibilities.

Upon deserialization, a synthetic method of the class defining the lambda expression will get called (compare to this and this answer) which will reject deserialization attempts which do not match an existing definition of a lambda expression within that class, whereas the matching may depend on subtle aspects of the lambda’s definition. Note that even recompiling the defining class with Eclipse rather than javac might break the Serialization compatibility.

Not also the security impacts of Serializable lambdas. Generally, I recommend to avoid using it.

查看更多
登录 后发表回答