Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
432 views
in Technique[技术] by (71.8m points)

serialization - Java 8 lambdas that access instance fields and methods can't be deserialized

It seems to me it's a bug in the compiler or in the JVM, but maybe someone has a better explanation.

The following code runs fine as is, but if I uncomment the second runnable initialization, that uses 'this' directly, it can't deserialize the object (in.readObject() throws an exception).

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 {
}

This is the stacktrace for the root cause:

java.lang.IllegalArgumentException: Invalid lambda deserialization
    at j8test.TestClass.$deserializeLambda$(TestClass.java:1)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at java.lang.invoke.SerializedLambda.readResolve(SerializedLambda.java:230)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at java.io.ObjectStreamClass.invokeReadResolve(ObjectStreamClass.java:1104)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1810)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351)
    at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1993)
    at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1918)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1801)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371)
    at j8test.TestClass.main(TestClass.java:30)

Is it the expected behavior?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I tried everything but the most obvious.

The problem happens in Eclipse (wherein the java 8 support is still in beta), but not in javac. Thus, a JDT bug.

[EDIT]

I'm running:

Eclipse IDE for Java and Report Developers
Version: Luna RC1 Release (4.4.0RC1)
Build id: 20140522-1310

Java(TM) SE Runtime Environment (build 1.8.0_05-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.5-b02, mixed mode)

OS X 10.9.3

Maybe it's already corrected in a more recent build.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...