I'm using Java 8 lambdas with Wicket, and they make it really simple
to have almost 100% type-safe code, without the verbosity of anonymous
inner classes. With a few adapter classes and interfaces, it was
relatively easy to integrate them.
But I'm having some non-trivial problems with serialization. I think
it's a bug in the compiler, but I'm curious if someone else has seen
this:
public class TestClass implements Serializable {
String msg = "HEY!";
SerializableRunnable runnable;
public TestClass() {
TestClass self = this;
runnable = () -> self.say(); // uses a local copy of 'this'
// runnable = () -> this.say(); // uses 'this' directly
}
public void say() {
System.out.println(msg);
}
public static void main(String[] args) throws Exception {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
try (ObjectOutputStream out = new ObjectOutputStream(buffer)) {
out.writeObject(new TestClass());
}
try (ObjectInputStream in = new ObjectInputStream(new
ByteArrayInputStream(buffer.toByteArray()))) {
TestClass s = (TestClass) in.readObject();
s.say();
}
}
}
interface SerializableRunnable extends Runnable, Serializable {
}
The above code runs fine, but if I use the commented line to
initialize the runnable (using 'this' directly instead of a local
variable), the in.readObject() call throws an excetion
('java.lang.IllegalArgumentException: Invalid lambda
deserialization'). The object is serialized, but can't be
deserialized.
That is, lambdas are correctly serialized when it only uses the local
scope, but if it tries to use the enclosing class directly (methods or
attributes), it fails. I mean, it compiles, it works, it can access
them, but if serialized, it can't be deserialized.
Obviously, it makes it very inconvenient to use with Wicket, which
uses serialization extensively.
I already submited a bug to Oracle. Do you agree that it looks like a bug?