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