Fixed bug 497879 - [1.8][compiler][codegen] Serializable lambda does not
work for constructor references
Change-Id: Idcb64d6348d55c99ee26a46f65857a560a663737
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SerializableLambdaTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SerializableLambdaTest.java
index 63820b8..18e554d 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SerializableLambdaTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SerializableLambdaTest.java
@@ -2012,7 +2012,152 @@
},
options);
}
-
+ public void testbug497879() {
+ this.runConformTest(
+ new String[]{
+ "LambdaSerializationTest.java",
+ "import java.io.ByteArrayInputStream;\n" +
+ "import java.io.ByteArrayOutputStream;\n" +
+ "import java.io.IOException;\n" +
+ "import java.io.ObjectInputStream;\n" +
+ "import java.io.ObjectOutputStream;\n" +
+ "import java.io.Serializable;\n" +
+ "import java.util.ArrayList;\n" +
+ "import java.util.List;\n" +
+ "import java.util.function.Supplier;\n" +
+ "public class LambdaSerializationTest {\n" +
+ " interface SerializableSupplier<T> extends Supplier<T>, Serializable {}\n" +
+ " public static void constructorReferenceSerialization() throws IOException, ClassNotFoundException {\n" +
+ " SerializableSupplier<List<?>> function = ArrayList::new; //Collections::emptyList;\n" +
+ " Object result = serializeDeserialize(function);\n" +
+ " Class<?>[] infs = result.getClass().getInterfaces();\n" +
+ " for(int i = 0; i < infs.length; i++) {\n" +
+ " System.out.println(infs[i]);\n" +
+ " }\n" +
+ " }\n" +
+ " private static Object serializeDeserialize(Object obj) throws IOException, ClassNotFoundException {\n" +
+ " try (\n" +
+ " ByteArrayOutputStream buffer = new ByteArrayOutputStream(); //\n" +
+ " ObjectOutputStream output = new ObjectOutputStream(buffer)) {\n" +
+ " output.writeObject(obj);\n" +
+ " try (ObjectInputStream input = new ObjectInputStream(new ByteArrayInputStream(buffer.toByteArray()))) {\n" +
+ " return input.readObject();\n" +
+ " }\n" +
+ " }\n" +
+ " }\n" +
+ " public static void main(String[] args) {\n" +
+ " try {\n" +
+ " LambdaSerializationTest.constructorReferenceSerialization();\n" +
+ " } catch (ClassNotFoundException | IOException e) {\n" +
+ " // TODO Auto-generated catch block\n" +
+ " e.printStackTrace();\n" +
+ " }\n" +
+ " }\n" +
+ "}"
+ },
+ "interface LambdaSerializationTest$SerializableSupplier",
+ null,true,
+ new String[]{"-Ddummy"});
+ }
+ public void testbug497879a() {
+ this.runConformTest(
+ new String[]{
+ "LambdaSerializationTest.java",
+ "import java.io.ByteArrayInputStream;\n" +
+ "import java.io.ByteArrayOutputStream;\n" +
+ "import java.io.IOException;\n" +
+ "import java.io.ObjectInputStream;\n" +
+ "import java.io.ObjectOutputStream;\n" +
+ "import java.io.Serializable;\n" +
+ "import java.util.ArrayList;\n" +
+ "import java.util.List;\n" +
+ "import java.util.function.Supplier;\n" +
+ "public class LambdaSerializationTest {\n" +
+ " interface SerializableSupplier<T> extends Supplier<T>, Serializable {}\n" +
+ " static class Junk {\n" +
+ " private Junk() {}\n" +
+ " }\n" +
+ " public static void constructorReferenceSerialization() throws IOException, ClassNotFoundException {\n" +
+ " SerializableSupplier<Junk> function = Junk::new;\n" +
+ " Object result = serializeDeserialize(function);\n" +
+ " Class<?>[] infs = result.getClass().getInterfaces();\n" +
+ " for(int i = 0; i < infs.length; i++) {\n" +
+ " System.out.println(infs[i]);\n" +
+ " }\n" +
+ " }\n" +
+ " private static Object serializeDeserialize(Object obj) throws IOException, ClassNotFoundException {\n" +
+ " try (\n" +
+ " ByteArrayOutputStream buffer = new ByteArrayOutputStream(); //\n" +
+ " ObjectOutputStream output = new ObjectOutputStream(buffer)) {\n" +
+ " output.writeObject(obj);\n" +
+ " try (ObjectInputStream input = new ObjectInputStream(new ByteArrayInputStream(buffer.toByteArray()))) {\n" +
+ " return input.readObject();\n" +
+ " }\n" +
+ " }\n" +
+ " }\n" +
+ " public static void main(String[] args) {\n" +
+ " try {\n" +
+ " LambdaSerializationTest.constructorReferenceSerialization();\n" +
+ " } catch (ClassNotFoundException | IOException e) {\n" +
+ " // TODO Auto-generated catch block\n" +
+ " e.printStackTrace();\n" +
+ " }\n" +
+ " }\n" +
+ "}"
+ },
+ "interface LambdaSerializationTest$SerializableSupplier",
+ null,true,
+ new String[]{"-Ddummy"});
+ }
+ public void testbug497879b() {
+ this.runConformTest(
+ new String[]{
+ "LambdaSerializationTest.java",
+ "import java.io.ByteArrayInputStream;\n" +
+ "import java.io.ByteArrayOutputStream;\n" +
+ "import java.io.IOException;\n" +
+ "import java.io.ObjectInputStream;\n" +
+ "import java.io.ObjectOutputStream;\n" +
+ "import java.io.Serializable;\n" +
+ "import java.util.ArrayList;\n" +
+ "import java.util.List;\n" +
+ "import java.util.function.Supplier;\n" +
+ "public class LambdaSerializationTest {\n" +
+ " interface SerializableSupplier<T> extends Serializable {\n" +
+ " T get(int count);\n" +
+ " }\n" +
+ " public static void constructorReferenceSerialization() throws IOException, ClassNotFoundException {\n" +
+ " SerializableSupplier<List[]> function = ArrayList[]::new;\n" +
+ " Object result = serializeDeserialize(function);\n" +
+ " Class<?>[] infs = result.getClass().getInterfaces();\n" +
+ " for(int i = 0; i < infs.length; i++) {\n" +
+ " System.out.println(infs[i]);\n" +
+ " }\n" +
+ " }\n" +
+ " private static Object serializeDeserialize(Object obj) throws IOException, ClassNotFoundException {\n" +
+ " try (\n" +
+ " ByteArrayOutputStream buffer = new ByteArrayOutputStream(); //\n" +
+ " ObjectOutputStream output = new ObjectOutputStream(buffer)) {\n" +
+ " output.writeObject(obj);\n" +
+ " try (ObjectInputStream input = new ObjectInputStream(new ByteArrayInputStream(buffer.toByteArray()))) {\n" +
+ " return input.readObject();\n" +
+ " }\n" +
+ " }\n" +
+ " }\n" +
+ " public static void main(String[] args) {\n" +
+ " try {\n" +
+ " LambdaSerializationTest.constructorReferenceSerialization();\n" +
+ " } catch (ClassNotFoundException | IOException e) {\n" +
+ " // TODO Auto-generated catch block\n" +
+ " e.printStackTrace();\n" +
+ " }\n" +
+ " }\n" +
+ "}"
+ },
+ "interface LambdaSerializationTest$SerializableSupplier",
+ null,true,
+ new String[]{"-Ddummy"});
+ }
// ---
private void checkExpected(String expected, String actual) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java
index aec0d2a..55db27c 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java
@@ -293,9 +293,6 @@
}
}
}
- if (this.isSerializable) {
- sourceType.addSyntheticMethod(this);
- }
int pc = codeStream.position;
StringBuffer buffer = new StringBuffer();
int argumentsSize = 0;
@@ -349,6 +346,9 @@
buffer.append('L');
buffer.append(this.resolvedType.constantPoolName());
buffer.append(';');
+ if (this.isSerializable) {
+ sourceType.addSyntheticMethod(this);
+ }
int invokeDynamicNumber = codeStream.classFile.recordBootstrapMethod(this);
codeStream.invokeDynamic(invokeDynamicNumber, argumentsSize, 1, this.descriptor.selector, buffer.toString().toCharArray(),
this.isConstructorReference(), (this.lhs instanceof TypeReference? (TypeReference) this.lhs : null), this.typeArguments);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java
index 448a720..f21c3ba 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java
@@ -2646,6 +2646,8 @@
methodKind = ClassFileConstants.MethodHandleRefKindInvokeStatic;
} else if (mb.isPrivate()) {
methodKind = ClassFileConstants.MethodHandleRefKindInvokeSpecial;
+ } else if (mb.isConstructor()) {
+ methodKind = ClassFileConstants.MethodHandleRefKindNewInvokeSpecial;
} else {
methodKind = ClassFileConstants.MethodHandleRefKindInvokeVirtual;
}