| /******************************************************************************* |
| * Copyright (c) 2014, 2017 GoPivotal, Inc. and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for |
| * Bug 405104 - [1.8][compiler][codegen] Implement support for serializeable lambdas |
| * Bug 439889 - [1.8][compiler] [lambda] Deserializing lambda fails with IllegalArgumentException: "Invalid lambda deserialization" |
| * Bug 442416 - $deserializeLambda$ missing cases for nested lambdas |
| * Bug 442418 - $deserializeLambda$ off-by-one error when deserializing the captured arguments of a lambda that also capture this |
| * Bug 449467 - [1.8][compiler] Invalid lambda deserialization with anonymous class |
| * Olivier Tardieu tardieu@us.ibm.com - Contributions for |
| * Bug 442416 - $deserializeLambda$ missing cases for nested lambdas |
| * Bug 442418 - $deserializeLambda$ off-by-one error when deserializing the captured arguments of a lambda that also capture this |
| * IBM Corporation - Additional tests |
| *******************************************************************************/ |
| package org.eclipse.jdt.core.tests.compiler.regression; |
| |
| import java.io.File; |
| import java.lang.reflect.Modifier; |
| import java.util.Map; |
| |
| import org.eclipse.jdt.core.ToolFactory; |
| import org.eclipse.jdt.core.util.ClassFileBytesDisassembler; |
| import org.eclipse.jdt.core.util.IBootstrapMethodsEntry; |
| import org.eclipse.jdt.core.util.IClassFileAttribute; |
| import org.eclipse.jdt.core.util.IClassFileReader; |
| import org.eclipse.jdt.core.util.IConstantPool; |
| import org.eclipse.jdt.core.util.IConstantPoolConstant; |
| import org.eclipse.jdt.core.util.IConstantPoolEntry; |
| import org.eclipse.jdt.core.util.IConstantPoolEntry2; |
| import org.eclipse.jdt.core.util.IMethodInfo; |
| import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; |
| import org.eclipse.jdt.internal.core.util.BootstrapMethodsAttribute; |
| |
| import junit.framework.Test; |
| |
| @SuppressWarnings({ "unchecked", "rawtypes" }) |
| public class SerializableLambdaTest extends AbstractRegressionTest { |
| |
| static { |
| // TESTS_NUMBERS = new int [] { 40 }; |
| // TESTS_NAMES = new String[] { "testTypeVariable" }; |
| } |
| |
| public static Class testClass() { |
| return SerializableLambdaTest.class; |
| } |
| public static Test suite() { |
| return buildMinimalComplianceTestSuite(testClass(), F_1_8); |
| } |
| public SerializableLambdaTest(String testName){ |
| super(testName); |
| } |
| |
| // Enables the tests to run individually |
| @Override |
| protected Map getCompilerOptions() { |
| Map defaultOptions = super.getCompilerOptions(); |
| defaultOptions.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_8); |
| defaultOptions.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_8); |
| defaultOptions.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_8); |
| return defaultOptions; |
| } |
| |
| public static final String RUNNER_CLASS = |
| "public class Y {\n"+ |
| " public static void main(String[]args) {\n"+ |
| " com.foo.X.main(args);\n"+ |
| " }\n"+ |
| "}"; |
| |
| private static final String HELPER_CLASS = |
| "package util;\n"+ |
| "import java.io.*;\n"+ |
| "public class Helper {\n"+ |
| "public static void print(Object o ) {System.err.println(o);}\n"+ |
| "static byte[][] data;\n"+ |
| "\n"+ |
| "public static void write(Object o) { write(0,o); }\n"+ |
| "public static void write(int i, Object o) {\n"+ |
| " if (data==null) data=new byte[10][];\n"+ |
| " try {\n"+ |
| " ByteArrayOutputStream baos = new ByteArrayOutputStream();\n"+ |
| " ObjectOutputStream oos = new ObjectOutputStream(baos);\n"+ |
| " oos.writeObject(o);\n"+ |
| " oos.flush();\n"+ |
| " oos.close();\n"+ |
| " data[i] = baos.toByteArray();\n"+ |
| " } catch (Exception e) {\n"+ |
| " }\n"+ |
| "}\n"+ |
| "\n"+ |
| "public static Object read() { return read(0); }\n"+ |
| "public static Object read(int i) {\n"+ |
| " try {\n"+ |
| " ByteArrayInputStream bais = new ByteArrayInputStream(data[i]);\n"+ |
| " ObjectInputStream ois = new ObjectInputStream(bais);\n"+ |
| " Object o = ois.readObject();\n"+ |
| " ois.close();\n"+ |
| " return o;\n"+ |
| " } catch (Exception e) {\n"+ |
| " }\n"+ |
| " return null;\n"+ |
| "}\n"+ |
| "}\n"; |
| |
| /** |
| * Verifies that after deserializing it is usable, also that the bootstrap methods attribute indicates use of altMetafactory |
| */ |
| public void test001_simple() throws Exception { |
| this.runConformTest( |
| new String[]{ |
| "X.java", |
| "import java.io.*;\n"+ |
| "public class X {\n"+ |
| " interface Foo extends Serializable { int m(); }\n"+ |
| "\n"+ |
| " public static void main(String[] args) {\n"+ |
| " Foo f1 = null;\n"+ |
| " f1 = () -> 3;\n"+ |
| " util.Helper.write(f1);\n"+ |
| " f1 = (Foo)util.Helper.read();\n"+ |
| " System.out.println(f1.m());\n"+ |
| " }\n"+ |
| "}\n", |
| "Helper.java",HELPER_CLASS, |
| }, |
| "3", |
| null, |
| true, |
| new String [] { "-Ddummy" }); // Not sure, unless we force the VM to not be reused by passing dummy vm argument, the generated program aborts midway through its execution. |
| String expectedOutput = |
| "0: invokestatic java/lang/invoke/LambdaMetafactory.altMetafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;\n"+ |
| " Method arguments:\n"+ |
| " ()I\n"+ |
| " invokestatic X.lambda$0:()I\n"+ |
| " ()I\n"+ |
| " 1\n"; |
| String data = printBootstrapMethodsAttribute(OUTPUT_DIR + File.separator + "X.class"); |
| checkExpected(expectedOutput,data); |
| } |
| |
| /** |
| * Sanity test, non serializable should have bootstrap methods attribute reference to metafactory. |
| */ |
| public void test002_simpleNonSerializable() throws Exception { |
| this.runConformTest( |
| new String[]{ |
| "X.java", |
| "import java.io.*;\n"+ |
| "public class X {\n"+ |
| " interface Foo { int m(); }\n"+ |
| "\n"+ |
| " public static void main(String[] args) {\n"+ |
| " Foo f1 = null;\n"+ |
| " f1 = () -> 3;\n"+ |
| " System.out.println(f1.m());\n"+ |
| " }\n"+ |
| "}\n", |
| "Helper.java",HELPER_CLASS, |
| }, |
| "3"); |
| String expectedOutput = |
| "0: invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;\n"+ |
| " Method arguments:\n"+ |
| " ()I\n"+ |
| " invokestatic X.lambda$0:()I\n"+ |
| " ()I\n"; |
| String data = printBootstrapMethodsAttribute(OUTPUT_DIR + File.separator + "X.class"); |
| checkExpected(expectedOutput,data); |
| } |
| |
| /** |
| * Basic test that deserializeLambda can cope with two lambda expressions. |
| */ |
| public void test003_twoSerializedLambdas() throws Exception { |
| this.runConformTest( |
| new String[]{ |
| "X.java", |
| "import java.io.*;\n"+ |
| "public class X {\n"+ |
| " interface Foo extends Serializable { int m(); }\n"+ |
| "\n"+ |
| " public static void main(String[] args) {\n"+ |
| " Foo f1 = null, f2 = null;\n"+ |
| " f1 = () -> 33;\n"+ |
| " f2 = () -> 99;\n"+ |
| " util.Helper.write(0,f1);\n"+ |
| " util.Helper.write(1,f2);\n"+ |
| " f2 = (Foo)util.Helper.read(1);\n"+ |
| " f1 = (Foo)util.Helper.read(0);\n"+ |
| " System.out.println(f1.m());\n"+ |
| " System.out.println(f2.m());\n"+ |
| " }\n"+ |
| "}\n", |
| "Helper.java",HELPER_CLASS, |
| }, |
| "33\n99", |
| null, |
| true, |
| new String [] { "-Ddummy" }); // Not sure, unless we force the VM to not be reused by passing dummy vm argument, the generated program aborts midway through its execution. |
| String expectedOutput = |
| "0: invokestatic java/lang/invoke/LambdaMetafactory.altMetafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;\n"+ |
| " Method arguments:\n"+ |
| " ()I\n"+ |
| " invokestatic X.lambda$0:()I\n"+ |
| " ()I\n"+ |
| " 1\n"+ |
| "1: invokestatic java/lang/invoke/LambdaMetafactory.altMetafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;\n"+ |
| " Method arguments:\n"+ |
| " ()I\n"+ |
| " invokestatic X.lambda$1:()I\n"+ |
| " ()I\n"+ |
| " 1\n"; |
| String data = printBootstrapMethodsAttribute(OUTPUT_DIR + File.separator + "X.class"); |
| checkExpected(expectedOutput,data); |
| } |
| |
| public void test004_lambdaWithParameterInPackage() throws Exception { |
| this.runConformTest( |
| new String[]{ |
| "Y.java", |
| "public class Y {\n"+ |
| " public static void main(String[]args) {\n"+ |
| " com.foo.X.main(args);\n"+ |
| " }\n"+ |
| "}", |
| "X.java", |
| "package com.foo;\n"+ |
| "import java.io.*;\n"+ |
| "public class X {\n"+ |
| " interface Foo extends Serializable { int m(int i); }\n"+ |
| "\n"+ |
| " public static void main(String[] args) {\n"+ |
| " Foo f1 = null, f2 = null;\n"+ |
| " f1 = (i) -> i*2;\n"+ |
| " util.Helper.write(f1);\n"+ |
| " f1 = (Foo)util.Helper.read();\n"+ |
| " System.out.println(f1.m(4));\n"+ |
| " }\n"+ |
| "}\n", |
| "Helper.java",HELPER_CLASS, |
| }, |
| "8", |
| null, |
| true, |
| new String [] { "-Ddummy" }); // Not sure, unless we force the VM to not be reused by passing dummy vm argument, the generated program aborts midway through its execution. |
| String expectedOutput = |
| "0: invokestatic java/lang/invoke/LambdaMetafactory.altMetafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;\n"+ |
| " Method arguments:\n"+ |
| " (I)I\n"+ |
| " invokestatic com/foo/X.lambda$0:(I)I\n"+ |
| " (I)I\n"+ |
| " 1\n"; |
| String data = printBootstrapMethodsAttribute(OUTPUT_DIR + File.separator + "com"+File.separator+"foo"+File.separator+"X.class"); |
| checkExpected(expectedOutput,data); |
| } |
| |
| public void test005_capturingVariableLambdaWithParameterInPackage() throws Exception { |
| this.runConformTest( |
| new String[]{ |
| "Y.java", |
| "public class Y {\n"+ |
| " public static void main(String[]args) {\n"+ |
| " com.foo.X.main(args);\n"+ |
| " }\n"+ |
| "}", |
| "X.java", |
| "package com.foo;\n"+ |
| "import java.io.*;\n"+ |
| "public class X {\n"+ |
| " interface Foo extends Serializable { int m(int i); }\n"+ |
| "\n"+ |
| " public static void main(String[] args) {\n"+ |
| " Foo f1 = null;\n"+ |
| " int multiplier = 3;\n"+ |
| " f1 = (i) -> i * multiplier;\n"+ |
| " util.Helper.write(f1);\n"+ |
| " f1 = (Foo)util.Helper.read();\n"+ |
| " System.out.println(f1.m(4));\n"+ |
| " }\n"+ |
| "}\n", |
| "Helper.java",HELPER_CLASS, |
| }, |
| "12", |
| null, |
| true, |
| new String [] { "-Ddummy" }); // Not sure, unless we force the VM to not be reused by passing dummy vm argument, the generated program aborts midway through its execution. |
| String expectedOutput = |
| "0: invokestatic java/lang/invoke/LambdaMetafactory.altMetafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;\n"+ |
| " Method arguments:\n"+ |
| " (I)I\n"+ |
| " invokestatic com/foo/X.lambda$0:(II)I\n"+ |
| " (I)I\n"+ |
| " 1\n"; |
| String data = printBootstrapMethodsAttribute(OUTPUT_DIR + File.separator + "com"+File.separator+"foo"+File.separator+"X.class"); |
| checkExpected(expectedOutput,data); |
| } |
| |
| // differing types, not just int |
| public void test006_capturingVariableLambdaWithParameterInPackage() throws Exception { |
| this.runConformTest( |
| new String[]{ |
| "Y.java", |
| "public class Y {\n"+ |
| " public static void main(String[]args) {\n"+ |
| " com.foo.X.main(args);\n"+ |
| " }\n"+ |
| "}", |
| "X.java", |
| "package com.foo;\n"+ |
| "import java.io.*;\n"+ |
| "public class X {\n"+ |
| " interface Foo extends Serializable { int m(String n); }\n"+ |
| "\n"+ |
| " public static void main(String[] args) {\n"+ |
| " Foo f1 = null;\n"+ |
| " int multiplier = 3;\n"+ |
| " f1 = (n) -> Integer.valueOf(n) * multiplier;\n"+ |
| " util.Helper.write(f1);\n"+ |
| " f1 = (Foo)util.Helper.read();\n"+ |
| " System.out.println(f1.m(\"33\"));\n"+ |
| " }\n"+ |
| "}\n", |
| "Helper.java",HELPER_CLASS, |
| }, |
| "99", |
| null, |
| true, |
| new String [] { "-Ddummy" }); // Not sure, unless we force the VM to not be reused by passing dummy vm argument, the generated program aborts midway through its execution. |
| String expectedOutput = |
| "0: invokestatic java/lang/invoke/LambdaMetafactory.altMetafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;\n"+ |
| " Method arguments:\n"+ |
| " (Ljava/lang/String;)I\n"+ |
| " invokestatic com/foo/X.lambda$0:(ILjava/lang/String;)I\n"+ |
| " (Ljava/lang/String;)I\n"+ |
| " 1\n"; |
| String data = printBootstrapMethodsAttribute(OUTPUT_DIR + File.separator + "com"+File.separator+"foo"+File.separator+"X.class"); |
| checkExpected(expectedOutput,data); |
| } |
| |
| // Fails the same way as javac right now... with NPE (b120) |
| public void xtest007_capturingFieldLambdaWithParameterInPackage() throws Exception { |
| this.runConformTest( |
| new String[]{ |
| "Y.java", |
| "public class Y {\n"+ |
| " public static void main(String[]args) {\n"+ |
| " com.foo.X.main(args);\n"+ |
| " }\n"+ |
| "}", |
| "X.java", |
| "package com.foo;\n"+ |
| "import java.io.*;\n"+ |
| "public class X {\n"+ |
| " int multiplier = 3;\n"+ |
| " interface Foo extends Serializable { int m(int i); }\n"+ |
| "\n"+ |
| " public static void main(String[] args) {\n"+ |
| " new X().run();\n"+ |
| " }\n"+ |
| " public void run() {\n"+ |
| " Foo f1 = null;\n"+ |
| " f1 = (i) -> i * this.multiplier;\n"+ |
| " util.Helper.write(f1);\n"+ |
| " f1 = (Foo)util.Helper.read();\n"+ |
| " System.out.println(f1.m(4));\n"+ |
| " }\n"+ |
| "}\n", |
| "Helper.java",HELPER_CLASS, |
| }, |
| "12", |
| null, |
| true, |
| new String [] { "-Ddummy" }); // Not sure, unless we force the VM to not be reused by passing dummy vm argument, the generated program aborts midway through its execution. |
| String expectedOutput = |
| "0: invokestatic java/lang/invoke/LambdaMetafactory.altMetafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;\n"+ |
| " Method arguments:\n"+ |
| " (I)I\n"+ |
| " invokestatic com/foo/X.lambda$0:(II)I\n"+ |
| " (I)I\n"+ |
| " 1\n"; |
| String data = printBootstrapMethodsAttribute(OUTPUT_DIR + File.separator + "com"+File.separator+"foo"+File.separator+"X.class"); |
| checkExpected(expectedOutput,data); |
| } |
| |
| public void test008_capturingTwoVariableLambdaWithParameterInPackage() throws Exception { |
| this.runConformTest( |
| new String[]{ |
| "Y.java", |
| "public class Y {\n"+ |
| " public static void main(String[]args) {\n"+ |
| " com.foo.X.main(args);\n"+ |
| " }\n"+ |
| "}", |
| "X.java", |
| "package com.foo;\n"+ |
| "import java.io.*;\n"+ |
| "public class X {\n"+ |
| " interface Foo extends Serializable { float m(int i, float f); }\n"+ |
| "\n"+ |
| " public static void main(String[] args) {\n"+ |
| " new X().run();\n"+ |
| " }\n"+ |
| " public void run() {\n"+ |
| " Foo f1 = null;\n"+ |
| " f1 = (i,f) -> ((float)i) * f;\n"+ |
| " util.Helper.write(f1);\n"+ |
| " f1 = (Foo)util.Helper.read();\n"+ |
| " System.out.println(f1.m(3,4.0f));\n"+ |
| " }\n"+ |
| "}\n", |
| "Helper.java",HELPER_CLASS, |
| }, |
| "12.0", |
| null, |
| true, |
| new String [] { "-Ddummy" }); // Not sure, unless we force the VM to not be reused by passing dummy vm argument, the generated program aborts midway through its execution. |
| String expectedOutput = |
| "0: invokestatic java/lang/invoke/LambdaMetafactory.altMetafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;\n"+ |
| " Method arguments:\n"+ |
| " (IF)F\n"+ |
| " invokestatic com/foo/X.lambda$0:(IF)F\n"+ |
| " (IF)F\n"+ |
| " 1\n"; |
| String data = printBootstrapMethodsAttribute(OUTPUT_DIR + File.separator + "com"+File.separator+"foo"+File.separator+"X.class"); |
| checkExpected(expectedOutput,data); |
| } |
| |
| public void test009_capturingTwoSlotVariablesLambdaWithParameterInPackage() throws Exception { |
| this.runConformTest( |
| new String[]{ |
| "Y.java",RUNNER_CLASS, |
| "X.java", |
| "package com.foo;\n"+ |
| "import java.io.*;\n"+ |
| "public class X {\n"+ |
| " interface Foo extends Serializable { double m(int i, long l); }\n"+ |
| "\n"+ |
| " public static void main(String[] args) {\n"+ |
| " new X().run();\n"+ |
| " }\n"+ |
| " public void run() {\n"+ |
| " Foo f1 = null;\n"+ |
| " f1 = (i,l) -> (double)(i*l);\n"+ |
| " util.Helper.write(f1);\n"+ |
| " f1 = (Foo)util.Helper.read();\n"+ |
| " System.out.println(f1.m(3,40L));\n"+ |
| " }\n"+ |
| "}\n", |
| "Helper.java",HELPER_CLASS, |
| }, |
| "120.0", |
| null, |
| true, |
| new String [] { "-Ddummy" }); // Not sure, unless we force the VM to not be reused by passing dummy vm argument, the generated program aborts midway through its execution. |
| String expectedOutput = |
| "0: invokestatic java/lang/invoke/LambdaMetafactory.altMetafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;\n"+ |
| " Method arguments:\n"+ |
| " (IJ)D\n"+ |
| " invokestatic com/foo/X.lambda$0:(IJ)D\n"+ |
| " (IJ)D\n"+ |
| " 1\n"; |
| String data = printBootstrapMethodsAttribute(OUTPUT_DIR + File.separator + "com"+File.separator+"foo"+File.separator+"X.class"); |
| checkExpected(expectedOutput,data); |
| } |
| |
| public void test010_VarargsLambdaExpression() throws Exception { |
| this.runConformTest( |
| new String[]{ |
| "Y.java",RUNNER_CLASS, |
| "X.java", |
| "package com.foo;\n"+ |
| "import java.io.*;\n"+ |
| "public class X {\n"+ |
| " interface Foo extends Serializable { String m(String... ss); }\n"+ |
| "\n"+ |
| " public static void main(String[] args) {\n"+ |
| " new X().run();\n"+ |
| " }\n"+ |
| " public void run() {\n"+ |
| " Foo f1 = null;\n"+ |
| " f1 = (strings) -> strings[0]+strings[1];\n"+ |
| " util.Helper.write(f1);\n"+ |
| " f1 = (Foo)util.Helper.read();\n"+ |
| " System.out.println(f1.m(\"abc\",\"def\"));\n"+ |
| " }\n"+ |
| "}\n", |
| "Helper.java",HELPER_CLASS, |
| }, |
| "abcdef", |
| null, |
| true, |
| new String [] { "-Ddummy" }); // Not sure, unless we force the VM to not be reused by passing dummy vm argument, the generated program aborts midway through its execution. |
| String expectedOutput = |
| "0: invokestatic java/lang/invoke/LambdaMetafactory.altMetafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;\n"+ |
| " Method arguments:\n"+ |
| " ([Ljava/lang/String;)Ljava/lang/String;\n"+ |
| " invokestatic com/foo/X.lambda$0:([Ljava/lang/String;)Ljava/lang/String;\n"+ |
| " ([Ljava/lang/String;)Ljava/lang/String;\n"+ |
| " 1\n"; |
| String data = printBootstrapMethodsAttribute(OUTPUT_DIR + File.separator + "com"+File.separator+"foo"+File.separator+"X.class"); |
| checkExpected(expectedOutput,data); |
| } |
| |
| // Fails same way as javac right now... with an NPE (b120) |
| public void xtest011_CapturingInstance() throws Exception { |
| this.runConformTest( |
| new String[]{ |
| "Y.java",RUNNER_CLASS, |
| "X.java", |
| "package com.foo;\n"+ |
| "import java.io.*;\n"+ |
| "public class X {\n"+ |
| " interface Foo extends Serializable { String m(); }\n"+ |
| "\n"+ |
| " String fieldValue = \"hello\";\n"+ |
| " public static void main(String[] args) {\n"+ |
| " new X().run();\n"+ |
| " }\n"+ |
| " public void run() {\n"+ |
| " Foo f1 = null;\n"+ |
| " f1 = () -> this.fieldValue;\n"+ |
| " util.Helper.write(f1);\n"+ |
| " f1 = (Foo)util.Helper.read();\n"+ |
| " System.out.println(f1.m());\n"+ |
| " }\n"+ |
| "}\n", |
| "Helper.java",HELPER_CLASS, |
| }, |
| "abcdef", |
| null, |
| true, |
| new String [] { "-Ddummy" }); // Not sure, unless we force the VM to not be reused by passing dummy vm argument, the generated program aborts midway through its execution. |
| String expectedOutput = |
| "0: invokestatic java/lang/invoke/LambdaMetafactory.altMetafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;\n"+ |
| " Method arguments:\n"+ |
| " ([Ljava/lang/String;)Ljava/lang/String;\n"+ |
| " invokestatic com/foo/X.lambda$0:([Ljava/lang/String;)Ljava/lang/String;\n"+ |
| " ([Ljava/lang/String;)Ljava/lang/String;\n"+ |
| " 1\n"; |
| String data = printBootstrapMethodsAttribute(OUTPUT_DIR + File.separator + "com"+File.separator+"foo"+File.separator+"X.class"); |
| checkExpected(expectedOutput,data); |
| } |
| |
| public void test012_intersectionCast() throws Exception { |
| this.runConformTest( |
| new String[]{ |
| "X.java", |
| "import java.io.*;\n"+ |
| "public class X {\n"+ |
| " interface Foo extends Serializable { int m(); }\n"+ |
| " interface Marker {}\n"+ |
| "\n"+ |
| " public static void main(String[] args) {\n"+ |
| " Foo f1 = null;\n"+ |
| " f1 = (Foo & Marker) () -> 3;\n"+ |
| " System.out.println(\"isMarker?\"+(f1 instanceof Marker));\n"+ |
| " util.Helper.write(f1);\n"+ |
| " f1 = (Foo)util.Helper.read();\n"+ |
| " System.out.println(f1.m());\n"+ |
| " System.out.println(\"isMarker?\"+(f1 instanceof Marker));\n"+ |
| " }\n"+ |
| "}\n", |
| "Helper.java",HELPER_CLASS, |
| }, |
| "isMarker?true\n3\nisMarker?true", |
| null, |
| true, |
| new String [] { "-Ddummy" }); // Not sure, unless we force the VM to not be reused by passing dummy vm argument, the generated program aborts midway through its execution. |
| String expectedOutput = |
| "0: invokestatic java/lang/invoke/LambdaMetafactory.altMetafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;\n"+ |
| " Method arguments:\n"+ |
| " ()I\n"+ |
| " invokestatic X.lambda$0:()I\n"+ |
| " ()I\n"+ |
| " 3\n"+ // BitFlags: 0x01 = FLAG_SERIALIZABLE 0x02 = FLAG_MARKER |
| " 1\n"+ // Marker interface count |
| " X$Marker\n"; |
| String data = printBootstrapMethodsAttribute(OUTPUT_DIR + File.separator + "X.class"); |
| checkExpected(expectedOutput,data); |
| } |
| |
| public void test013_intersectionCast() throws Exception { |
| this.runConformTest( |
| new String[]{ |
| "X.java", |
| "import java.io.*;\n"+ |
| "interface Goo {}\n"+ |
| "public class X {\n"+ |
| " interface Foo extends Serializable { int m(); }\n"+ |
| " interface Marker {}\n"+ |
| "\n"+ |
| " public static void main(String[] args) {\n"+ |
| " Foo f1 = null;\n"+ |
| " f1 = (Foo & Goo & Serializable & Marker) () -> 3;\n"+ |
| " System.out.println(\"isMarker?\"+(f1 instanceof Marker));\n"+ |
| " System.out.println(\"isGoo?\"+(f1 instanceof Goo));\n"+ |
| " System.out.println(\"isSerializable?\"+(f1 instanceof Serializable));\n"+ |
| " util.Helper.write(f1);\n"+ |
| " f1 = (Foo)util.Helper.read();\n"+ |
| " System.out.println(f1.m());\n"+ |
| " System.out.println(\"isMarker?\"+(f1 instanceof Marker));\n"+ |
| " System.out.println(\"isGoo?\"+(f1 instanceof Goo));\n"+ |
| " System.out.println(\"isSerializable?\"+(f1 instanceof Serializable));\n"+ |
| " }\n"+ |
| "}\n", |
| "Helper.java",HELPER_CLASS, |
| }, |
| "isMarker?true\nisGoo?true\nisSerializable?true\n3\nisMarker?true\nisGoo?true\nisSerializable?true", |
| null, |
| true, |
| new String [] { "-Ddummy" }); // Not sure, unless we force the VM to not be reused by passing dummy vm argument, the generated program aborts midway through its execution. |
| String expectedOutput = |
| "0: invokestatic java/lang/invoke/LambdaMetafactory.altMetafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;\n"+ |
| " Method arguments:\n"+ |
| " ()I\n"+ |
| " invokestatic X.lambda$0:()I\n"+ |
| " ()I\n"+ |
| " 3\n"+ // BitFlags: 0x01 = FLAG_SERIALIZABLE 0x02 = FLAG_MARKER |
| " 2\n"+ // Marker interface count |
| " Goo\n"+ |
| " X$Marker\n"; |
| String data = printBootstrapMethodsAttribute(OUTPUT_DIR + File.separator + "X.class"); |
| checkExpected(expectedOutput,data); |
| } |
| |
| public void test014_intersectionCastAndNotSerializable() throws Exception { |
| this.runConformTest( |
| new String[]{ |
| "X.java", |
| "import java.io.*;\n"+ |
| "interface Goo {}\n"+ |
| "public class X {\n"+ |
| " interface Foo { int m(); }\n"+ |
| " interface Marker {}\n"+ |
| "\n"+ |
| " public static void main(String[] args) {\n"+ |
| " Foo f1 = null;\n"+ |
| " f1 = (Foo & Goo & Marker) () -> 3;\n"+ |
| " System.out.println(\"isMarker?\"+(f1 instanceof Marker));\n"+ |
| " System.out.println(\"isGoo?\"+(f1 instanceof Goo));\n"+ |
| " System.out.println(\"isSerializable?\"+(f1 instanceof Serializable));\n"+ |
| " System.out.println(f1.m());\n"+ |
| " }\n"+ |
| "}\n", |
| "Helper.java",HELPER_CLASS, |
| }, |
| "isMarker?true\nisGoo?true\nisSerializable?false\n3", |
| null, |
| true, |
| new String [] { "-Ddummy" }); // Not sure, unless we force the VM to not be reused by passing dummy vm argument, the generated program aborts midway through its execution. |
| String expectedOutput = |
| "0: invokestatic java/lang/invoke/LambdaMetafactory.altMetafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;\n"+ |
| " Method arguments:\n"+ |
| " ()I\n"+ |
| " invokestatic X.lambda$0:()I\n"+ |
| " ()I\n"+ |
| " 2\n"+ // BitFlags: 0x02 = FLAG_MARKER |
| " 2\n"+ // Marker interface count |
| " Goo\n"+ |
| " X$Marker\n"; |
| String data = printBootstrapMethodsAttribute(OUTPUT_DIR + File.separator + "X.class"); |
| checkExpected(expectedOutput,data); |
| } |
| |
| public void test015_serializableViaIntersectionCast() throws Exception { |
| this.runConformTest( |
| new String[]{ |
| "X.java", |
| "import java.io.*;\n"+ |
| "interface Goo {}\n"+ |
| "public class X {\n"+ |
| " interface Foo { int m(); }\n"+ |
| " interface Marker {}\n"+ |
| "\n"+ |
| " public static void main(String[] args) {\n"+ |
| " Foo f1 = null;\n"+ |
| " f1 = (Foo & Goo & Serializable & Marker) () -> 3;\n"+ |
| " System.out.println(\"isMarker?\"+(f1 instanceof Marker));\n"+ |
| " System.out.println(\"isGoo?\"+(f1 instanceof Goo));\n"+ |
| " System.out.println(\"isSerializable?\"+(f1 instanceof Serializable));\n"+ |
| " util.Helper.write(f1);\n"+ |
| " f1 = (Foo)util.Helper.read();\n"+ |
| " System.out.println(f1.m());\n"+ |
| " System.out.println(\"isMarker?\"+(f1 instanceof Marker));\n"+ |
| " System.out.println(\"isGoo?\"+(f1 instanceof Goo));\n"+ |
| " System.out.println(\"isSerializable?\"+(f1 instanceof Serializable));\n"+ |
| " }\n"+ |
| "}\n", |
| "Helper.java",HELPER_CLASS, |
| }, |
| "isMarker?true\nisGoo?true\nisSerializable?true\n3\nisMarker?true\nisGoo?true\nisSerializable?true", |
| null, |
| true, |
| new String [] { "-Ddummy" }); // Not sure, unless we force the VM to not be reused by passing dummy vm argument, the generated program aborts midway through its execution. |
| String expectedOutput = |
| "0: invokestatic java/lang/invoke/LambdaMetafactory.altMetafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;\n"+ |
| " Method arguments:\n"+ |
| " ()I\n"+ |
| " invokestatic X.lambda$0:()I\n"+ |
| " ()I\n"+ |
| " 3\n"+ // BitFlags: 0x01 = FLAG_SERIALIZABLE 0x02 = FLAG_MARKER |
| " 2\n"+ // Marker interface count |
| " Goo\n"+ |
| " X$Marker\n"; |
| String data = printBootstrapMethodsAttribute(OUTPUT_DIR + File.separator + "X.class"); |
| checkExpected(expectedOutput,data); |
| } |
| |
| // SAM type not first in intersection cast |
| public void test016_bug424211() throws Exception { |
| this.runConformTest( |
| new String[]{ |
| "X.java", |
| "import java.io.Serializable;\n"+ |
| "public class X {\n"+ |
| " public static void main(String argv[]) throws Exception {\n"+ |
| " AutoCloseable one = ((Serializable & AutoCloseable) (() -> {}));\n"+ |
| " one.close();\n"+ |
| " }\n"+ |
| "}" |
| }, |
| "", |
| null, |
| true, |
| new String [] { "-Ddummy" }); // Not sure, unless we force the VM to not be reused by passing dummy vm argument, the generated program aborts midway through its execution. |
| String expectedOutput = |
| "0: invokestatic java/lang/invoke/LambdaMetafactory.altMetafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;\n"+ |
| " Method arguments:\n"+ |
| " ()V\n"+ |
| " invokestatic X.lambda$0:()V\n"+ |
| " ()V\n"+ |
| " 1\n"; |
| String data = printBootstrapMethodsAttribute(OUTPUT_DIR + File.separator + "X.class"); |
| checkExpected(expectedOutput,data); |
| } |
| |
| // Now SAM type first |
| public void test017_bug424211() throws Exception { |
| this.runConformTest( |
| new String[]{ |
| "X.java", |
| "import java.io.Serializable;\n"+ |
| "public class X {\n"+ |
| " public static void main(String argv[]) throws Exception {\n"+ |
| " AutoCloseable one = ((AutoCloseable & Serializable) (() -> {}));\n"+ |
| " one.close();\n"+ |
| " }\n"+ |
| "}" |
| }, |
| "", |
| null, |
| true, |
| new String [] { "-Ddummy" }); // Not sure, unless we force the VM to not be reused by passing dummy vm argument, the generated program aborts midway through its execution. |
| String expectedOutput = |
| "0: invokestatic java/lang/invoke/LambdaMetafactory.altMetafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;\n"+ |
| " Method arguments:\n"+ |
| " ()V\n"+ |
| " invokestatic X.lambda$0:()V\n"+ |
| " ()V\n"+ |
| " 1\n"; |
| String data = printBootstrapMethodsAttribute(OUTPUT_DIR + File.separator + "X.class"); |
| checkExpected(expectedOutput,data); |
| } |
| |
| // Not Serializable but a regular marker interface |
| public void test018_bug424211() throws Exception { |
| this.runConformTest( |
| new String[]{ |
| "X.java", |
| "import java.io.Serializable;\n"+ |
| "interface Marker {}\n"+ |
| "public class X {\n"+ |
| " public static void main(String argv[]) throws Exception {\n"+ |
| " AutoCloseable one = ((Marker & AutoCloseable) (() -> {}));\n"+ |
| " one.close();\n"+ |
| " }\n"+ |
| "}" |
| }, |
| "", |
| null, |
| true, |
| new String [] { "-Ddummy" }); // Not sure, unless we force the VM to not be reused by passing dummy vm argument, the generated program aborts midway through its execution. |
| String expectedOutput = |
| "0: invokestatic java/lang/invoke/LambdaMetafactory.altMetafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;\n"+ |
| " Method arguments:\n"+ |
| " ()V\n"+ |
| " invokestatic X.lambda$0:()V\n"+ |
| " ()V\n"+ |
| " 2\n"+ |
| " 1\n"+ |
| " Marker\n"; |
| String data = printBootstrapMethodsAttribute(OUTPUT_DIR + File.separator + "X.class"); |
| checkExpected(expectedOutput,data); |
| } |
| |
| // Now SAM type not first and serialization occurring |
| public void test019_bug424211() throws Exception { |
| this.runConformTest( |
| new String[]{ |
| "X.java", |
| "import java.io.Serializable;\n"+ |
| "interface SAM {int m();}\n"+ |
| "public class X {\n"+ |
| " public static void main(String argv[]) throws Exception {\n"+ |
| " SAM one = ((Serializable & SAM) (() -> 3));\n"+ |
| " System.out.println(one.m());\n"+ |
| " util.Helper.write(one);\n"+ |
| " one = (SAM)util.Helper.read();\n"+ |
| " System.out.println(one.m());\n"+ |
| " }\n"+ |
| "}", |
| "Helper.java",HELPER_CLASS, |
| }, |
| "3\n3", |
| null, |
| true, |
| new String [] { "-Ddummy" }); // Not sure, unless we force the VM to not be reused by passing dummy vm argument, the generated program aborts midway through its execution. |
| String expectedOutput = |
| "0: invokestatic java/lang/invoke/LambdaMetafactory.altMetafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;\n"+ |
| " Method arguments:\n"+ |
| " ()I\n"+ |
| " invokestatic X.lambda$0:()I\n"+ |
| " ()I\n"+ |
| " 1\n"; |
| String data = printBootstrapMethodsAttribute(OUTPUT_DIR + File.separator + "X.class"); |
| checkExpected(expectedOutput,data); |
| } |
| |
| public void test020_lambdaNames() throws Exception { |
| this.runConformTest( |
| new String[]{ |
| "X.java", |
| "import java.io.Serializable;\n"+ |
| "interface Foo {int m();}\n"+ |
| "interface FooN extends Serializable {int m();}\n"+ |
| "public class X {\n"+ |
| " public static void main(String argv[]) throws Exception {\n"+ |
| " AutoCloseable one = () -> {};\n"+ |
| " new X().m();\n"+ |
| " one.close();\n"+ |
| " }\n"+ |
| " public void m() { Foo f = () -> 3; System.out.println(f.m());}\n"+ |
| " public void n() { FooN f = () -> 3; System.out.println(f.m());}\n"+ |
| "}" |
| }, |
| "3", |
| null, |
| true, |
| new String [] { "-Ddummy" }); // Not sure, unless we force the VM to not be reused by passing dummy vm argument, the generated program aborts midway through its execution. |
| String expectedOutput = |
| " private static synthetic void lambda$0() throws java.lang.Exception;\n"; |
| checkDisassembledClassFile(OUTPUT_DIR + File.separator + "X.class", "X", expectedOutput, ClassFileBytesDisassembler.SYSTEM); |
| expectedOutput = |
| " private static synthetic int lambda$1();\n"; |
| checkDisassembledClassFile(OUTPUT_DIR + File.separator + "X.class", "X", expectedOutput, ClassFileBytesDisassembler.SYSTEM); |
| } |
| |
| public void test021_lambdaNamesVariants() throws Exception { |
| this.runConformTest( |
| new String[]{ |
| "X.java", |
| "import java.io.Serializable;\n"+ |
| "interface Foo {int m();}\n"+ |
| "interface FooSer extends Serializable {int m();}\n"+ |
| "interface FooI {int m(int i);}\n"+ |
| "interface FooSerI extends Serializable {int m(int i);}\n"+ |
| "public class X {\n"+ |
| "\n"+ |
| " Foo instanceField = () -> 1;\n"+ |
| " FooSer instanceFieldSer = () -> 2;\n"+ |
| " static Foo staticField = () -> 3;\n"+ |
| " static FooSer staticFieldSer = () -> 4;\n"+ |
| " FooI instanceFieldI = (i) -> 5;\n"+ |
| " FooSerI instanceFieldSerI = (i) -> 6;\n"+ |
| "\n"+ |
| " public static void main(String argv[]) throws Exception {\n"+ |
| " int x = 4;\n"+ |
| " Foo a = () -> 1;\n"+ |
| " FooSer b = () -> 2;\n"+ |
| " FooI c = (i) -> 3;\n"+ |
| " FooSerI d = (i) -> 4;\n"+ |
| " Foo e = () -> x;\n"+ |
| " FooSer f = () -> x+1;\n"+ |
| " FooI g = (i) -> x+2;\n"+ |
| " FooSerI h = (i) -> x+3;\n"+ |
| " }\n"+ |
| "}" |
| }, |
| "", |
| null, |
| true, |
| new String [] { "-Ddummy" }); // Not sure, unless we force the VM to not be reused by passing dummy vm argument, the generated program aborts midway through its execution. |
| String expectedOutput = |
| "static lambda$2()I\n"+ |
| "static lambda$3()I\n"+ |
| "static lambda$0()I\n"+ |
| "static lambda$1()I\n"+ |
| "static lambda$4(I)I\n"+ |
| "static lambda$5(I)I\n"+ |
| "static lambda$6()I\n"+ |
| "static lambda$7()I\n"+ |
| "static lambda$8(I)I\n"+ |
| "static lambda$9(I)I\n"+ |
| "static lambda$10(I)I\n"+ |
| "static lambda$11(I)I\n"+ |
| "static lambda$12(II)I\n"+ |
| "static lambda$13(II)I\n"; |
| String actualOutput = printLambdaMethods(OUTPUT_DIR + File.separator + "X.class"); |
| if (!actualOutput.equals(expectedOutput)) { |
| printIt(actualOutput); |
| assertEquals(expectedOutput,actualOutput); |
| } |
| } |
| |
| public void test022_nestedLambdas() throws Exception { |
| this.runConformTest( |
| new String[]{ |
| "X.java", |
| "import java.io.Serializable;\n"+ |
| "interface Foo extends Serializable {int m();}\n"+ |
| "public class X {\n"+ |
| " public static void main(String argv[]) throws Exception {\n"+ |
| " Foo f = () -> { return ((Foo)()->33).m();};\n"+ |
| " System.out.println(f.m());\n"+ |
| " util.Helper.write(f);\n"+ |
| " f = (Foo)util.Helper.read();\n"+ |
| " System.out.println(f.m());\n"+ |
| " }\n"+ |
| "}", |
| "Helper.java",HELPER_CLASS, |
| }, |
| "33\n33", |
| null, |
| true, |
| new String [] { "-Ddummy" }); // Not sure, unless we force the VM to not be reused by passing dummy vm argument, the generated program aborts midway through its execution. |
| String expectedOutput = |
| "0: invokestatic java/lang/invoke/LambdaMetafactory.altMetafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;\n"+ |
| " Method arguments:\n"+ |
| " ()I\n"+ |
| " invokestatic X.lambda$0:()I\n"+ |
| " ()I\n"+ |
| " 1\n"+ |
| "1: invokestatic java/lang/invoke/LambdaMetafactory.altMetafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;\n"+ |
| " Method arguments:\n"+ |
| " ()I\n"+ |
| " invokestatic X.lambda$1:()I\n"+ |
| " ()I\n"+ |
| " 1\n"; |
| String data = printBootstrapMethodsAttribute(OUTPUT_DIR + File.separator + "X.class"); |
| checkExpected(expectedOutput,data); |
| } |
| |
| public void test023_lambdasInOtherPlaces_Field() throws Exception { |
| this.runConformTest( |
| new String[]{ |
| "X.java", |
| "import java.io.Serializable;\n"+ |
| "interface Foo extends Serializable {int m();}\n"+ |
| "public class X {\n"+ |
| " Foo f = () -> 99;\n" + |
| " public static void main(String argv[]) throws Exception {\n"+ |
| " new X().run();\n"+ |
| " }\n"+ |
| " public void run() {\n"+ |
| " System.out.println(f.m());\n"+ |
| " util.Helper.write(f);\n"+ |
| " f = (Foo)util.Helper.read();\n"+ |
| " System.out.println(f.m());\n"+ |
| " }\n"+ |
| "}", |
| "Helper.java",HELPER_CLASS, |
| }, |
| "99\n99", |
| null, |
| true, |
| new String [] { "-Ddummy" }); // Not sure, unless we force the VM to not be reused by passing dummy vm argument, the generated program aborts midway through its execution. |
| String expectedOutput = |
| "0: invokestatic java/lang/invoke/LambdaMetafactory.altMetafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;\n"+ |
| " Method arguments:\n"+ |
| " ()I\n"+ |
| " invokestatic X.lambda$0:()I\n"+ |
| " ()I\n"+ |
| " 1\n"; |
| String data = printBootstrapMethodsAttribute(OUTPUT_DIR + File.separator + "X.class"); |
| checkExpected(expectedOutput,data); |
| } |
| |
| public void test024_lambdasInOtherPlaces_MethodParameter() throws Exception { |
| this.runConformTest( |
| new String[]{ |
| "X.java", |
| "import java.io.Serializable;\n"+ |
| "interface Foo extends Serializable {int m();}\n"+ |
| "public class X {\n"+ |
| " public static void main(String argv[]) throws Exception {\n"+ |
| " new X().run(()->33);\n"+ |
| " }\n"+ |
| " public void run(Foo f) {\n"+ |
| " System.out.println(f.m());\n"+ |
| " util.Helper.write(f);\n"+ |
| " f = (Foo)util.Helper.read();\n"+ |
| " System.out.println(f.m());\n"+ |
| " }\n"+ |
| "}", |
| "Helper.java",HELPER_CLASS, |
| }, |
| "33\n33", |
| null, |
| true, |
| new String [] { "-Ddummy" }); // Not sure, unless we force the VM to not be reused by passing dummy vm argument, the generated program aborts midway through its execution. |
| String expectedOutput = |
| "0: invokestatic java/lang/invoke/LambdaMetafactory.altMetafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;\n"+ |
| " Method arguments:\n"+ |
| " ()I\n"+ |
| " invokestatic X.lambda$0:()I\n"+ |
| " ()I\n"+ |
| " 1\n"; |
| String data = printBootstrapMethodsAttribute(OUTPUT_DIR + File.separator + "X.class"); |
| checkExpected(expectedOutput,data); |
| } |
| |
| public void test025_lambdasWithGenericInferencing() throws Exception { |
| this.runConformTest( |
| new String[]{ |
| "X.java", |
| "import java.io.Serializable;\n"+ |
| "import java.util.function.*;\n"+ |
| "public class X {\n"+ |
| " public static void main(String argv[]) throws Exception {\n"+ |
| " new X().run();\n"+ |
| " }\n"+ |
| " public void run() {\n"+ |
| " IntFunction<Integer> times3 = (IntFunction<Integer> & Serializable) (triple) -> 3 * triple;\n"+ |
| " System.out.println(times3.apply(4));\n"+ |
| " util.Helper.write(times3);\n"+ |
| " times3 = (IntFunction<Integer>)util.Helper.read();\n"+ |
| " System.out.println(times3.apply(4));\n"+ |
| " }\n"+ |
| "}", |
| "Helper.java",HELPER_CLASS, |
| }, |
| "12\n12", |
| null, |
| true, |
| new String [] { "-Ddummy" }); // Not sure, unless we force the VM to not be reused by passing dummy vm argument, the generated program aborts midway through its execution. |
| String expectedOutput = |
| "0: invokestatic java/lang/invoke/LambdaMetafactory.altMetafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;\n"+ |
| " Method arguments:\n"+ |
| " (I)Ljava/lang/Object;\n"+ |
| " invokestatic X.lambda$0:(I)Ljava/lang/Integer;\n"+ |
| " (I)Ljava/lang/Integer;\n"+ |
| " 1\n"; |
| String data = printBootstrapMethodsAttribute(OUTPUT_DIR + File.separator + "X.class"); |
| checkExpected(expectedOutput,data); |
| } |
| public void test026_lambdasInOtherPlaces_Clinit() throws Exception { |
| this.runConformTest( |
| new String[]{ |
| "X.java", |
| "import java.io.Serializable;\n"+ |
| "interface Foo extends Serializable {int m();}\n"+ |
| "public class X {\n"+ |
| " static {\n"+ |
| " Foo f = () -> 99;\n" + |
| " }\n"+ |
| " public static void main(String argv[]) throws Exception {\n"+ |
| " new X().run();\n"+ |
| " }\n"+ |
| " public void run() {\n"+ |
| " Foo f = ()->99;\n"+ |
| " System.out.println(f.m());\n"+ |
| " util.Helper.write(f);\n"+ |
| " f = (Foo)util.Helper.read();\n"+ |
| " System.out.println(f.m());\n"+ |
| " }\n"+ |
| "}", |
| "Helper.java",HELPER_CLASS, |
| }, |
| "99\n99", |
| null, |
| true, |
| new String [] { "-Ddummy" }); // Not sure, unless we force the VM to not be reused by passing dummy vm argument, the generated program aborts midway through its execution. |
| String expectedOutput = |
| "0: invokestatic java/lang/invoke/LambdaMetafactory.altMetafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;\n"+ |
| " Method arguments:\n"+ |
| " ()I\n"+ |
| " invokestatic X.lambda$0:()I\n"+ |
| " ()I\n"+ |
| " 1\n"+ |
| "1: invokestatic java/lang/invoke/LambdaMetafactory.altMetafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;\n"+ |
| " Method arguments:\n"+ |
| " ()I\n"+ |
| " invokestatic X.lambda$1:()I\n"+ |
| " ()I\n"+ |
| " 1\n"; |
| String data = printBootstrapMethodsAttribute(OUTPUT_DIR + File.separator + "X.class"); |
| checkExpected(expectedOutput,data); |
| } |
| |
| // https://bugs.eclipse.org/bugs/show_bug.cgi?id=449467 - [1.8][compiler] Invalid lambda deserialization with anonymous class |
| public void test449467() throws Exception { |
| this.runConformTest( |
| new String[]{ |
| "TestClass.java", |
| "import java.io.ByteArrayInputStream;\n"+ |
| "import java.io.ByteArrayOutputStream;\n"+ |
| "import java.io.ObjectInputStream;\n"+ |
| "import java.io.ObjectOutputStream;\n"+ |
| "import java.io.Serializable;\n"+ |
| "\n"+ |
| "public class TestClass implements Serializable {\n"+ |
| " String msg = \"HEY!\";\n"+ |
| " OtherClass other;\n"+ |
| "\n"+ |
| " public TestClass(StringBuilder sb) {\n"+ |
| " other = new OtherClass() {\n"+ |
| " {\n"+ |
| " other2 = new OtherClass2((Runnable & Serializable) () -> {\n"+ |
| " sb.length();\n"+ |
| " say();\n"+ |
| " });\n"+ |
| " }\n"+ |
| " };\n"+ |
| " }\n"+ |
| "\n"+ |
| " public void say() {\n"+ |
| " System.out.println(msg);\n"+ |
| " }\n"+ |
| "\n"+ |
| " public static void main(String[] args) throws Exception {\n"+ |
| " ByteArrayOutputStream buffer = new ByteArrayOutputStream();\n"+ |
| " try (ObjectOutputStream out = new ObjectOutputStream(buffer)) {\n"+ |
| " out.writeObject(new TestClass(new StringBuilder()));\n"+ |
| " }\n"+ |
| " try (ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(buffer.toByteArray()))) {\n"+ |
| " TestClass s = (TestClass) in.readObject();\n"+ |
| " s.say();\n"+ |
| " }\n"+ |
| " }\n"+ |
| "}\n"+ |
| "\n"+ |
| "class OtherClass implements Serializable {\n"+ |
| " OtherClass2 other2;\n"+ |
| "}\n"+ |
| "\n"+ |
| "class OtherClass2 implements Serializable {\n"+ |
| " Runnable runnable;\n"+ |
| "\n"+ |
| " public OtherClass2(Runnable runnable) {\n"+ |
| " this.runnable = runnable;\n"+ |
| " }\n"+ |
| "}\n" |
| }, |
| "HEY!", |
| null, |
| true, |
| new String [] { "-Ddummy" }); // Not sure, unless we force the VM to not be reused by passing dummy vm argument, the generated program aborts midway through its execution. |
| } |
| |
| public void test449467_2() throws Exception { |
| this.runConformTest( |
| new String[]{ |
| "com/foo/TestClass.java", |
| "package com.foo;\n"+ |
| "import java.io.ByteArrayInputStream;\n"+ |
| "import java.io.ByteArrayOutputStream;\n"+ |
| "import java.io.ObjectInputStream;\n"+ |
| "import java.io.ObjectOutputStream;\n"+ |
| "import java.io.Serializable;\n"+ |
| "public class TestClass implements Serializable {\n"+ |
| " String msg = \"HEY!\";\n"+ |
| " OtherClass other;\n"+ |
| "\n"+ |
| " public TestClass(StringBuilder sb) {\n"+ |
| " other = new OtherClass() {\n"+ |
| " {\n"+ |
| " other2 = new OtherClass2((Runnable & Serializable) () -> {\n"+ |
| " sb.length();\n"+ |
| " say();\n"+ |
| " });\n"+ |
| " }\n"+ |
| " };\n"+ |
| " }\n"+ |
| "\n"+ |
| " public void say() {\n"+ |
| " System.out.println(msg);\n"+ |
| " }\n"+ |
| "\n"+ |
| " public static void main(String[] args) throws Exception {\n"+ |
| " ByteArrayOutputStream buffer = new ByteArrayOutputStream();\n"+ |
| " try (ObjectOutputStream out = new ObjectOutputStream(buffer)) {\n"+ |
| " out.writeObject(new TestClass(new StringBuilder()));\n"+ |
| " }\n"+ |
| " try (ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(buffer.toByteArray()))) {\n"+ |
| " TestClass s = (TestClass) in.readObject();\n"+ |
| " s.say();\n"+ |
| " }\n"+ |
| " }\n"+ |
| "}\n"+ |
| "\n"+ |
| "class OtherClass implements Serializable {\n"+ |
| " OtherClass2 other2;\n"+ |
| "}\n"+ |
| "\n"+ |
| "class OtherClass2 implements Serializable {\n"+ |
| " Runnable runnable;\n"+ |
| "\n"+ |
| " public OtherClass2(Runnable runnable) {\n"+ |
| " this.runnable = runnable;\n"+ |
| " }\n"+ |
| "}\n" |
| }, |
| "HEY!", |
| null, |
| true, |
| new String [] { "-Ddummy" }); // Not sure, unless we force the VM to not be reused by passing dummy vm argument, the generated program aborts midway through its execution. |
| } |
| |
| // https://bugs.eclipse.org/bugs/show_bug.cgi?id=428552, [1.8][compiler][codegen] Serialization does not work for method references |
| public void test428552() throws Exception { |
| this.runConformTest( |
| new String[]{ |
| "X.java", |
| "import java.io.*;\n" + |
| "public class X {\n" + |
| " interface Example extends Serializable {\n" + |
| " String convert(X o);\n" + |
| " }\n" + |
| " public static void main(String[] args) throws IOException {\n" + |
| " Example e=X::toString;\n" + |
| " util.Helper.write(e);\n"+ |
| " e = (Example)util.Helper.read();\n"+ |
| " System.out.println(e.convert(new X()));\n"+ |
| " }\n" + |
| " public String toString() {\n" + |
| " return \"XItIs\";\n" + |
| " }\n" + |
| "}\n", |
| "Helper.java",HELPER_CLASS, |
| }, |
| "XItIs", |
| null, |
| true, |
| new String [] { "-Ddummy" }); // Not sure, unless we force the VM to not be reused by passing dummy vm argument, the generated program aborts midway through its execution. |
| } |
| |
| // https://bugs.eclipse.org/bugs/show_bug.cgi?id=428642 |
| public void test428642() throws Exception { |
| this.runConformTest( |
| new String[]{ |
| "QuickSerializedLambdaTest.java", |
| "import java.io.*;\n"+ |
| "import java.util.function.IntConsumer;\n"+ |
| "\n"+ |
| "public class QuickSerializedLambdaTest {\n"+ |
| " interface X extends IntConsumer,Serializable{}\n"+ |
| " public static void main(String[] args) throws IOException, ClassNotFoundException {\n"+ |
| " X x2 = System::exit; // method reference\n"+ |
| " ByteArrayOutputStream debug=new ByteArrayOutputStream();\n"+ |
| " try(ObjectOutputStream oo=new ObjectOutputStream(debug))\n"+ |
| " {\n"+ |
| " oo.writeObject(x2);\n"+ |
| " }\n"+ |
| " try(ObjectInputStream oi=new ObjectInputStream(new ByteArrayInputStream(debug.toByteArray())))\n"+ |
| " {\n"+ |
| " X x=(X)oi.readObject();\n"+ |
| " x.accept(0);// shall exit\n"+ |
| " }\n"+ |
| " throw new AssertionError(\"should not reach this point\");\n"+ |
| " }\n"+ |
| "}\n", |
| "Helper.java", |
| "public class Helper {\n"+ |
| " public static String tostring(java.lang.invoke.SerializedLambda sl) {\n"+ |
| " return sl.toString();\n"+ |
| " }\n"+ |
| "}" |
| }, |
| "", |
| null,true, |
| new String[]{"-Ddummy"}); // Not sure, unless we force the VM to not be reused by passing dummy vm argument, the generated program aborts midway through its execution. |
| } |
| |
| public void test428642_2() throws Exception { |
| this.runConformTest( |
| new String[]{ |
| "Helper.java", |
| "public class Helper {\n"+ |
| " public static String tostring(java.lang.invoke.SerializedLambda sl) {\n"+ |
| " return sl.toString();\n"+ |
| " }\n"+ |
| " public static void main(String[]argv) throws Exception {\n"+ |
| " foo.QuickSerializedLambdaTest.main(argv);\n"+ |
| " }\n"+ |
| "}", |
| "QuickSerializedLambdaTest.java", |
| "package foo;\n"+ |
| "import java.io.*;\n"+ |
| "import java.util.function.IntConsumer;\n"+ |
| "\n"+ |
| "public class QuickSerializedLambdaTest {\n"+ |
| " interface X extends IntConsumer,Serializable{}\n"+ |
| " public static void main(String[] args) throws IOException, ClassNotFoundException {\n"+ |
| " X x1 = i -> System.out.println(i);// lambda expression\n"+ |
| " X x2 = System::exit; // method reference\n"+ |
| " ByteArrayOutputStream debug=new ByteArrayOutputStream();\n"+ |
| " try(ObjectOutputStream oo=new ObjectOutputStream(debug))\n"+ |
| " {\n"+ |
| " oo.writeObject(x1);\n"+ |
| " oo.writeObject(x2);\n"+ |
| " }\n"+ |
| " try(ObjectInputStream oi=new ObjectInputStream(new ByteArrayInputStream(debug.toByteArray())))\n"+ |
| " {\n"+ |
| " X x=(X)oi.readObject();\n"+ |
| " x.accept(42);// shall print \"42\"\n"+ |
| " x=(X)oi.readObject();\n"+ |
| " x.accept(0);// shall exit\n"+ |
| " }\n"+ |
| " throw new AssertionError(\"should not reach this point\");\n"+ |
| " }\n"+ |
| "}\n" |
| }, |
| "42", |
| null,true, |
| new String[]{"-Ddummy"}); // Not sure, unless we force the VM to not be reused by passing dummy vm argument, the generated program aborts midway through its execution. |
| } |
| |
| // https://bugs.eclipse.org/bugs/show_bug.cgi?id=429112, [1.8][compiler] Exception when compiling Serializable array constructor reference |
| public void test429112() throws Exception { |
| this.runConformTest( |
| new String[]{ |
| "X.java", |
| "import java.io.*;\n" + |
| "import java.util.function.IntFunction;\n" + |
| "public class X {\n" + |
| " interface IF extends IntFunction<Object>, Serializable {}\n" + |
| " public static void main(String[] args) throws IOException, ClassNotFoundException {\n" + |
| " IF factory=String[]::new;\n" + |
| " Object o = factory.apply(1234);\n" + |
| " ByteArrayOutputStream debug=new ByteArrayOutputStream();\n"+ |
| " try(ObjectOutputStream oo=new ObjectOutputStream(debug))\n"+ |
| " {\n"+ |
| " oo.writeObject(factory);\n"+ |
| " }\n"+ |
| " try(ObjectInputStream oi=new ObjectInputStream(new ByteArrayInputStream(debug.toByteArray())))\n"+ |
| " {\n"+ |
| " IF x = (IF)oi.readObject();\n"+ |
| " Object p = x.apply(1234);\n"+ |
| " System.out.println(p.getClass());\n" + |
| " String [] sa = (String []) p;\n" + |
| " System.out.println(sa.length);\n" + |
| " }\n"+ |
| " }\n"+ |
| "}\n", |
| }, |
| "class [Ljava.lang.String;\n" + |
| "1234", |
| null,true, |
| new String[]{"-Ddummy"}); // Not sure, unless we force the VM to not be reused by passing dummy vm argument, the generated program aborts midway through its execution. |
| } |
| |
| // https://bugs.eclipse.org/bugs/show_bug.cgi?id=439889 - [1.8][compiler] [lambda] Deserializing lambda fails with IllegalArgumentException: "Invalid lambda deserialization" |
| public void test439889() throws Exception { |
| this.runConformTest( |
| new String[]{ |
| "SerializationTest.java", |
| "import java.io.*;\n"+ |
| "\n"+ |
| "public class SerializationTest implements Serializable {\n"+ |
| " interface SerializableRunnable extends Runnable, Serializable {\n"+ |
| " }\n"+ |
| "\n"+ |
| " SerializableRunnable runnable;\n"+ |
| "\n"+ |
| " public SerializationTest() {\n"+ |
| " final SerializationTest self = this;\n"+ |
| " // runnable = () -> self.doSomething();\n"+ |
| " runnable = () -> this.doSomething();\n"+ // results in this method handle: #166 invokespecial SerializationTest.lambda$0:()V |
| " }\n"+ |
| "\n"+ |
| " public void doSomething() {\n"+ |
| " System.out.println(\"Hello,world!\");\n"+ |
| " }\n"+ |
| "\n"+ |
| " public static void main(String[] args) throws Exception {\n"+ |
| " final ByteArrayOutputStream buffer = new ByteArrayOutputStream();\n"+ |
| " try (ObjectOutputStream out = new ObjectOutputStream(buffer) ) {\n"+ |
| " out.writeObject(new SerializationTest());\n"+ |
| " }\n"+ |
| " try (ObjectInputStream in = new ObjectInputStream( new ByteArrayInputStream(buffer.toByteArray()))) {\n"+ |
| " final SerializationTest s = (SerializationTest) in.readObject();\n"+ |
| " s.doSomething();\n"+ |
| " }\n"+ |
| " }\n"+ |
| "}\n" |
| }, |
| "Hello,world!", |
| null,true, |
| new String[]{"-Ddummy"}); // Not sure, unless we force the VM to not be reused by passing dummy vm argument, the generated program aborts midway through its execution. |
| } |
| |
| public void test439889_2() throws Exception { |
| this.runConformTest( |
| new String[]{ |
| "SerializationTest.java", |
| "import java.io.*;\n"+ |
| "\n"+ |
| "public class SerializationTest implements Serializable {\n"+ |
| " interface SerializableRunnable extends Runnable, Serializable {\n"+ |
| " }\n"+ |
| "\n"+ |
| " SerializableRunnable runnable;\n"+ |
| "\n"+ |
| " public SerializationTest() {\n"+ |
| " final SerializationTest self = this;\n"+ |
| " runnable = () -> self.doSomething();\n"+ // results in this method handle: #168 invokestatic SerializationTest.lambda$0:(LSerializationTest;)V |
| " // runnable = () -> this.doSomething();\n"+ |
| " }\n"+ |
| "\n"+ |
| " public void doSomething() {\n"+ |
| " System.out.println(\"Hello,world!\");\n"+ |
| " }\n"+ |
| "\n"+ |
| " public static void main(String[] args) throws Exception {\n"+ |
| " final ByteArrayOutputStream buffer = new ByteArrayOutputStream();\n"+ |
| " try (ObjectOutputStream out = new ObjectOutputStream(buffer) ) {\n"+ |
| " out.writeObject(new SerializationTest());\n"+ |
| " }\n"+ |
| " try (ObjectInputStream in = new ObjectInputStream( new ByteArrayInputStream(buffer.toByteArray()))) {\n"+ |
| " final SerializationTest s = (SerializationTest) in.readObject();\n"+ |
| " s.doSomething();\n"+ |
| " }\n"+ |
| " }\n"+ |
| "}\n" |
| }, |
| "Hello,world!", |
| null,true, |
| new String[]{"-Ddummy"}); // Not sure, unless we force the VM to not be reused by passing dummy vm argument, the generated program aborts midway through its execution. |
| } |
| |
| public void testNestedLambdas_442416() throws Exception { |
| this.runConformTest( |
| new String[]{ |
| "Foo.java", |
| "import java.io.*;\n"+ |
| "public class Foo {\n"+ |
| " static byte[] toSer(Object o) {\n"+ |
| " try {\n"+ |
| " final ByteArrayOutputStream buffer = new ByteArrayOutputStream();\n"+ |
| " try (ObjectOutputStream out = new ObjectOutputStream(buffer) ) {\n"+ |
| " out.writeObject(o);\n"+ |
| " }\n"+ |
| " return buffer.toByteArray();\n"+ |
| " } catch (Exception e) {e.printStackTrace();return null;}\n"+ |
| " }\n"+ |
| " static Object fromSer(byte[] bs) {\n"+ |
| " try {\n"+ |
| " try (ObjectInputStream in = new ObjectInputStream( new ByteArrayInputStream(bs))) {\n"+ |
| " final Object s = in.readObject();\n"+ |
| " return s;\n"+ |
| " }\n"+ |
| " } catch (Exception e) {e.printStackTrace();return null;}\n"+ |
| " }\n"+ |
| " public static void main(String[] args) throws Exception {\n"+ |
| " Runnable nested1,nested2;\n"+ |
| " Runnable lambda0 = (java.io.Serializable & Runnable) () -> {\n"+ |
| " Runnable lambda1 = (java.io.Serializable & Runnable) () -> {\n"+ |
| " Runnable lambda2 = (java.io.Serializable & Runnable) () -> {\n"+ |
| " System.out.println(\"Hello,world!\");\n"+ |
| " };\n"+ |
| " byte[] bs = toSer(lambda2);\n"+ |
| " Runnable r = (Runnable)fromSer(bs);\n"+ |
| " r.run();\n"+ |
| " };\n"+ |
| " byte[] bs = toSer(lambda1);\n"+ |
| " Runnable r = (Runnable)fromSer(bs);\n"+ |
| " r.run();\n"+ |
| " };\n"+ |
| " byte[] bs = toSer(lambda0);\n"+ |
| " Runnable r = (Runnable)fromSer(bs);\n"+ |
| " r.run();\n"+ |
| " }\n"+ |
| "}\n", |
| }, |
| "Hello,world!", |
| null,true, |
| new String[]{"-Ddummy"}); // Not sure, unless we force the VM to not be reused by passing dummy vm argument, the generated program aborts midway through its execution. |
| } |
| |
| public void testBindingThis_442418() throws Exception { |
| this.runConformTest( |
| new String[]{ |
| "Foo.java", |
| "import java.io.*;\n"+ |
| "public class Foo implements Serializable {\n"+ |
| " static byte[] toSer(Object o) {\n"+ |
| " try {\n"+ |
| " final ByteArrayOutputStream buffer = new ByteArrayOutputStream();\n"+ |
| " try (ObjectOutputStream out = new ObjectOutputStream(buffer) ) {\n"+ |
| " out.writeObject(o);\n"+ |
| " }\n"+ |
| " return buffer.toByteArray();\n"+ |
| " } catch (Exception e) {e.printStackTrace();return null;}\n"+ |
| " }\n"+ |
| " static Object fromSer(byte[] bs) {\n"+ |
| " try {\n"+ |
| " try (ObjectInputStream in = new ObjectInputStream( new ByteArrayInputStream(bs))) {\n"+ |
| " final Object s = in.readObject();\n"+ |
| " return s;\n"+ |
| " }\n"+ |
| " } catch (Exception e) {e.printStackTrace();return null;}\n"+ |
| " }\n"+ |
| " void m(int i) {\n"+ |
| " System.out.println(i);\n"+ |
| " }\n"+ |
| " void n(int i) {\n"+ |
| " Runnable lambda = (java.io.Serializable & Runnable) () -> { this.m(i); };\n"+ |
| " byte[] bs = toSer(lambda);\n"+ |
| " Runnable r = (Runnable)fromSer(bs);\n"+ |
| " r.run();\n"+ |
| " }\n"+ |
| " public static void main(String[] args) throws Exception {\n"+ |
| " new Foo().n(42);\n"+ |
| " }\n"+ |
| "}\n", |
| }, |
| "42", |
| null,true, |
| new String[]{"-Ddummy"}); // Not sure, unless we force the VM to not be reused by passing dummy vm argument, the generated program aborts midway through its execution. |
| } |
| |
| public void testbug479119() { |
| this.runConformTest( |
| new String[]{ |
| "Testbed.java", |
| "import java.io.ObjectStreamClass;\n" + |
| "import java.io.Serializable;\n" + |
| "import java.lang.invoke.SerializedLambda;\n" + |
| "import java.lang.reflect.Method;\n" + |
| "import java.util.function.IntFunction;\n" + |
| "import java.util.stream.Stream;\n" + |
| "public class Testbed {\n" + |
| " public static void main(String[] args) {\n" + |
| " System.out.println(getMethod(Testbed::foo).equals(getMethod(Testbed::foo)));\n" + |
| " }\n" + |
| " private static void foo() { }\n" + |
| " static interface MethodRef extends Runnable, Serializable { }\n" + |
| " private static Method getMethod(MethodRef methodRef) {\n" + |
| " try {\n" + |
| " final Method invokeWriteReplaceMethod = ObjectStreamClass.class.getDeclaredMethod(\"invokeWriteReplace\", Object.class);\n" + |
| " invokeWriteReplaceMethod.setAccessible(true);\n" + |
| " final SerializedLambda l = (SerializedLambda)invokeWriteReplaceMethod.invoke(\n" + |
| " ObjectStreamClass.lookupAny(methodRef.getClass()),\n" + |
| " methodRef\n" + |
| " );\n" + |
| " System.out.println(\"Looking for \" + l.getImplClass() + \".\" + l.getImplMethodName());\n" + |
| " final Method[] methods = Stream.of(Class.forName(l.getImplClass()).getDeclaredMethods()).\n" + |
| " filter(m -> m.getName().equals(l.getImplMethodName())).\n" + |
| " toArray(Method[]::new);\n" + |
| " if(methods.length != 1) throw new AssertionError(\"TODO: check signature\");\n" + |
| " return methods[0];\n" + |
| " } catch(Exception e) {\n" + |
| " throw new RuntimeException(e);\n" + |
| " }\n" + |
| " }\n" + |
| "}\n" |
| }, |
| "Looking for Testbed.foo\n" + |
| "Looking for Testbed.foo\n" + |
| "true", |
| null,true, |
| (isJRE9Plus |
| ? new String[] { "--add-opens", "java.base/java.io=ALL-UNNAMED" } |
| : new String [] { "-Ddummy" }) |
| ); |
| |
| |
| String bootstrapEntries = printBootstrapMethodsAttribute(OUTPUT_DIR + File.separator + "Testbed.class"); |
| String expectedOutput = |
| "0: invokestatic java/lang/invoke/LambdaMetafactory.altMetafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;\n"+ |
| " Method arguments:\n"+ |
| " ()V\n"+ |
| " invokestatic Testbed.foo:()V\n"+ |
| " ()V\n"+ |
| " 1\n"+ |
| "1: invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;\n"+ |
| " Method arguments:\n"+ |
| " (Ljava/lang/Object;)Z\n"+ |
| " invokestatic Testbed.lambda$2:(Ljava/lang/invoke/SerializedLambda;Ljava/lang/reflect/Method;)Z\n"+ |
| " (Ljava/lang/reflect/Method;)Z\n"+ |
| "2: invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;\n"+ |
| " Method arguments:\n"+ |
| " (I)Ljava/lang/Object;\n"+ |
| " invokestatic Testbed.lambda$3:(I)[Ljava/lang/reflect/Method;\n"+ |
| " (I)[Ljava/lang/reflect/Method;\n"; |
| |
| checkExpected(expectedOutput, bootstrapEntries); |
| } |
| |
| public void testbug479119a() { |
| this.runConformTest( |
| new String[]{ |
| "Testbed.java", |
| "import java.io.ObjectStreamClass;\n" + |
| "import java.io.Serializable;\n" + |
| "import java.lang.invoke.SerializedLambda;\n" + |
| "import java.lang.reflect.Constructor;\n" + |
| "import java.lang.reflect.Executable;\n" + |
| "import java.lang.reflect.Method;\n" + |
| "import java.util.function.IntFunction;\n" + |
| "import java.util.stream.Stream;\n" + |
| "public class Testbed {\n" + |
| " public static void main(String[] args) {\n" + |
| " System.out.println(getMethod(Testbed::foo).equals(getMethod(Testbed::foo)));\n" + |
| " System.out.println(getMethod(new Foo()::method).equals(getMethod(new Bar()::method)));\n" + |
| " System.out.println(getMethod(MethodRefImpl::new).equals(getMethod(MethodRefImpl::new)));\n" + |
| " }\n" + |
| " static class MethodRefImpl implements MethodRef {\n" + |
| " @Override\n" + |
| " public void run() {}\n" + |
| " }\n" + |
| " public static class Base {\n" + |
| " public void method () {}\n" + |
| " }\n" + |
| " public static class Foo extends Base {}\n" + |
| " public static class Bar extends Base {}\n" + |
| " private static void foo() { }\n" + |
| " static interface MethodRef extends Runnable, Serializable { }\n" + |
| " private static Executable getMethod(MethodRef methodRef) {\n" + |
| " try {\n" + |
| " final Method invokeWriteReplaceMethod = ObjectStreamClass.class.getDeclaredMethod(\"invokeWriteReplace\", Object.class);\n" + |
| " invokeWriteReplaceMethod.setAccessible(true);\n" + |
| " final SerializedLambda l = (SerializedLambda)invokeWriteReplaceMethod.invoke(\n" + |
| " ObjectStreamClass.lookupAny(methodRef.getClass()),\n" + |
| " methodRef\n" + |
| " );\n" + |
| " System.out.println(\"Looking for \" + l.getImplClass() + \".\" + l.getImplMethodName());\n" + |
| " boolean isConstructor = l.getImplMethodName().indexOf(\"<init>\") >= 0;\n" + |
| " final Executable[] methods = Stream.of(isConstructor ? Class.forName(l.getImplClass()).getDeclaredConstructors() : Class.forName(l.getImplClass()).getDeclaredMethods()).\n" + |
| " filter(m -> m.getName().equals(isConstructor ? l.getImplClass() : l.getImplMethodName())).\n" + |
| " toArray(isConstructor ? Constructor[]::new : Method[]::new);\n" + |
| " if(methods.length != 1) throw new AssertionError(\"TODO: check signature\");\n" + |
| " return methods[0];\n" + |
| " } catch(Exception e) {\n" + |
| " throw new RuntimeException(e);\n" + |
| " }\n" + |
| " }\n" + |
| "}\n" |
| }, |
| "Looking for Testbed.foo\n" + |
| "Looking for Testbed.foo\n" + |
| "true\n" + |
| "Looking for Testbed$Base.method\n" + |
| "Looking for Testbed$Base.method\n" + |
| "true\n" + |
| "Looking for Testbed$MethodRefImpl.<init>\n" + |
| "Looking for Testbed$MethodRefImpl.<init>\n" + |
| "true", |
| null,true, |
| (isJRE9Plus |
| ? new String[] { "--add-opens", "java.base/java.io=ALL-UNNAMED" } |
| : new String [] { "-Ddummy" }) |
| ); |
| } |
| |
| // Serializable reference expressions that share the same name |
| public void testbug479119b() { |
| this.runConformTest( |
| new String[]{ |
| "X.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" + |
| "public class X {\n" + |
| " public static interface Consumer<T> extends Serializable {\n" + |
| " void accept(T t);\n" + |
| " }\n" + |
| " public static class Foo {\n" + |
| " public void method () {\n" + |
| " System.out.println(\"Foo\");\n" + |
| " }\n" + |
| " }\n" + |
| " public static class Bar {\n" + |
| " public void method () {\n" + |
| " System.out.println(\"Bar\");\n" + |
| " }\n" + |
| " }\n" + |
| " public static void main (String[] args) throws IOException, ClassNotFoundException {\n" + |
| " Consumer<Foo> foo = Foo::method;\n" + |
| " Consumer<Bar> bar = Bar::method;\n" + |
| " Consumer<Foo> baz = (b) -> {b.method();};\n" + |
| " ByteArrayOutputStream debug=new ByteArrayOutputStream();\n" + |
| " try(ObjectOutputStream oo=new ObjectOutputStream(debug)) {\n" + |
| " oo.writeObject(bar);\n" + |
| " }\n" + |
| " try(ObjectInputStream oi=new ObjectInputStream(new ByteArrayInputStream(debug.toByteArray()))) {\n" + |
| " Consumer<Bar> x = (Consumer)oi.readObject();\n" + |
| " x.accept(new Bar());\n" + |
| " }\n" + |
| " debug.reset();\n" + |
| " try(ObjectOutputStream oo=new ObjectOutputStream(debug)) {\n" + |
| " oo.writeObject(foo);\n" + |
| " }\n" + |
| " try(ObjectInputStream oi=new ObjectInputStream(new ByteArrayInputStream(debug.toByteArray()))) {\n" + |
| " Consumer<Foo> x = (Consumer)oi.readObject();\n" + |
| " x.accept(new Foo());\n" + |
| " }\n" + |
| " }\n" + |
| "}\n" |
| }, |
| "Bar\n" + |
| "Foo", |
| null,true, |
| new String[]{"-Ddummy"}); |
| } |
| public void testbug479119_comment20() { |
| this.runConformTest( |
| new String[]{ |
| "Testbed.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" + |
| "interface FI extends Serializable{\n" + |
| " void run(Testbed args);\n" + |
| "}\n" + |
| "interface IF extends Serializable{\n" + |
| " void run();\n" + |
| "}\n" + |
| "public class Testbed implements Serializable{\n" + |
| " String f;\n" + |
| " Testbed(String str) {\n" + |
| " f = str;\n" + |
| " }\n" + |
| " void test() throws IOException, ClassNotFoundException {\n" + |
| " accept(Testbed::foo);\n" + |
| " accept(this::foo); \n" + |
| " }\n" + |
| " void foo() {\n" + |
| " System.out.println(this.f);\n" + |
| " }\n" + |
| " void accept(FI fi) {\n" + |
| " fi.run(this);\n" + |
| " }\n" + |
| " void accept(IF i) {\n" + |
| " i.run();\n" + |
| " }\n" + |
| " public static void main(String[] args) throws ClassNotFoundException, IOException {\n" + |
| " Testbed t = new Testbed(\"IF\");\n" + |
| " Testbed t2 = new Testbed(\"FI\");\n" + |
| " IF i = t::foo;\n" + |
| " FI f = Testbed::foo;\n" + |
| " ByteArrayOutputStream debug=new ByteArrayOutputStream();\n" + |
| " try(ObjectOutputStream oo=new ObjectOutputStream(debug))\n" + |
| " {\n" + |
| " oo.writeObject(i);\n" + |
| " }\n" + |
| " try(ObjectInputStream oi=new ObjectInputStream(new ByteArrayInputStream(debug.toByteArray())))\n" + |
| " {\n" + |
| " IF x = (IF)oi.readObject();\n" + |
| " t.accept(x);\n" + |
| " }\n" + |
| " debug=new ByteArrayOutputStream();\n" + |
| " try(ObjectOutputStream oo=new ObjectOutputStream(debug))\n" + |
| " {\n" + |
| " oo.writeObject(f);\n" + |
| " }\n" + |
| " try(ObjectInputStream oi=new ObjectInputStream(new ByteArrayInputStream(debug.toByteArray())))\n" + |
| " {\n" + |
| " FI x = (FI)oi.readObject();\n" + |
| " t2.accept(x);\n" + |
| " }\n" + |
| " }\n" + |
| "}" |
| }, |
| "IF\n" + |
| "FI", |
| null,true, |
| new String[]{"-Ddummy"}); |
| } |
| public void testbug485333() { |
| this.runConformTest( |
| new String[]{ |
| "Test.java", |
| "import java.io.ByteArrayInputStream;\n" + |
| "import java.io.ByteArrayOutputStream;\n" + |
| "import java.io.ObjectInputStream;\n" + |
| "import java.io.ObjectOutputStream;\n" + |
| "import java.io.Serializable;\n" + |
| "interface Func<T> extends Serializable {\n" + |
| " T get();\n" + |
| "}\n" + |
| "class Impl implements Serializable {\n" + |
| " int val = 0;\n" + |
| " public int next() {\n" + |
| " val += 1;\n" + |
| " return val;\n" + |
| " }\n" + |
| "}\n" + |
| "public class Test {\n" + |
| " final Impl impl = new Impl();\n" + |
| " final Func<Integer> func = (Func<Integer> & Cloneable)impl::next;\n" + |
| " public void test() throws Throwable {\n" + |
| " byte[] bytes = write(func);//25\n" + |
| " Func<Integer> func = read(bytes);\n" + |
| " System.out.println(func.get());\n" + |
| " }\n" + |
| " public static void main(String[] args) throws Throwable {\n" + |
| " new Test().test();\n" + |
| "}\n" + |
| " @SuppressWarnings(\"unchecked\")\n" + |
| " private static Func<Integer> read(byte[] bytes) throws Exception {\n" + |
| " ByteArrayInputStream bis = new ByteArrayInputStream(bytes);\n" + |
| " try (ObjectInputStream ois = new ObjectInputStream(bis)) {\n" + |
| " return (Func<Integer>) ois.readObject();\n" + |
| " }\n" + |
| " }\n" + |
| " private static byte[] write(Func<Integer> func) throws Exception {\n" + |
| " ByteArrayOutputStream bos = new ByteArrayOutputStream();\n" + |
| " System.out.println(func.get());\n" + |
| " try (ObjectOutputStream oos = new ObjectOutputStream(bos)) {\n" + |
| " oos.writeObject(func);//42\n" + |
| " }\n" + |
| " return bos.toByteArray();\n" + |
| " }\n" + |
| "}" |
| }, |
| "1\n" + |
| "2", |
| null,true, |
| new String[]{"-Ddummy"}); |
| } |
| public void testbug494487() { |
| Map options = getCompilerOptions(); |
| options.put(CompilerOptions.OPTION_LocalVariableAttribute, CompilerOptions.DO_NOT_GENERATE); |
| this.runConformTest( |
| new String[]{ |
| "Test.java", |
| "import java.io.IOException;\n" + |
| "import java.io.Serializable;\n" + |
| "public class Test {\n" + |
| " class AnException extends Exception {\n" + |
| " }\n" + |
| " class Asd {\n" + |
| " public Asd(String asd) { data = asd; }\n" + |
| " private final String data;\n" + |
| " @Override\n" + |
| " public String toString() {\n" + |
| " return data;\n" + |
| " }\n" + |
| " }\n" + |
| " public interface Test1 extends Serializable {\n" + |
| " void test() throws IOException;\n" + |
| " }\n" + |
| " public interface Test2 {\n" + |
| " void test() throws AnException;\n" + |
| " }\n" + |
| " public void test1( Test1 test ) {\n" + |
| " try {\n" + |
| " test.test();\n" + |
| " } catch( IOException e ) {\n" + |
| " e.printStackTrace();\n" + |
| " }\n" + |
| " }\n" + |
| " public void test2( Test2 test ) {\n" + |
| " try {\n" + |
| " test.test();\n" + |
| " } catch( AnException e ) {\n" + |
| " System.out.println( e );\n" + |
| " }\n" + |
| " }\n" + |
| " public void lambdas() {\n" + |
| " test1( () -> System.out.println( \"test a\" ) );\n" + |
| " test1( () -> System.out.println( \"test b\" ) );\n" + |
| " test2( () -> System.out.println( \"test c\" ) );\n" + |
| " test2( () -> System.out.println( \"test d\" ) );\n" + |
| " }\n" + |
| " public void print( CharSequence a, String b, long c ) {\n" + |
| " System.out.println( a );\n" + |
| " System.out.println( b );\n" + |
| " System.out.println( c );\n" + |
| " }\n" + |
| " public void filler() {\n" + |
| " System.out.println( \"Now we need to get this class file closer to 3000 bytes boundary\" );\n" + |
| " filler1();\n" + |
| " filler2();\n" + |
| " filler3();\n" + |
| " filler4();\n" + |
| " filler5();\n" + |
| " filler6();\n" + |
| " filler7();\n" + |
| " filler8();\n" + |
| " filler9();\n" + |
| " filler10();\n" + |
| " filler11();\n" + |
| " filler12();\n" + |
| " filler13();\n" + |
| " filler14();\n" + |
| " filler15();\n" + |
| " filler16();\n" + |
| " filler17();\n" + |
| " filler18();\n" + |
| " filler19();\n" + |
| " filler20();\n" + |
| " filler21();\n" + |
| " filler22();\n" + |
| " filler23();\n" + |
| " filler24();\n" + |
| " filler25();\n" + |
| " filler26();\n" + |
| " filler27();\n" + |
| " filler28();\n" + |
| " print( \"a\", \"b\", System.currentTimeMillis() );\n" + |
| " print( \"a\", \"b\", System.currentTimeMillis() );\n" + |
| " print( \"a\", \"b\", System.currentTimeMillis() );\n" + |
| " print( \"a\", \"b\", System.currentTimeMillis() );\n" + |
| " print( \"a\", \"b\", System.currentTimeMillis() );\n" + |
| " print( \"a\", \"b\", System.currentTimeMillis() );\n" + |
| " }\n" + |
| " private void filler28() {\n" + |
| " print( \"a\", \"b\", System.currentTimeMillis() );\n" + |
| " }\n" + |
| " private void filler27() {\n" + |
| " print( \"a\", \"b\", System.currentTimeMillis() );\n" + |
| " }\n" + |
| " private void filler26() {\n" + |
| " print( \"a\", \"b\", System.currentTimeMillis() );\n" + |
| " }\n" + |
| " private void filler25() {\n" + |
| " print( \"a\", \"b\", System.currentTimeMillis() );\n" + |
| " }\n" + |
| " private void filler24() {\n" + |
| " print( \"a\", \"b\", System.currentTimeMillis() );\n" + |
| " }\n" + |
| " private void filler23() {\n" + |
| " print( \"a\", \"b\", System.currentTimeMillis() );\n" + |
| " }\n" + |
| " private void filler22() {\n" + |
| " print( \"a\", \"b\", System.currentTimeMillis() );\n" + |
| " }\n" + |
| " private void filler21() {\n" + |
| " print( \"a\", \"b\", System.currentTimeMillis() );\n" + |
| " }\n" + |
| " private void filler20() {\n" + |
| " print( \"a\", \"b\", System.currentTimeMillis() );\n" + |
| " }\n" + |
| " private void filler19() {\n" + |
| " print( \"a\", \"b\", System.currentTimeMillis() );\n" + |
| " }\n" + |
| " private void filler18() {\n" + |
| " print( \"a\", \"b\", System.currentTimeMillis() );\n" + |
| " }\n" + |
| " private void filler17() {\n" + |
| " print( \"a\", \"b\", System.currentTimeMillis() );\n" + |
| " }\n" + |
| " private void filler16() {\n" + |
| " print( \"a\", \"b\", System.currentTimeMillis() );\n" + |
| " }\n" + |
| " private void filler15() {\n" + |
| " print( \"a\", \"b\", System.currentTimeMillis() );\n" + |
| " }\n" + |
| " private void filler14() {\n" + |
| " print( \"a\", \"b\", System.currentTimeMillis() );\n" + |
| " }\n" + |
| " private void filler13() {\n" + |
| " print( \"a\", \"b\", System.currentTimeMillis() );\n" + |
| " }\n" + |
| " private void filler12() {\n" + |
| " print( \"a\", \"b\", System.currentTimeMillis() );\n" + |
| " }\n" + |
| " private void filler11() {\n" + |
| " print( \"a\", \"b\", System.currentTimeMillis() );\n" + |
| " }\n" + |
| " private void filler10() {\n" + |
| " print( \"a\", \"b\", System.currentTimeMillis() );\n" + |
| " }\n" + |
| " private void filler9() {\n" + |
| " print( \"a\", \"b\", System.currentTimeMillis() );\n" + |
| " }\n" + |
| " private void filler8() {\n" + |
| " print( \"a\", \"b\", System.currentTimeMillis() );\n" + |
| " }\n" + |
| " private void filler7() {\n" + |
| " print( \"a\", \"b\", System.currentTimeMillis() );\n" + |
| " }\n" + |
| " private void filler6() {\n" + |
| " print( \"a\", \"b\", System.currentTimeMillis() );\n" + |
| " }\n" + |
| " private void filler5() {\n" + |
| " print( c.toString(), d.toString(), System.currentTimeMillis() );\n" + |
| " }\n" + |
| " private void filler4() {\n" + |
| " print( a.toString(), b.toString(), System.currentTimeMillis() );\n" + |
| " }\n" + |
| " private void filler3() {\n" + |
| " print( \"a\", System.getenv( \"asd\" ), System.currentTimeMillis() );\n" + |
| " }\n" + |
| " private void filler2() {\n" + |
| " print( \"a\", System.lineSeparator(), System.currentTimeMillis() );\n" + |
| " }\n" + |
| " private void filler1() {\n" + |
| " print( \"a\", \"b\", System.currentTimeMillis() );\n" + |
| " }\n" + |
| " private final Asd a = new Asd(\"a\");\n" + |
| " private final Asd b = new Asd(\"b\");\n" + |
| " private final Asd c = new Asd(\"c\");\n" + |
| " private final Asd d = new Asd(\"d\");\n" + |
| "}\n" |
| }, |
| 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"}); |
| } |
| public void testbug503118() { |
| this.runConformTest( |
| new String[]{ |
| "lambdabug/App.java", |
| "package lambdabug;\n" + |
| "import java.io.ByteArrayInputStream;\n" + |
| "import java.io.ByteArrayOutputStream;\n" + |
| "import java.io.ObjectInputStream;\n" + |
| "import java.io.ObjectOutputStream;\n" + |
| "import java.io.Serializable;\n" + |
| "import java.util.function.Function;\n" + |
| "public class App {\n" + |
| " public static interface SerialFunction<T, R> extends Function<T, R>, Serializable {\n" + |
| " }\n" + |
| " public static interface TestInterface extends Serializable {\n" + |
| " public Integer method(Integer i);\n" + |
| " }\n" + |
| " public static class TestClass implements TestInterface {\n" + |
| " private static final long serialVersionUID = 1L;\n" + |
| " @Override\n" + |
| " public Integer method(Integer i) {\n" + |
| " return i;\n" + |
| " }\n" + |
| " }\n" + |
| " public static void main(String[] args) throws Exception {\n" + |
| " TestInterface testService = getService();\n" + |
| " SerialFunction<Integer, Integer> sf = testService::method;\n" + |
| " ByteArrayOutputStream bos = new ByteArrayOutputStream();\n" + |
| " new ObjectOutputStream(bos).writeObject(sf);\n" + |
| " Object o = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray())).readObject();\n" + |
| " System.out.println(o.getClass().getInterfaces()[0]);\n" + |
| " }\n" + |
| " private static TestInterface getService() {\n" + |
| " return new TestClass();\n" + |
| " }\n" + |
| "}\n" |
| }, |
| "interface lambdabug.App$SerialFunction", |
| null,true, |
| new String[]{"-Ddummy"}); |
| } |
| public void testbug507011() { |
| this.runConformTest( |
| new String[]{ |
| "VerifyErrorDerived.java", |
| "import java.io.Serializable;\n" + |
| "import java.util.function.Function;\n" + |
| "public class VerifyErrorDerived extends VerifyErrorBase {\n" + |
| " public static void main(String [] args) {\n" + |
| " System.out.println(\"hello world\");\n" + |
| " }\n" + |
| " public int derivedMethod(String param) {\n" + |
| " SerializableFunction<String, Integer> f = super::baseMethod;\n" + |
| " return f.apply(param);\n" + |
| " }\n" + |
| "}\n" + |
| "interface SerializableFunction<T, R> extends Function<T, R>, Serializable {}", |
| "VerifyErrorBase.java", |
| "public class VerifyErrorBase {\n" + |
| " public int baseMethod(String param) {\n" + |
| " return 7;\n" + |
| " }\n" + |
| "}\n" |
| }, |
| "hello world", |
| null,true, |
| new String[]{"-Ddummy"}); |
| } |
| public void testbug509782() { |
| this.runConformTest( |
| new String[]{ |
| "compilertest/BaseType.java", |
| "package compilertest;\n" + |
| "import java.io.ByteArrayInputStream;\n" + |
| "import java.io.ByteArrayOutputStream;\n" + |
| "import java.io.ObjectInputStream;\n" + |
| "import java.io.ObjectOutputStream;\n" + |
| "import java.io.Serializable;\n" + |
| "import compilertest.sub.SubType;\n" + |
| "public class BaseType implements Serializable {\n" + |
| " protected void doSomething() {\n" + |
| " }\n" + |
| " public static void main(String[] args) throws Exception {\n" + |
| " SubType instance = new SubType();\n" + |
| " ByteArrayOutputStream bs = new ByteArrayOutputStream();\n" + |
| " ObjectOutputStream out = new ObjectOutputStream(bs);\n" + |
| " out.writeObject(instance);\n" + |
| " byte[] data = bs.toByteArray();\n" + |
| " ObjectInputStream in = new ObjectInputStream(\n" + |
| " new ByteArrayInputStream(data));\n" + |
| " in.readObject();\n" + |
| " System.out.println(\"Done\");\n" + |
| " }\n" + |
| "}", |
| "compilertest/sub/SubType.java", |
| "package compilertest.sub;\n" + |
| "import java.io.Serializable;\n" + |
| "import compilertest.BaseType;\n" + |
| "public class SubType extends BaseType {\n" + |
| " Runnable task = (Runnable & Serializable) this::doSomething;\n" + |
| "}\n" |
| }, |
| "Done", |
| null,true, |
| new String[]{"-Ddummy"}); |
| } |
| public void testbug566155() { |
| // method reference must be compiled as an implicit lambda expression |
| // else it cannot be serialized correctly |
| this.runConformTest(new String[] { |
| "OuterClass.java", |
| "import java.io.*;\n"+ |
| "import java.util.function.Supplier;\n"+ |
| "\n"+ |
| "public class OuterClass implements Serializable {\n"+ |
| "\n"+ |
| " private static final long serialVersionUID = 5390565572939096897L;\n"+ |
| " public Supplier<OuterClass.InnerClass> supplier;\n"+ |
| "\n"+ |
| " @SuppressWarnings(\"unchecked\")\n"+ |
| " public OuterClass() {\n"+ |
| " this.supplier = (Supplier<OuterClass.InnerClass> & Serializable) InnerClass::new;\n"+ |
| " }\n"+ |
| "\n"+ |
| " public class InnerClass implements Serializable {\n"+ |
| " private static final long serialVersionUID = 2478179807896338433L;\n"+ |
| " public InnerClass() {\n"+ |
| " }\n"+ |
| " }\n"+ |
| "\n"+ |
| "}\n" |
| }, ""); |
| String expectedOutput = |
| "lambda$1()LOuterClass$InnerClass;\n"; |
| String data = printLambdaMethods(OUTPUT_DIR + File.separator + "OuterClass.class"); |
| checkExpected(expectedOutput,data); |
| } |
| // --- |
| |
| private void checkExpected(String expected, String actual) { |
| if (!expected.equals(actual)) { |
| printIt(actual); |
| } |
| assertEquals(expected,actual); |
| } |
| |
| /** |
| * Print a piece of text with the necessary extra quotes and newlines so that it can be cut/pasted into |
| * the test source file. |
| */ |
| private void printIt(String text) { |
| String quotedText = text; |
| if (!quotedText.startsWith("\"")) { |
| quotedText = "\""+quotedText.replaceAll("\n", "\\\\n\"+\n\""); |
| quotedText = quotedText.substring(0,quotedText.length()-3); |
| } |
| System.out.println(quotedText); |
| } |
| |
| /** |
| * Print the bootstrap methods attribute in a very similar fashion to javap for checking. |
| * Unlike javap the constant pool indexes are not included, to make the test a little less |
| * fragile. |
| */ |
| private String printBootstrapMethodsAttribute(String filepath) { |
| IClassFileReader cfr = ToolFactory.createDefaultClassFileReader(filepath, IClassFileReader.CLASSFILE_ATTRIBUTES); |
| BootstrapMethodsAttribute bootstrapMethodsAttribute = null; |
| IClassFileAttribute[] attrs = cfr.getAttributes(); |
| for (int i=0,max=attrs.length;i<max;i++) { |
| if (new String(attrs[i].getAttributeName()).equals("BootstrapMethods")) { |
| bootstrapMethodsAttribute = (BootstrapMethodsAttribute)attrs[i]; |
| } |
| } |
| if (bootstrapMethodsAttribute==null) { |
| return ""; |
| } |
| IConstantPool cp = cfr.getConstantPool(); |
| StringBuilder sb = new StringBuilder(); |
| int bmaLength = bootstrapMethodsAttribute.getBootstrapMethodsLength(); |
| for (int i=0;i<bmaLength;i++) { |
| IBootstrapMethodsEntry entry = bootstrapMethodsAttribute.getBootstrapMethods()[i]; |
| int mr = entry.getBootstrapMethodReference(); |
| IConstantPoolEntry2 icpe = (IConstantPoolEntry2)cfr.getConstantPool().decodeEntry(mr); |
| |
| sb.append(i).append(": ").append(formatReferenceKind(icpe.getReferenceKind())); |
| sb.append(" ").append(format(cp,icpe.getReferenceIndex())); |
| sb.append("\n"); |
| int[] args = entry.getBootstrapArguments(); |
| sb.append(" Method arguments:\n"); |
| for (int a=0;a<args.length;a++) { |
| sb.append(" ").append(format(cp,args[a])).append("\n"); |
| } |
| } |
| return sb.toString(); |
| } |
| |
| private String printLambdaMethods(String filepath) { |
| IClassFileReader cfr = ToolFactory.createDefaultClassFileReader(filepath, IClassFileReader.METHOD_INFOS); |
| IMethodInfo[] methodInfos = cfr.getMethodInfos(); |
| StringBuilder buf = new StringBuilder(); |
| for (int i = 0, max = methodInfos.length; i < max; i++) { |
| IMethodInfo methodInfo = methodInfos[i]; |
| if (!new String(methodInfo.getName()).startsWith("lambda")) |
| continue; |
| int accessFlags = methodInfo.getAccessFlags(); |
| if (Modifier.isStatic(accessFlags)) { |
| buf.append("static "); |
| } |
| buf.append(methodInfo.getName()); |
| buf.append(methodInfo.getDescriptor()); |
| buf.append("\n"); |
| } |
| return buf.toString(); |
| } |
| |
| String formatReferenceKind(int kind) { |
| switch (kind) { |
| case IConstantPoolConstant.METHOD_TYPE_REF_InvokeStatic: |
| return "invokestatic"; |
| default: |
| throw new IllegalStateException("nyi for "+kind); |
| } |
| } |
| |
| String format(IConstantPool cp, int entryNumber) { |
| IConstantPoolEntry entry = cp.decodeEntry(entryNumber); |
| if (entry == null) { |
| return "null"; |
| } |
| switch (entry.getKind()) { |
| case IConstantPoolConstant.CONSTANT_Integer: |
| return Integer.toString(entry.getIntegerValue()); |
| case IConstantPoolConstant.CONSTANT_Utf8: |
| return new String(entry.getUtf8Value()); |
| case IConstantPoolConstant.CONSTANT_Methodref: |
| return new String(entry.getClassName())+"."+new String(entry.getMethodName())+":"+new String(entry.getMethodDescriptor()); |
| case IConstantPoolConstant.CONSTANT_MethodHandle: |
| IConstantPoolEntry2 entry2 = (IConstantPoolEntry2)entry; |
| return formatReferenceKind(entry2.getReferenceKind())+" "+format(cp,entry2.getReferenceIndex()); |
| case IConstantPoolConstant.CONSTANT_MethodType: |
| return format(cp,((IConstantPoolEntry2)entry).getDescriptorIndex()); |
| case IConstantPoolConstant.CONSTANT_Class: |
| return new String(entry.getClassInfoName()); |
| default: |
| throw new IllegalStateException("nyi for "+entry.getKind()); |
| } |
| } |
| |
| } |
| |