-
Bug
-
Resolution: Unresolved
-
P4
-
8u101, 9
The SerializedLambda class doesn't encode the extra interfaces and method descriptors provided to 'altMetafactory'. As a result, method references that refer to the same method but with different target types can end up being deserialized to the same class, leaving one of the deserialized objects with either too many or too few interfaces/bridges.
--------
Test:
import java.util.Arrays;
import java.io.*;
public class LambdaSerialization {
interface I {}
public static void main(String... args) throws Exception {
Runnable r1 = (Runnable & Serializable) System::gc;
Runnable r2 = (Runnable & Serializable & I) System::gc;
test(r1);
System.out.println();
test(r2);
}
public static void test(Object o1) throws Exception {
System.out.printf("Starting object %s implements %s%n", o1, Arrays.asList(o1.getClass().getInterfaces()));
try (ByteArrayOutputStream outBytes = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(outBytes)) {
out.writeObject(o1);
out.flush();
try (ByteArrayInputStream inBytes = new ByteArrayInputStream(outBytes.toByteArray());
ObjectInputStream in = new ObjectInputStream(inBytes)) {
Object o2 = in.readObject();
System.out.printf("Deserialized object %s implements %s%n", o2, Arrays.asList(o2.getClass().getInterfaces()));
}
}
}
}
This program prints:
Starting object LambdaSerialization$$Lambda$1/989110044@404b9385 implements [interface java.lang.Runnable, interface java.io.Serializable]
Deserialized object LambdaSerialization$$Lambda$4/284720968@b4c966a implements [interface java.lang.Runnable, interface java.io.Serializable]
Starting object LambdaSerialization$$Lambda$2/1096979270@2f4d3709 implements [interface java.lang.Runnable, interface LambdaSerialization$I, interface java.io.Serializable]
Deserialized object LambdaSerialization$$Lambda$4/284720968@b4c966a implements [interface java.lang.Runnable, interface java.io.Serializable]
--------
The API deficiency is reported in JDK-8174864. Possible ways forward:
- Wait for JDK-8174864 to be addressed, then adapt $deserializeLambda$ code-gen logic
- Detect when a serialized form clash will occur (different LambdaMetafactory parameters, same SerializedLambda), and generate a lambda bridge for the second occurrence
- *Always* generate a lambda bridge when, say, FLAG_BRIDGES or FLAG_MARKERS would be needed.
--------
Test:
import java.util.Arrays;
import java.io.*;
public class LambdaSerialization {
interface I {}
public static void main(String... args) throws Exception {
Runnable r1 = (Runnable & Serializable) System::gc;
Runnable r2 = (Runnable & Serializable & I) System::gc;
test(r1);
System.out.println();
test(r2);
}
public static void test(Object o1) throws Exception {
System.out.printf("Starting object %s implements %s%n", o1, Arrays.asList(o1.getClass().getInterfaces()));
try (ByteArrayOutputStream outBytes = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(outBytes)) {
out.writeObject(o1);
out.flush();
try (ByteArrayInputStream inBytes = new ByteArrayInputStream(outBytes.toByteArray());
ObjectInputStream in = new ObjectInputStream(inBytes)) {
Object o2 = in.readObject();
System.out.printf("Deserialized object %s implements %s%n", o2, Arrays.asList(o2.getClass().getInterfaces()));
}
}
}
}
This program prints:
Starting object LambdaSerialization$$Lambda$1/989110044@404b9385 implements [interface java.lang.Runnable, interface java.io.Serializable]
Deserialized object LambdaSerialization$$Lambda$4/284720968@b4c966a implements [interface java.lang.Runnable, interface java.io.Serializable]
Starting object LambdaSerialization$$Lambda$2/1096979270@2f4d3709 implements [interface java.lang.Runnable, interface LambdaSerialization$I, interface java.io.Serializable]
Deserialized object LambdaSerialization$$Lambda$4/284720968@b4c966a implements [interface java.lang.Runnable, interface java.io.Serializable]
--------
The API deficiency is reported in JDK-8174864. Possible ways forward:
- Wait for JDK-8174864 to be addressed, then adapt $deserializeLambda$ code-gen logic
- Detect when a serialized form clash will occur (different LambdaMetafactory parameters, same SerializedLambda), and generate a lambda bridge for the second occurrence
- *Always* generate a lambda bridge when, say, FLAG_BRIDGES or FLAG_MARKERS would be needed.
- relates to
-
JDK-8282080 Lambda deserialization fails for Object method references on interfaces
- Closed
-
JDK-8154236 Deserialization of lambda causes ClassCastException
- Open
-
JDK-8174864 SerializedLambda does not preserve markers & bridges
- In Progress