Stability of lambda serialization

Scott Stark sstark at redhat.com
Tue Jul 23 10:35:26 PDT 2013


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.


More information about the lambda-spec-experts mailing list