Stability of lambda serialization

Brian Goetz brian.goetz at oracle.com
Sat Aug 3 00:00:03 PDT 2013


This was discussed in the meeting after JVMLS this week.  The consensus was that, while *this particular* issue could be addressed, there is an infinite spectrum of similar issues that cannot be addressed, and that it is preferable to draw a clean line about what the user can expect in terms of code changes destabilizing lambdas.  

That line is: If the code inside a method, or the method's signature, changes *in any way*, lambdas captured in that method should be considered destabilized.  Changes to other methods, or changes to the order of methods, do not affect lambdas in an unchanged method.  

On Jul 23, 2013, at 10:35 AM, Scott Stark wrote:

> Red Hat has a concern regarding how fragile the default serialization behavior of lambda expressions is in the current reference implementation, currently:
> ironmaiden:OpenJDK starksm$ /Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/Home/bin/java -version
> java version "1.8.0-ea"
> Java(TM) SE Runtime Environment (build 1.8.0-ea-b98)
> Java HotSpot(TM) 64-Bit Server VM (build 25.0-b40, mixed mode)
> 
> The problem is that the serialized form of a lambda expression depends on the order in which captured arguments are declared. The attached simple example demonstrates how easy it is for a trivial reordering of the lambda code block to result in an inability to deserialize a previously saved expression.
> 
> To produce this exception:
> 1. Run the serialization.AuthenticationContext.testWriteLambda method with the lambda expression written as:
>     Authenticator a = (Authenticator & Serializable) (String principal, char[] pass) -> {
>         // Run with p declared first when writing out the /tmp/testWriteLambda.bin, then switch
>         // to declare u first when running testReadLambda
>         String p = "-> Password " + password + " <-";
>         String u = "-> User " + user + " <-";
>         return u + " " + p;
>     };
> 2. Change the lambda expression to:
>     Authenticator a = (Authenticator & Serializable) (String principal, char[] pass) -> {
>         // Run with p declared first when writing out the /tmp/testWriteLambda.bin, then switch
>         // to declare u first when running testReadLambda
>         String u = "-> User " + user + " <-";
>         String p = "-> Password " + password + " <-";
>         return u + " " + p;
>     };
> 
> Recompile and run serialization.AuthenticationContext.testReadLambda to produce:
> 
> java.io.IOException: unexpected exception type
> 	at java.io.ObjectStreamClass.throwMiscException(ObjectStreamClass.java:1538)
> 	at java.io.ObjectStreamClass.invokeReadResolve(ObjectStreamClass.java:1110)
> 	at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1807)
> 	at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1348)
> 	at java.io.ObjectInputStream.readObject(ObjectInputStream.java:370)
> 	at serialization.AuthenticationContext.testReadLambda(AuthenticationContext.java:34)
> ...
> Caused by: java.lang.reflect.InvocationTargetException
> 	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
> 	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
> 	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
> 	at java.lang.invoke.SerializedLambda.readResolve(SerializedLambda.java:222)
> 	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
> 	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
> 	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
> 	at java.io.ObjectStreamClass.invokeReadResolve(ObjectStreamClass.java:1104)
> 	... 30 more
> Caused by: java.lang.IllegalArgumentException: Invalid lambda deserialization
> 	at serialization.AuthenticationContext.$deserializeLambda$(AuthenticationContext.java:1)
> 	... 40 more
> 
> One does not see the same level of sensitivity to the ordering of the serialization fields in a POJO as demonstrated by the serialization.AuthenticationContext.testWritePOJO/testReadPOJO cases where one can reorder the TestPOJO.{user,password} fields without having serialization fail.
> 
> We would like to see at least that level of stability of the serialized form of lambda expressions.
> <AuthenticationContext.java><TestPOJO.java><Authenticator.java>



More information about the lambda-spec-observers mailing list