JDK-8282080 : Lambda deserialization fails for Object method references on interfaces
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 18
  • Priority: P2
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2022-02-18
  • Updated: 2022-06-07
  • Resolved: 2022-05-17
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 18 JDK 19
18.0.2Fixed 19 b23Fixed
Related Reports
CSR :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Sub Tasks
JDK-8286857 :  
Description
The example serializes and deserializes a lambda for an Object method reference on an interface.

This works for JDK 17 and earlier, but fails with JDK 18.

The regression was introduced by https://bugs.openjdk.java.net/browse/JDK-8272564


```
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.nio.file.Files;
import java.nio.file.Paths;

public class X {
  interface I extends Serializable {}

  interface F<T, R> extends Serializable {
    R apply(T t);
  }

  @SuppressWarnings("unchecked")
  public static void main(String[] args) throws Exception {
    F<I, Integer> f = I::hashCode;
    try (OutputStream os = Files.newOutputStream(Paths.get("o"));
        ObjectOutputStream oos = new ObjectOutputStream(os)) {
      oos.writeObject(f);
    }
    try (InputStream is = Files.newInputStream(Paths.get("o"));
        ObjectInputStream ois = new ObjectInputStream(is)) {
      f = (F<I, Integer>) ois.readObject();
    }
    System.err.println(f.apply(new I() {}));
  }
}
```

```
$ javac X.java
$ java X
...
Exception in thread "main" java.io.InvalidObjectException: ReflectiveOperationException during deserialization
        at java.base/java.lang.invoke.SerializedLambda.readResolve(SerializedLambda.java:280)
        at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
        at java.base/java.lang.reflect.Method.invoke(Method.java:577)
        at java.base/java.io.ObjectStreamClass.invokeReadResolve(ObjectStreamClass.java:1321)
        at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2301)
        at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1768)
        at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:543)
        at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:501)
        at X.main(X.java:25)
Caused by: java.lang.reflect.InvocationTargetException
        at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:119)
        at java.base/java.lang.reflect.Method.invoke(Method.java:577)
        at java.base/java.lang.invoke.SerializedLambda.readResolve(SerializedLambda.java:278)
        at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
        at java.base/java.lang.reflect.Method.invoke(Method.java:577)
        at java.base/java.io.ObjectStreamClass.invokeReadResolve(ObjectStreamClass.java:1321)
        at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2301)
        at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1768)
        at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:543)
        at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:501)
        at X.main(X.java:25)
        at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
        at java.base/java.lang.reflect.Method.invoke(Method.java:577)
        at jdk.compiler/com.sun.tools.javac.launcher.Main.execute(Main.java:421)
        at jdk.compiler/com.sun.tools.javac.launcher.Main.run(Main.java:192)
        at jdk.compiler/com.sun.tools.javac.launcher.Main.main(Main.java:132)
Caused by: java.lang.IllegalArgumentException: Invalid lambda deserialization
        at X.$deserializeLambda$(X.java:9)
        at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
        ... 15 more
```
Comments
Fix Request Request to backport this fix to JDK18u, please. This fix should allow to to generate classfiles that deserialize certain serialized method references. The serialized form can be produced by classfiles produced by various versions of JDK, but JDK 18 cannot deserialize them, so it would be nice to allow their deserialization on classfiles produced by an JDK 18 update.
17-05-2022

A pull request was submitted for review. URL: https://git.openjdk.java.net/jdk18u/pull/133 Date: 2022-05-17 14:01:54 +0000
17-05-2022

Changeset: c0d51d42 Author: Jan Lahoda <jlahoda@openjdk.org> Date: 2022-05-17 13:48:45 +0000 URL: https://git.openjdk.java.net/jdk/commit/c0d51d42d9715b44df995328bba978ba61dec3af
17-05-2022

A pull request was submitted for review. URL: https://git.openjdk.java.net/jdk/pull/8054 Date: 2022-03-31 08:13:57 +0000
31-03-2022

FWIW, even though for the specific testcase above, the change that triggered the issue is JDK-8272564, the problem appears to have existed latently even before, consider testcase: ``` /** * @test * @compile X.java * @run main X */ import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.OutputStream; import java.io.Serializable; import java.nio.file.Files; import java.nio.file.Paths; public class X { interface I extends Serializable { public int hashCode(); } interface F<T, R> extends Serializable { R apply(T t); } @SuppressWarnings("unchecked") public static void main(String[] args) throws Exception { F<I, Integer> f = I::hashCode; try (OutputStream os = Files.newOutputStream(Paths.get("o")); ObjectOutputStream oos = new ObjectOutputStream(os)) { oos.writeObject(f); } try (InputStream is = Files.newInputStream(Paths.get("o")); ObjectInputStream ois = new ObjectInputStream(is)) { f = (F<I, Integer>) ois.readObject(); } System.err.println(f.apply(new I() {})); } } ``` ``` $ ~/tools/jdk/jdk-11/bin/javac X.java $ ~/tools/jdk/jdk-11/bin/java X Exception in thread "main" java.io.IOException: unexpected exception type at java.base/java.io.ObjectStreamClass.throwMiscException(ObjectStreamClass.java:1626) at java.base/java.io.ObjectStreamClass.invokeReadResolve(ObjectStreamClass.java:1256) at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2096) at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1594) at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:430) at X.main(X.java:34) Caused by: java.lang.reflect.InvocationTargetException at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at java.base/java.lang.invoke.SerializedLambda.readResolve(SerializedLambda.java:237) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at java.base/java.io.ObjectStreamClass.invokeReadResolve(ObjectStreamClass.java:1250) ... 4 more Caused by: java.lang.IllegalArgumentException: Invalid lambda deserialization at X.$deserializeLambda$(X.java:14) ... 14 more ```
02-03-2022