undefect. CWE-407 — 63 sites patched across 27 ecosystems
Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com Patches, unit tests, benchmarks, whitepaper, and outreach briefs. Public domain — no copyright claimed. Use freely.
This commit is contained in:
commit
0a580b313d
70422 changed files with 17213626 additions and 0 deletions
42
test/jdk/java/lang/invoke/lambda/DupIntf.java
Normal file
42
test/jdk/java/lang/invoke/lambda/DupIntf.java
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8025868
|
||||
* @summary Lambda class can be generated with duplicate interfaces (ClassFormatError)
|
||||
* @run main DupIntf
|
||||
*/
|
||||
|
||||
interface SAM<P1> {
|
||||
P1 m();
|
||||
}
|
||||
|
||||
interface Other { }
|
||||
|
||||
public class DupIntf {
|
||||
public static void main(String argv[]) {
|
||||
SAM<?> sam = (SAM<?> & Other) () -> "Pass.";
|
||||
System.out.println(sam.m());
|
||||
}
|
||||
}
|
||||
85
test/jdk/java/lang/invoke/lambda/InheritedMethodTest.java
Normal file
85
test/jdk/java/lang/invoke/lambda/InheritedMethodTest.java
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8174399
|
||||
* @summary LambdaMetafactory should be able to handle inherited methods as 'implMethod'
|
||||
*/
|
||||
import java.lang.ReflectiveOperationException;
|
||||
import java.lang.invoke.*;
|
||||
|
||||
public class InheritedMethodTest {
|
||||
|
||||
public static MethodType mt(Class<?> ret, Class<?>... params) { return MethodType.methodType(ret, params); }
|
||||
|
||||
public interface StringFactory {
|
||||
String get();
|
||||
}
|
||||
|
||||
public interface I {
|
||||
String iString();
|
||||
}
|
||||
|
||||
public interface J extends I {}
|
||||
|
||||
public static abstract class C implements I {}
|
||||
|
||||
public static class D extends C implements J {
|
||||
public String toString() { return "a"; }
|
||||
public String iString() { return "b"; }
|
||||
}
|
||||
|
||||
private static final MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
|
||||
public static void main(String... args) throws Throwable {
|
||||
test(lookup.findVirtual(C.class, "toString", mt(String.class)), "a");
|
||||
test(lookup.findVirtual(C.class, "iString", mt(String.class)), "b");
|
||||
test(lookup.findVirtual(J.class, "toString", mt(String.class)), "a");
|
||||
test(lookup.findVirtual(J.class, "iString", mt(String.class)), "b");
|
||||
test(lookup.findVirtual(I.class, "toString", mt(String.class)), "a");
|
||||
test(lookup.findVirtual(I.class, "iString", mt(String.class)), "b");
|
||||
}
|
||||
|
||||
static void test(MethodHandle implMethod, String expected) throws Throwable {
|
||||
testMetafactory(implMethod, expected);
|
||||
testAltMetafactory(implMethod, expected);
|
||||
}
|
||||
|
||||
static void testMetafactory(MethodHandle implMethod, String expected) throws Throwable {
|
||||
CallSite cs = LambdaMetafactory.metafactory(lookup, "get", mt(StringFactory.class, D.class), mt(String.class),
|
||||
implMethod, mt(String.class));
|
||||
StringFactory factory = (StringFactory) cs.dynamicInvoker().invokeExact(new D());
|
||||
String actual = factory.get();
|
||||
if (!expected.equals(actual)) throw new AssertionError("Unexpected result: " + actual);
|
||||
}
|
||||
|
||||
static void testAltMetafactory(MethodHandle implMethod, String expected) throws Throwable {
|
||||
CallSite cs = LambdaMetafactory.altMetafactory(lookup, "get", mt(StringFactory.class, D.class), mt(String.class),
|
||||
implMethod, mt(String.class), LambdaMetafactory.FLAG_SERIALIZABLE);
|
||||
StringFactory factory = (StringFactory) cs.dynamicInvoker().invokeExact(new D());
|
||||
String actual = factory.get();
|
||||
if (!expected.equals(actual)) throw new AssertionError("Unexpected result: " + actual);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8003881
|
||||
* @library /test/lib/
|
||||
* @modules jdk.compiler
|
||||
* jdk.zipfs
|
||||
* @compile LambdaAccessControlDoPrivilegedTest.java
|
||||
* @run main/othervm LambdaAccessControlDoPrivilegedTest
|
||||
* @summary tests DoPrivileged action (implemented as lambda expressions) by
|
||||
* inserting them into the BootClassPath.
|
||||
*/
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.spi.ToolProvider;
|
||||
|
||||
import static jdk.test.lib.process.ProcessTools.*;
|
||||
|
||||
public class LambdaAccessControlDoPrivilegedTest {
|
||||
public static void main(String... args) throws Exception {
|
||||
final List<String> scratch = new ArrayList();
|
||||
scratch.clear();
|
||||
scratch.add("import java.security.*;");
|
||||
scratch.add("public class DoPriv {");
|
||||
scratch.add("public static void main(String... args) {");
|
||||
scratch.add("String prop = AccessController.doPrivileged((PrivilegedAction<String>) () -> {");
|
||||
scratch.add("return System.getProperty(\"user.home\");");
|
||||
scratch.add("});");
|
||||
scratch.add("}");
|
||||
scratch.add("}");
|
||||
Path doprivJava = Path.of("DoPriv.java");
|
||||
Path doprivClass = Path.of("DoPriv.class");
|
||||
Files.write(doprivJava, scratch, Charset.defaultCharset());
|
||||
|
||||
scratch.clear();
|
||||
scratch.add("public class Bar {");
|
||||
scratch.add("public static void main(String... args) {");
|
||||
scratch.add("DoPriv.main();");
|
||||
scratch.add("}");
|
||||
scratch.add("}");
|
||||
|
||||
Path barJava = Path.of("Bar.java");
|
||||
Path barClass = Path.of("Bar.class");
|
||||
Files.write(barJava, scratch, Charset.defaultCharset());
|
||||
|
||||
compile(barJava.toString(), doprivJava.toString());
|
||||
|
||||
jar("cvf", "foo.jar", doprivClass.toString());
|
||||
Files.delete(doprivJava);
|
||||
Files.delete(doprivClass);
|
||||
|
||||
ProcessBuilder pb = createTestJavaProcessBuilder(
|
||||
"-Xbootclasspath/a:foo.jar",
|
||||
"-cp", ".",
|
||||
"Bar");
|
||||
executeProcess(pb).shouldHaveExitValue(0);
|
||||
|
||||
Files.delete(barJava);
|
||||
Files.delete(barClass);
|
||||
Files.delete(Path.of("foo.jar"));
|
||||
}
|
||||
|
||||
static final ToolProvider JAR_TOOL = ToolProvider.findFirst("jar").orElseThrow();
|
||||
static final ToolProvider JAVAC = ToolProvider.findFirst("javac").orElseThrow();
|
||||
static void compile(String... args) throws IOException {
|
||||
if (JAVAC.run(System.out, System.err, args) != 0) {
|
||||
throw new RuntimeException("compilation fails");
|
||||
}
|
||||
}
|
||||
|
||||
static void jar(String... args) {
|
||||
int rc = JAR_TOOL.run(System.out, System.err, args);
|
||||
if (rc != 0){
|
||||
throw new RuntimeException("fail to create JAR file");
|
||||
}
|
||||
}
|
||||
}
|
||||
188
test/jdk/java/lang/invoke/lambda/LambdaAsm.java
Normal file
188
test/jdk/java/lang/invoke/lambda/LambdaAsm.java
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
/*
|
||||
* Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8027232
|
||||
* @library /test/lib/
|
||||
* @modules jdk.zipfs
|
||||
* @compile LambdaAsm.java
|
||||
* @run main/othervm LambdaAsm
|
||||
* @summary ensures that j.l.i.InvokerByteCodeGenerator and Class-File API
|
||||
* generate bytecodes with correct constant pool references
|
||||
*/
|
||||
import java.io.IOException;
|
||||
import java.lang.classfile.Attributes;
|
||||
import java.lang.classfile.ClassFile;
|
||||
import java.lang.classfile.ClassModel;
|
||||
import java.lang.classfile.Opcode;
|
||||
import java.lang.classfile.attribute.CodeAttribute;
|
||||
import java.lang.classfile.constantpool.ConstantPool;
|
||||
import java.lang.classfile.constantpool.MethodRefEntry;
|
||||
import java.lang.classfile.instruction.InvokeInstruction;
|
||||
import java.lang.constant.ClassDesc;
|
||||
import java.lang.constant.MethodTypeDesc;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.nio.file.DirectoryStream;
|
||||
import java.nio.file.Path;
|
||||
import jdk.test.lib.compiler.CompilerUtils;
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
|
||||
import static java.lang.constant.ConstantDescs.*;
|
||||
import static java.lang.classfile.ClassFile.*;
|
||||
import static java.nio.file.Files.*;
|
||||
import static jdk.test.lib.process.ProcessTools.*;
|
||||
|
||||
public class LambdaAsm {
|
||||
static final Path DUMP_LAMBDA_PROXY_CLASS_FILES = Path.of("DUMP_LAMBDA_PROXY_CLASS_FILES");
|
||||
static final Path SRC = Path.of("src");
|
||||
static final Path CLASSES = Path.of("classes");
|
||||
|
||||
static void init() throws Exception {
|
||||
emitCode();
|
||||
CompilerUtils.compile(SRC, CLASSES);
|
||||
OutputAnalyzer outputAnalyzer = executeProcess(createTestJavaProcessBuilder(
|
||||
"-Djdk.invoke.LambdaMetafactory.dumpProxyClassFiles=true",
|
||||
"-cp", CLASSES.toString(), "A"));
|
||||
outputAnalyzer.shouldHaveExitValue(0);
|
||||
}
|
||||
|
||||
static void emitCode() throws IOException {
|
||||
ArrayList<String> scratch = new ArrayList<>();
|
||||
scratch.add("import java.util.function.*;");
|
||||
scratch.add("class A {");
|
||||
scratch.add(" interface I {");
|
||||
scratch.add(" default Supplier<Integer> a() { return () -> 1; }");
|
||||
scratch.add(" default Supplier<Integer> b(int i) { return () -> i; }");
|
||||
scratch.add(" default Supplier<Integer> c(int i) { return () -> m(i); }");
|
||||
scratch.add(" int m(int i);");
|
||||
scratch.add(" static Integer d() { return 0; }");
|
||||
scratch.add(" }");
|
||||
scratch.add(" static class C implements I {");
|
||||
scratch.add(" public int m(int i) { return i;}");
|
||||
scratch.add(" }");
|
||||
scratch.add(" public static void main(String[] args) {");
|
||||
scratch.add(" I i = new C();");
|
||||
scratch.add(" i.a();");
|
||||
scratch.add(" i.b(1);");
|
||||
scratch.add(" i.c(1);");
|
||||
scratch.add(" I.d();");
|
||||
scratch.add(" }");
|
||||
scratch.add("}");
|
||||
|
||||
Path testFile = SRC.resolve("A.java");
|
||||
Files.createDirectories(SRC);
|
||||
Files.write(testFile, scratch, Charset.defaultCharset());
|
||||
}
|
||||
|
||||
static void checkMethod(String cname, String mname, ConstantPool cp,
|
||||
CodeAttribute code) throws IllegalArgumentException {
|
||||
for (var inst : code) {
|
||||
if (inst instanceof InvokeInstruction inv && (inv.opcode() == Opcode.INVOKESPECIAL
|
||||
|| inv.opcode() == Opcode.INVOKEINTERFACE)) {
|
||||
var ref = inv.method();
|
||||
System.out.println("Verifying " + cname + ":" + mname +
|
||||
" instruction:" + inv.opcode() + " index @" + ref.index());
|
||||
if (ref instanceof MethodRefEntry) {
|
||||
throw new RuntimeException("unexpected CP type expected "
|
||||
+ "InterfaceMethodRef, got MethodRef, " + cname
|
||||
+ ", " + mname);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int checkMethod(ClassModel cf, String mthd) throws Exception {
|
||||
if (cf.majorVersion() < 52) {
|
||||
throw new RuntimeException("unexpected class file version, in "
|
||||
+ cf.thisClass().asInternalName() + "expected 52, got "
|
||||
+ cf.majorVersion());
|
||||
}
|
||||
int count = 0;
|
||||
for (var m : cf.methods()) {
|
||||
String mname = m.methodName().stringValue();
|
||||
if (mname.equals(mthd)) {
|
||||
for (var a : m.findAttributes(Attributes.code())) {
|
||||
count++;
|
||||
checkMethod(cf.thisClass().asInternalName(), mname,
|
||||
cf.constantPool(), a);
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static void verifyInvokerBytecodeGenerator() throws Exception {
|
||||
int count = 0;
|
||||
int mcount = 0;
|
||||
try (DirectoryStream<Path> ds = newDirectoryStream(DUMP_LAMBDA_PROXY_CLASS_FILES,
|
||||
// filter in lambda proxy classes
|
||||
"A$I$$Lambda.*.class")) {
|
||||
for (Path p : ds) {
|
||||
System.out.println(p.toFile());
|
||||
ClassModel cm = ClassFile.of().parse(p);
|
||||
// Check those methods implementing Supplier.get
|
||||
mcount += checkMethod(cm, "get");
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if (count < 3) {
|
||||
throw new RuntimeException("unexpected number of files, "
|
||||
+ "expected atleast 3 files, but got only " + count);
|
||||
}
|
||||
if (mcount < 3) {
|
||||
throw new RuntimeException("unexpected number of methods, "
|
||||
+ "expected atleast 3 methods, but got only " + mcount);
|
||||
}
|
||||
}
|
||||
|
||||
static void verifyASM() throws Exception {
|
||||
var functionDesc = ClassDesc.ofInternalName("java/util/function/Function");
|
||||
byte[] carray = ClassFile.of().build(ClassDesc.of("X"), clb -> clb
|
||||
.withVersion(JAVA_8_VERSION, 0)
|
||||
.withFlags(ACC_PUBLIC)
|
||||
.withSuperclass(CD_Object)
|
||||
.withMethodBody("foo", MTD_void, ACC_STATIC, cob -> cob
|
||||
.invokestatic(functionDesc, "identity", MethodTypeDesc.of(functionDesc), true)
|
||||
)
|
||||
);
|
||||
// for debugging
|
||||
// write((new File("X.class")).toPath(), carray, CREATE, TRUNCATE_EXISTING);
|
||||
|
||||
// verify using javap/classfile reader
|
||||
ClassModel cm = ClassFile.of().parse(carray);
|
||||
int mcount = checkMethod(cm, "foo");
|
||||
if (mcount < 1) {
|
||||
throw new RuntimeException("unexpected method count, expected 1" +
|
||||
"but got " + mcount);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String... args) throws Exception {
|
||||
init();
|
||||
verifyInvokerBytecodeGenerator();
|
||||
verifyASM();
|
||||
}
|
||||
}
|
||||
58
test/jdk/java/lang/invoke/lambda/LambdaClassFinal.java
Normal file
58
test/jdk/java/lang/invoke/lambda/LambdaClassFinal.java
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8012028
|
||||
* @summary Generated Lambda implementing class should be final
|
||||
*/
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.io.Serializable;
|
||||
|
||||
public class LambdaClassFinal {
|
||||
|
||||
interface I {
|
||||
void m();
|
||||
}
|
||||
|
||||
interface Iser extends Serializable {
|
||||
void m();
|
||||
}
|
||||
|
||||
static void assertTrue(boolean cond) {
|
||||
if (!cond)
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
new LambdaClassFinal().test();
|
||||
}
|
||||
|
||||
void test() throws Exception {
|
||||
I lam = () -> { };
|
||||
assertTrue((lam.getClass().getModifiers() & Modifier.FINAL) != 0);
|
||||
Iser slam = () -> { };
|
||||
assertTrue((slam.getClass().getModifiers() & Modifier.FINAL) != 0);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
* Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8004970
|
||||
* @summary Lambda serialization in the presence of class loaders
|
||||
* @run main LambdaClassLoaderSerialization
|
||||
* @author Peter Levart
|
||||
*/
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
|
||||
public class LambdaClassLoaderSerialization {
|
||||
|
||||
public interface SerializableRunnable extends Runnable, Serializable {}
|
||||
|
||||
public static class MyCode implements SerializableRunnable {
|
||||
|
||||
private byte[] serialize(Object o) {
|
||||
ByteArrayOutputStream baos;
|
||||
try (
|
||||
ObjectOutputStream oos =
|
||||
new ObjectOutputStream(baos = new ByteArrayOutputStream())
|
||||
) {
|
||||
oos.writeObject(o);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return baos.toByteArray();
|
||||
}
|
||||
|
||||
private <T> T deserialize(byte[] bytes) {
|
||||
try (
|
||||
ObjectInputStream ois =
|
||||
new ObjectInputStream(new ByteArrayInputStream(bytes))
|
||||
) {
|
||||
return (T) ois.readObject();
|
||||
}
|
||||
catch (IOException | ClassNotFoundException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
System.out.println(" this: " + this);
|
||||
|
||||
SerializableRunnable deSerializedThis = deserialize(serialize(this));
|
||||
System.out.println(" deSerializedThis: " + deSerializedThis);
|
||||
|
||||
SerializableRunnable runnable = () -> {System.out.println("HELLO");};
|
||||
System.out.println(" runnable: " + runnable);
|
||||
|
||||
SerializableRunnable deSerializedRunnable = deserialize(serialize(runnable));
|
||||
System.out.println("deSerializedRunnable: " + deSerializedRunnable);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
ClassLoader myCl = new MyClassLoader(
|
||||
LambdaClassLoaderSerialization.class.getClassLoader()
|
||||
);
|
||||
Class<?> myCodeClass = Class.forName(
|
||||
LambdaClassLoaderSerialization.class.getName() + "$MyCode",
|
||||
true,
|
||||
myCl
|
||||
);
|
||||
Runnable myCode = (Runnable) myCodeClass.newInstance();
|
||||
myCode.run();
|
||||
}
|
||||
|
||||
static class MyClassLoader extends ClassLoader {
|
||||
MyClassLoader(ClassLoader parent) {
|
||||
super(parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
|
||||
if (name.indexOf('.') < 0) {
|
||||
synchronized (getClassLoadingLock(name)) {
|
||||
Class<?> c = findLoadedClass(name);
|
||||
if (c == null) {
|
||||
c = findClass(name);
|
||||
}
|
||||
if (resolve) {
|
||||
resolveClass(c);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
} else {
|
||||
return super.loadClass(name, resolve);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> findClass(String name) throws ClassNotFoundException {
|
||||
String path = name.replace('.', '/').concat(".class");
|
||||
try (InputStream is = getResourceAsStream(path)) {
|
||||
if (is != null) {
|
||||
byte[] bytes = is.readAllBytes();
|
||||
return defineClass(name, bytes, 0, bytes.length);
|
||||
} else {
|
||||
throw new ClassNotFoundException(name);
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new ClassNotFoundException(name, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
58
test/jdk/java/lang/invoke/lambda/LambdaClassSynthetic.java
Normal file
58
test/jdk/java/lang/invoke/lambda/LambdaClassSynthetic.java
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8008941
|
||||
* @summary Generated Lambda implementing class should be synthetic
|
||||
*/
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.io.Serializable;
|
||||
|
||||
public class LambdaClassSynthetic {
|
||||
|
||||
interface I {
|
||||
void m();
|
||||
}
|
||||
|
||||
interface Iser extends Serializable {
|
||||
void m();
|
||||
}
|
||||
|
||||
static void assertTrue(boolean cond) {
|
||||
if (!cond)
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
new LambdaClassFinal().test();
|
||||
}
|
||||
|
||||
void test() throws Exception {
|
||||
I lam = () -> { };
|
||||
assertTrue(lam.getClass().isSynthetic());
|
||||
Iser slam = () -> { };
|
||||
assertTrue(slam.getClass().isSynthetic());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8016761
|
||||
* @summary Lambda metafactory: incorrect type conversion of constructor method handle
|
||||
*/
|
||||
|
||||
public class LambdaConstructorMethodHandleUnbox {
|
||||
interface IntFunction<X> {
|
||||
int m(X x);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
IntFunction<String> s = Integer::new;
|
||||
if (s.m("2000") + s.m("13") != 2013) {
|
||||
throw new RuntimeException("Lambda conversion failure");
|
||||
}
|
||||
}
|
||||
}
|
||||
91
test/jdk/java/lang/invoke/lambda/LambdaEagerInitTest.java
Normal file
91
test/jdk/java/lang/invoke/lambda/LambdaEagerInitTest.java
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8242451
|
||||
* @library /test/lib
|
||||
* @summary Test that the LAMBDA_INSTANCE$ field is present depending
|
||||
* on disableEagerInitialization
|
||||
* @run main LambdaEagerInitTest
|
||||
* @run main/othervm -Djdk.internal.lambda.disableEagerInitialization=true LambdaEagerInitTest
|
||||
*/
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static jdk.test.lib.Asserts.*;
|
||||
|
||||
public class LambdaEagerInitTest {
|
||||
|
||||
interface H {Object m(String s);}
|
||||
|
||||
private static Set<String> allowedStaticFields(boolean nonCapturing) {
|
||||
Set<String> s = new HashSet<>();
|
||||
if (Boolean.getBoolean("jdk.internal.lambda.disableEagerInitialization")) {
|
||||
if (nonCapturing) s.add("LAMBDA_INSTANCE$");
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
private void nonCapturingLambda() {
|
||||
H la = s -> s;
|
||||
assertEquals("hi", la.m("hi"));
|
||||
Class<? extends H> c1 = la.getClass();
|
||||
verifyLambdaClass(la.getClass(), true);
|
||||
}
|
||||
|
||||
private void capturingLambda() {
|
||||
H la = s -> concat(s, "foo");
|
||||
assertEquals("hi foo", la.m("hi"));
|
||||
verifyLambdaClass(la.getClass(), false);
|
||||
}
|
||||
|
||||
private void verifyLambdaClass(Class<?> c, boolean nonCapturing) {
|
||||
Set<String> staticFields = new HashSet<>();
|
||||
Set<String> instanceFields = new HashSet<>();
|
||||
for (Field f : c.getDeclaredFields()) {
|
||||
if (Modifier.isStatic(f.getModifiers())) {
|
||||
staticFields.add(f.getName());
|
||||
} else {
|
||||
instanceFields.add(f.getName());
|
||||
}
|
||||
}
|
||||
assertEquals(instanceFields.size(), nonCapturing ? 0 : 1, "Unexpected instance fields");
|
||||
assertEquals(staticFields, allowedStaticFields(nonCapturing), "Unexpected static fields");
|
||||
}
|
||||
|
||||
private String concat(String... ss) {
|
||||
return Arrays.stream(ss).collect(Collectors.joining(" "));
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
LambdaEagerInitTest test = new LambdaEagerInitTest();
|
||||
test.nonCapturingLambda();
|
||||
test.capturingLambda();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8248231
|
||||
* @summary Test to verify lambda serialization uses the correct UTF-8 encoding
|
||||
* @library /test/lib
|
||||
* @build jdk.test.lib.JDKToolFinder
|
||||
* jdk.test.lib.process.ProcessTools
|
||||
* @run junit LambdaFileEncodingSerialization
|
||||
*/
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Arrays;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import jdk.test.lib.JDKToolFinder;
|
||||
import jdk.test.lib.process.ProcessTools;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class LambdaFileEncodingSerialization {
|
||||
|
||||
private static final String TEST_NAME = "TestLambdaFileEncodingSerialization";
|
||||
|
||||
@Test
|
||||
public void testDeserializeLambdaEncoding() throws Throwable {
|
||||
|
||||
String javac = JDKToolFinder.getTestJDKTool("javac");
|
||||
String java = JDKToolFinder.getTestJDKTool("java");
|
||||
|
||||
String srcDir = System.getProperty("test.src");
|
||||
|
||||
// Compile <TEST_NAME>.java using ISO-8859-1 encoding
|
||||
String opts = "-J-Dfile.encoding=ISO-8859-1 -cp . -d .";
|
||||
String file = srcDir + File.separator + TEST_NAME + ".java";
|
||||
int exitCode = runCmd(javac, opts, file);
|
||||
assertTrue(exitCode == 0, "Command " + javac + " " + opts + " " + file + " , failed exitCode = "+exitCode);
|
||||
|
||||
// Execute TEST_NAME containing the re-serialized lambda
|
||||
opts = "-cp .";
|
||||
file = TEST_NAME;
|
||||
exitCode = runCmd(java, opts, file);
|
||||
assertTrue(exitCode == 0, "Command " + java + " " + opts + " " + file + " , failed exitCode = "+exitCode);
|
||||
}
|
||||
|
||||
// Run a command
|
||||
private static int runCmd(String prog, String options, String file) throws Throwable {
|
||||
|
||||
List<String> argList = new ArrayList<String>();
|
||||
argList.add(prog);
|
||||
argList.addAll(Arrays.asList(options.split(" ")));
|
||||
argList.add(file);
|
||||
|
||||
ProcessBuilder pb = new ProcessBuilder(argList);
|
||||
Map<String, String> env = pb.environment();
|
||||
env.put("LC_ALL", "en_US.UTF-8"); // Ensure locale supports the test requirements, lambda with a UTF char
|
||||
|
||||
int exitCode = ProcessTools.executeCommand(pb).outputTo(System.out)
|
||||
.errorTo(System.err)
|
||||
.getExitValue();
|
||||
return exitCode;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
92
test/jdk/java/lang/invoke/lambda/LambdaHiddenCaller.java
Normal file
92
test/jdk/java/lang/invoke/lambda/LambdaHiddenCaller.java
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.util.function.IntSupplier;
|
||||
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8343064
|
||||
* @summary Test about when lambda caller/target class is a hidden class
|
||||
* @run junit LambdaHiddenCaller
|
||||
*/
|
||||
public class LambdaHiddenCaller {
|
||||
static Hooks hiddenCaller;
|
||||
|
||||
@BeforeAll
|
||||
static void setup() throws Throwable {
|
||||
byte[] bytes;
|
||||
try (var in = LambdaHiddenCaller.class.getResourceAsStream("HiddenHooks.class")) {
|
||||
bytes = in.readAllBytes();
|
||||
}
|
||||
var hiddenClassLookup = MethodHandles.lookup().defineHiddenClass(bytes, true);
|
||||
hiddenCaller = (Hooks) hiddenClassLookup.findConstructor(hiddenClassLookup.lookupClass(), MethodType.methodType(void.class))
|
||||
.asType(MethodType.methodType(Hooks.class)).invokeExact();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testStaticMethod() {
|
||||
var is = hiddenCaller.callStaticMethodLambda();
|
||||
assertEquals(42, is.getAsInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSerializableLambda() {
|
||||
var is = hiddenCaller.callSerializableLambda();
|
||||
assertEquals(42, is.getAsInt());
|
||||
assertInstanceOf(Serializable.class, is);
|
||||
// We do not guarantee serialization functionalities yet
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hooks to call hidden class methods easily.
|
||||
*/
|
||||
interface Hooks {
|
||||
IntSupplier callStaticMethodLambda();
|
||||
|
||||
IntSupplier callSerializableLambda();
|
||||
}
|
||||
|
||||
class HiddenHooks implements Hooks {
|
||||
private static int compute() {
|
||||
return 42;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntSupplier callStaticMethodLambda() {
|
||||
return HiddenHooks::compute;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntSupplier callSerializableLambda() {
|
||||
return (IntSupplier & Serializable) HiddenHooks::compute;
|
||||
}
|
||||
}
|
||||
70
test/jdk/java/lang/invoke/lambda/LambdaReceiver.java
Normal file
70
test/jdk/java/lang/invoke/lambda/LambdaReceiver.java
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8035776
|
||||
* @summary Consistent Lambda construction
|
||||
*/
|
||||
|
||||
import java.lang.invoke.CallSite;
|
||||
import java.lang.invoke.LambdaMetafactory;
|
||||
import java.lang.invoke.LambdaConversionException;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import LambdaReceiver_anotherpkg.LambdaReceiver_A;
|
||||
|
||||
public class LambdaReceiver extends LambdaReceiver_A {
|
||||
|
||||
interface IA {
|
||||
int m(LambdaReceiver_A x);
|
||||
}
|
||||
|
||||
static MethodHandles.Lookup l;
|
||||
static MethodHandle h;
|
||||
private static MethodType mt(Class<?> k) { return MethodType.methodType(k); }
|
||||
private static MethodType mt(Class<?> k, Class<?> k2) { return MethodType.methodType(k, k2); }
|
||||
private static void mf(List<String> errs, MethodType mts, MethodType mtf, boolean shouldWork) {
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
l = MethodHandles.lookup();
|
||||
h = l.findVirtual(LambdaReceiver_A.class, "f", mt(int.class));
|
||||
MethodType X = mt(int.class, LambdaReceiver.class);
|
||||
MethodType A = mt(int.class, LambdaReceiver_A.class);
|
||||
MethodType mti = mt(IA.class);
|
||||
CallSite cs = LambdaMetafactory.metafactory(l, "m", mti,A,h,X);
|
||||
IA p = (IA)cs.dynamicInvoker().invoke();
|
||||
LambdaReceiver_A lra = new LambdaReceiver_A();
|
||||
try {
|
||||
p.m(lra);
|
||||
} catch (ClassCastException cce) {
|
||||
return;
|
||||
}
|
||||
throw new AssertionError("CCE expected");
|
||||
}
|
||||
}
|
||||
71
test/jdk/java/lang/invoke/lambda/LambdaReceiverBridge.java
Normal file
71
test/jdk/java/lang/invoke/lambda/LambdaReceiverBridge.java
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8035776
|
||||
* @summary Consistent Lambda construction
|
||||
*/
|
||||
|
||||
import java.lang.invoke.CallSite;
|
||||
import java.lang.invoke.LambdaMetafactory;
|
||||
import java.lang.invoke.LambdaConversionException;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import LambdaReceiver_anotherpkg.LambdaReceiver_A;
|
||||
|
||||
public class LambdaReceiverBridge extends LambdaReceiver_A {
|
||||
|
||||
interface IA {
|
||||
int m(LambdaReceiver_A x);
|
||||
}
|
||||
|
||||
static MethodHandles.Lookup l;
|
||||
static MethodHandle h;
|
||||
private static MethodType mt(Class<?> k) { return MethodType.methodType(k); }
|
||||
private static MethodType mt(Class<?> k, Class<?> k2) { return MethodType.methodType(k, k2); }
|
||||
private static void mf(List<String> errs, MethodType mts, MethodType mtf, boolean shouldWork) {
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
l = MethodHandles.lookup();
|
||||
h = l.findVirtual(LambdaReceiver_A.class, "f", mt(int.class));
|
||||
MethodType X = mt(int.class, LambdaReceiverBridge.class);
|
||||
MethodType A = mt(int.class, LambdaReceiver_A.class);
|
||||
MethodType mti = mt(IA.class);
|
||||
CallSite cs = LambdaMetafactory.altMetafactory(l, "m", mti,X,h,X,
|
||||
LambdaMetafactory.FLAG_BRIDGES, 1, A);
|
||||
IA p = (IA)cs.dynamicInvoker().invoke();
|
||||
LambdaReceiver_A lra = new LambdaReceiver_A();
|
||||
try {
|
||||
p.m(lra);
|
||||
} catch (ClassCastException cce) {
|
||||
return;
|
||||
}
|
||||
throw new AssertionError("CCE expected");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package LambdaReceiver_anotherpkg;
|
||||
|
||||
public class LambdaReceiver_A {
|
||||
protected final int f() { return 2; }
|
||||
}
|
||||
92
test/jdk/java/lang/invoke/lambda/LambdaReturn.java
Normal file
92
test/jdk/java/lang/invoke/lambda/LambdaReturn.java
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8035776
|
||||
* @summary Consistent Lambda construction
|
||||
*/
|
||||
|
||||
import java.lang.invoke.LambdaMetafactory;
|
||||
import java.lang.invoke.LambdaConversionException;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class LambdaReturn {
|
||||
|
||||
interface I {
|
||||
void m();
|
||||
}
|
||||
|
||||
static void hereV() {}
|
||||
static String hereS() { return "hi"; }
|
||||
static MethodHandles.Lookup l;
|
||||
private static MethodType mt(Class<?> k) { return MethodType.methodType(k); }
|
||||
private static MethodType mt(Class<?> k, Class<?> k2) { return MethodType.methodType(k, k2); }
|
||||
private static void amf(List<String> errs, MethodHandle h, MethodType mts, MethodType mtf, MethodType mtb, boolean shouldWork) {
|
||||
MethodType mti = mt(I.class);
|
||||
try {
|
||||
LambdaMetafactory.altMetafactory(l, "m", mti, mts,h,mtf,
|
||||
LambdaMetafactory.FLAG_BRIDGES, 1, mtb);
|
||||
} catch(LambdaConversionException e) {
|
||||
if (shouldWork) errs.add("Error: Should work h=" + h + " s=" + mts + " -- f=" + mtf + " / b=" + mtb + " got: " + e);
|
||||
return;
|
||||
}
|
||||
if (!shouldWork) errs.add("Error: Should fail h=" + h + " s=" + mts + " -- f=" + mtf + " / b=" + mtb);
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
l = MethodHandles.lookup();
|
||||
MethodHandle hV = l.findStatic(LambdaReturn.class, "hereV", mt(void.class));
|
||||
MethodHandle hS = l.findStatic(LambdaReturn.class, "hereS", mt(String.class));
|
||||
List<String> errs = new ArrayList<>();
|
||||
MethodType V = mt(void.class);
|
||||
MethodType S = mt(String.class);
|
||||
MethodType O = mt(Object.class);
|
||||
MethodType I = mt(int.class);
|
||||
amf(errs, hS, S, S, O, true);
|
||||
amf(errs, hS, S, S, V, false);
|
||||
amf(errs, hS, S, S, I, false);
|
||||
amf(errs, hS, O, S, S, true);
|
||||
amf(errs, hS, V, S, S, false);
|
||||
amf(errs, hS, I, S, S, false);
|
||||
amf(errs, hS, O, O, S, false);
|
||||
amf(errs, hS, S, O, O, false);
|
||||
amf(errs, hV, V, V, O, false);
|
||||
amf(errs, hV, V, V, I, false);
|
||||
amf(errs, hV, V, V, S, false);
|
||||
amf(errs, hV, O, V, V, false);
|
||||
amf(errs, hV, I, V, V, false);
|
||||
amf(errs, hV, S, V, V, false);
|
||||
|
||||
if (errs.size() > 0) {
|
||||
for (String err : errs) {
|
||||
System.err.println(err);
|
||||
}
|
||||
throw new AssertionError("Errors: " + errs.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
83
test/jdk/java/lang/invoke/lambda/LambdaSerialization.java
Normal file
83
test/jdk/java/lang/invoke/lambda/LambdaSerialization.java
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
@test
|
||||
@bug 8004970
|
||||
@summary Lambda serialization
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
|
||||
public class LambdaSerialization {
|
||||
|
||||
static int assertionCount = 0;
|
||||
|
||||
static void assertTrue(boolean cond) {
|
||||
assertionCount++;
|
||||
if (!cond)
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
try {
|
||||
// Write lambdas out
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ObjectOutput out = new ObjectOutputStream(baos);
|
||||
|
||||
write(out, z -> "[" + z + "]" );
|
||||
write(out, z -> z + z );
|
||||
write(out, z -> "blah" );
|
||||
out.flush();
|
||||
out.close();
|
||||
|
||||
// Read them back
|
||||
ByteArrayInputStream bais =
|
||||
new ByteArrayInputStream(baos.toByteArray());
|
||||
ObjectInputStream in = new ObjectInputStream(bais);
|
||||
readAssert(in, "[X]");
|
||||
readAssert(in, "XX");
|
||||
readAssert(in, "blah");
|
||||
in.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
}
|
||||
assertTrue(assertionCount == 3);
|
||||
}
|
||||
|
||||
static void write(ObjectOutput out, LSI lamb) throws IOException {
|
||||
out.writeObject(lamb);
|
||||
}
|
||||
|
||||
static void readAssert(ObjectInputStream in, String expected) throws IOException, ClassNotFoundException {
|
||||
LSI ls = (LSI) in.readObject();
|
||||
String result = ls.convert("X");
|
||||
System.out.printf("Result: %s\n", result);
|
||||
assertTrue(result.equals(expected));
|
||||
}
|
||||
}
|
||||
|
||||
interface LSI extends Serializable {
|
||||
String convert(String x);
|
||||
}
|
||||
213
test/jdk/java/lang/invoke/lambda/LambdaStackTrace.java
Normal file
213
test/jdk/java/lang/invoke/lambda/LambdaStackTrace.java
Normal file
|
|
@ -0,0 +1,213 @@
|
|||
/*
|
||||
* Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8025636
|
||||
* @library /test/lib/
|
||||
* @modules jdk.compiler
|
||||
* @compile LambdaStackTrace.java
|
||||
* @run main LambdaStackTrace
|
||||
* @summary Synthetic frames should be hidden in exceptions
|
||||
*/
|
||||
|
||||
import jdk.test.lib.compiler.CompilerUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.classfile.ClassFile;
|
||||
import java.lang.constant.ClassDesc;
|
||||
import java.lang.constant.MethodTypeDesc;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static java.lang.constant.ConstantDescs.CD_Object;
|
||||
import static java.lang.constant.ConstantDescs.CD_String;
|
||||
import static java.lang.classfile.ClassFile.*;
|
||||
|
||||
|
||||
public class LambdaStackTrace {
|
||||
|
||||
static Path CLASSES = Path.of(System.getProperty("test.classes", "."));
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
testBasic();
|
||||
testBridgeMethods();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the simple case
|
||||
*/
|
||||
private static void testBasic() throws Exception {
|
||||
try {
|
||||
Runnable r = () -> {
|
||||
throw new RuntimeException();
|
||||
};
|
||||
r.run();
|
||||
} catch (Exception ex) {
|
||||
// Before 8025636 the stacktrace would look like:
|
||||
// at LambdaStackTrace.lambda$main$0(LambdaStackTrace.java:37)
|
||||
// at LambdaStackTrace$$Lambda/1937396743.run(<Unknown>:1000000)
|
||||
// at LambdaStackTrace.testBasic(LambdaStackTrace.java:40)
|
||||
// at ...
|
||||
//
|
||||
// We are verifying that the middle frame above is gone.
|
||||
|
||||
verifyFrames(ex.getStackTrace(),
|
||||
"LambdaStackTrace\\..*",
|
||||
"LambdaStackTrace.testBasic");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the more complicated case with bridge methods.
|
||||
*
|
||||
* We set up the following interfaces:
|
||||
*
|
||||
* interface Maker {
|
||||
* Object make();
|
||||
* }
|
||||
* interface StringMaker extends Maker {
|
||||
* String make();
|
||||
* }
|
||||
*
|
||||
* And we will use them like so:
|
||||
*
|
||||
* StringMaker sm = () -> { throw new RuntimeException(); };
|
||||
* sm.make();
|
||||
* ((Maker)m).make();
|
||||
*
|
||||
* The first call is a "normal" interface call, the second will use a
|
||||
* bridge method. In both cases the generated lambda frame should
|
||||
* be removed from the stack trace.
|
||||
*/
|
||||
private static void testBridgeMethods() throws Exception {
|
||||
// setup
|
||||
generateInterfaces();
|
||||
compileCaller();
|
||||
|
||||
// test
|
||||
StackTraceElement[] frames = call("Caller", "callStringMaker");
|
||||
verifyFrames(frames,
|
||||
"Caller\\..*",
|
||||
"Caller.callStringMaker");
|
||||
|
||||
frames = call("Caller", "callMaker");
|
||||
verifyFrames(frames,
|
||||
"Caller\\..*",
|
||||
"Caller.callMaker");
|
||||
}
|
||||
|
||||
private static void generateInterfaces() throws IOException {
|
||||
// We can't let javac compile these interfaces because in > 1.8 it will insert
|
||||
// bridge methods into the interfaces - we want code that looks like <= 1.7,
|
||||
// so we generate it.
|
||||
Files.write(CLASSES.resolve("Maker.class"), generateMaker());
|
||||
Files.write(CLASSES.resolve("StringMaker.class"), generateStringMaker());
|
||||
}
|
||||
|
||||
private static byte[] generateMaker() {
|
||||
// interface Maker {
|
||||
// Object make();
|
||||
// }
|
||||
return ClassFile.of().build(ClassDesc.of("Maker"), clb -> clb
|
||||
.withVersion(JAVA_7_VERSION, 0)
|
||||
.withFlags(ACC_INTERFACE | ACC_ABSTRACT)
|
||||
.withSuperclass(CD_Object)
|
||||
.withMethod("make", MethodTypeDesc.of(CD_Object),
|
||||
ACC_PUBLIC | ACC_ABSTRACT, mb -> {})
|
||||
);
|
||||
}
|
||||
|
||||
private static byte[] generateStringMaker() {
|
||||
// interface StringMaker extends Maker {
|
||||
// String make();
|
||||
// }
|
||||
return ClassFile.of().build(ClassDesc.of("StringMaker"), clb -> clb
|
||||
.withVersion(JAVA_7_VERSION, 0)
|
||||
.withFlags(ACC_INTERFACE | ACC_ABSTRACT)
|
||||
.withSuperclass(CD_Object)
|
||||
.withInterfaceSymbols(ClassDesc.of("Maker"))
|
||||
.withMethod("make", MethodTypeDesc.of(CD_String),
|
||||
ACC_PUBLIC | ACC_ABSTRACT, mb -> {})
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
static void emitCode(Path file) throws IOException {
|
||||
ArrayList<String> scratch = new ArrayList<>();
|
||||
scratch.add("public class Caller {");
|
||||
scratch.add(" public static void callStringMaker() {");
|
||||
scratch.add(" StringMaker sm = () -> { throw new RuntimeException(); };");
|
||||
scratch.add(" sm.make();");
|
||||
scratch.add(" }");
|
||||
scratch.add(" public static void callMaker() {");
|
||||
scratch.add(" StringMaker sm = () -> { throw new RuntimeException(); };");
|
||||
scratch.add(" ((Maker) sm).make();"); // <-- This will call the bridge method
|
||||
scratch.add(" }");
|
||||
scratch.add("}");
|
||||
|
||||
Files.write(file, scratch, Charset.defaultCharset());
|
||||
}
|
||||
|
||||
static void compileCaller() throws IOException {
|
||||
Path src = Path.of("src");
|
||||
Files.createDirectories(src);
|
||||
|
||||
Path caller = src.resolve("Caller.java");
|
||||
emitCode(caller);
|
||||
CompilerUtils.compile(src, CLASSES, "-cp", CLASSES.toAbsolutePath().toString());
|
||||
}
|
||||
|
||||
private static void verifyFrames(StackTraceElement[] stack, String... patterns) throws Exception {
|
||||
for (int i = 0; i < patterns.length; i++) {
|
||||
String cm = stack[i].getClassName() + "." + stack[i].getMethodName();
|
||||
if (!cm.matches(patterns[i])) {
|
||||
System.err.println("Actual trace did not match expected trace at frame " + i);
|
||||
System.err.println("Expected frame patterns:");
|
||||
for (int j = 0; j < patterns.length; j++) {
|
||||
System.err.println(" " + j + ": " + patterns[j]);
|
||||
}
|
||||
System.err.println("Actual frames:");
|
||||
for (int j = 0; j < patterns.length; j++) {
|
||||
System.err.println(" " + j + ": " + stack[j]);
|
||||
}
|
||||
throw new Exception("Incorrect stack frames found");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static StackTraceElement[] call(String clazz, String method) throws Exception {
|
||||
Class<?> c = Class.forName(clazz);
|
||||
try {
|
||||
Method m = c.getDeclaredMethod(method);
|
||||
m.invoke(null);
|
||||
} catch(InvocationTargetException ex) {
|
||||
return ex.getTargetException().getStackTrace();
|
||||
}
|
||||
throw new Exception("Expected exception to be thrown");
|
||||
}
|
||||
}
|
||||
268
test/jdk/java/lang/invoke/lambda/LogGeneratedClassesTest.java
Normal file
268
test/jdk/java/lang/invoke/lambda/LogGeneratedClassesTest.java
Normal file
|
|
@ -0,0 +1,268 @@
|
|||
/*
|
||||
* Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8023524 8304846
|
||||
* @requires vm.flagless
|
||||
* @library /test/lib/
|
||||
* @library /java/nio/file
|
||||
* @modules jdk.compiler
|
||||
* jdk.zipfs
|
||||
* @run junit LogGeneratedClassesTest
|
||||
* @summary tests logging generated classes for lambda
|
||||
*/
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.FileStore;
|
||||
import java.nio.file.attribute.PosixFileAttributeView;
|
||||
|
||||
import jdk.test.lib.compiler.CompilerUtils;
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
|
||||
import static java.nio.file.attribute.PosixFilePermissions.*;
|
||||
import static jdk.test.lib.process.ProcessTools.*;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import org.junit.jupiter.api.Assumptions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class LogGeneratedClassesTest {
|
||||
static final Path DUMP_LAMBDA_PROXY_CLASS_FILES = Path.of("DUMP_LAMBDA_PROXY_CLASS_FILES");
|
||||
static final Path CLASSES = Path.of("classes").toAbsolutePath();
|
||||
static String longFQCN;
|
||||
|
||||
@BeforeAll
|
||||
public static void setup() throws IOException {
|
||||
final List<String> scratch = new ArrayList<>();
|
||||
scratch.clear();
|
||||
scratch.add("package com.example;");
|
||||
scratch.add("public class TestLambda {");
|
||||
scratch.add(" interface I {");
|
||||
scratch.add(" int foo();");
|
||||
scratch.add(" }");
|
||||
scratch.add(" public static void main(String[] args) {");
|
||||
scratch.add(" I lam = () -> 10;");
|
||||
scratch.add(" Runnable r = () -> {");
|
||||
scratch.add(" System.out.println(\"Runnable\");");
|
||||
scratch.add(" };");
|
||||
scratch.add(" r.run();");
|
||||
scratch.add(" System.out.println(\"Finish\");");
|
||||
scratch.add(" }");
|
||||
scratch.add("}");
|
||||
|
||||
Path testLambda = Path.of("TestLambda.java");
|
||||
Files.write(testLambda, scratch, Charset.defaultCharset());
|
||||
|
||||
scratch.remove(0);
|
||||
scratch.remove(0);
|
||||
scratch.add(0, "public class LongPackageName {");
|
||||
StringBuilder sb = new StringBuilder("com.example.");
|
||||
// longer than 255 which exceed max length of most filesystems
|
||||
for (int i = 0; i < 30; i++) {
|
||||
sb.append("nonsense.");
|
||||
}
|
||||
sb.append("enough");
|
||||
longFQCN = sb.toString() + ".LongPackageName";
|
||||
sb.append(";");
|
||||
sb.insert(0, "package ");
|
||||
scratch.add(0, sb.toString());
|
||||
Path lpnTest = Path.of("LongPackageName.java");
|
||||
Files.write(lpnTest, scratch, Charset.defaultCharset());
|
||||
|
||||
CompilerUtils.compile(Path.of("."), CLASSES);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void cleanup() throws IOException {
|
||||
Files.delete(Paths.get("TestLambda.java"));
|
||||
Files.delete(Paths.get("LongPackageName.java"));
|
||||
TestUtil.removeAll(DUMP_LAMBDA_PROXY_CLASS_FILES);
|
||||
TestUtil.removeAll(Paths.get("notDir"));
|
||||
TestUtil.removeAll(Paths.get("dump"));
|
||||
TestUtil.removeAll(Paths.get("dumpLong"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotLogging() throws Exception {
|
||||
ProcessBuilder pb = createLimitedTestJavaProcessBuilder(
|
||||
"-cp", CLASSES.toString(),
|
||||
"com.example.TestLambda");
|
||||
executeProcess(pb).shouldHaveExitValue(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLogging() throws Exception {
|
||||
Path testDir = Path.of("dump");
|
||||
Path dumpDir = testDir.resolve(DUMP_LAMBDA_PROXY_CLASS_FILES);
|
||||
Files.createDirectory(testDir);
|
||||
ProcessBuilder pb = createLimitedTestJavaProcessBuilder(
|
||||
"-cp", CLASSES.toString(),
|
||||
"-Djdk.invoke.LambdaMetafactory.dumpProxyClassFiles",
|
||||
"com.example.TestLambda").directory(testDir.toFile());
|
||||
executeProcess(pb).shouldHaveExitValue(0);
|
||||
|
||||
// 2 our own class files. We don't care about the others
|
||||
assertEquals(2, Files.find(
|
||||
dumpDir,
|
||||
99,
|
||||
(p, a) -> p.startsWith(dumpDir.resolve("com/example"))
|
||||
&& a.isRegularFile()).count(), "Two lambda captured");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDumpDirNotExist() throws Exception {
|
||||
Path testDir = Path.of("NotExist");
|
||||
Path dumpDir = testDir.resolve(DUMP_LAMBDA_PROXY_CLASS_FILES);
|
||||
Files.createDirectory(testDir);
|
||||
TestUtil.removeAll(dumpDir);
|
||||
assertFalse(Files.exists(dumpDir));
|
||||
|
||||
ProcessBuilder pb = createLimitedTestJavaProcessBuilder(
|
||||
"-cp", CLASSES.toString(),
|
||||
"-Djdk.invoke.LambdaMetafactory.dumpProxyClassFiles",
|
||||
"com.example.TestLambda").directory(testDir.toFile());
|
||||
executeProcess(pb).shouldHaveExitValue(0);
|
||||
|
||||
// The dump directory will be created if not exist
|
||||
assertEquals(2, Files.find(
|
||||
dumpDir,
|
||||
99,
|
||||
(p, a) -> p.startsWith(dumpDir.resolve("com/example"))
|
||||
&& a.isRegularFile()).count(), "Two lambda captured");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDumpDirIsFile() throws Exception {
|
||||
Path testDir = Path.of("notDir");
|
||||
Path dumpFile = testDir.resolve(DUMP_LAMBDA_PROXY_CLASS_FILES);
|
||||
Files.createDirectory(testDir);
|
||||
Files.createFile(dumpFile);
|
||||
assertTrue(Files.isRegularFile(dumpFile));
|
||||
ProcessBuilder pb = createLimitedTestJavaProcessBuilder(
|
||||
"-cp", CLASSES.toString(),
|
||||
"-Djdk.invoke.LambdaMetafactory.dumpProxyClassFiles",
|
||||
"com.example.TestLambda").directory(testDir.toFile());
|
||||
executeProcess(pb)
|
||||
.shouldContain("DUMP_LAMBDA_PROXY_CLASS_FILES is not a directory")
|
||||
.shouldNotHaveExitValue(0);
|
||||
}
|
||||
|
||||
private static boolean isWriteableDirectory(Path p) {
|
||||
if (!Files.isDirectory(p)) {
|
||||
return false;
|
||||
}
|
||||
Path test = p.resolve(Paths.get("test"));
|
||||
try {
|
||||
Files.createFile(test);
|
||||
assertTrue(Files.exists(test));
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
assertFalse(Files.exists(test));
|
||||
return false;
|
||||
} finally {
|
||||
if (Files.exists(test)) {
|
||||
try {
|
||||
Files.delete(test);
|
||||
} catch (IOException e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDumpDirNotWritable() throws Exception {
|
||||
FileStore fs;
|
||||
try {
|
||||
fs = Files.getFileStore(Paths.get("."));
|
||||
} catch (IOException e) {
|
||||
Assumptions.assumeTrue(false, "WARNING: IOException occurred: " + e + ", Skipping testDumpDirNotWritable test.");
|
||||
return;
|
||||
}
|
||||
Assumptions.assumeFalse(!fs.supportsFileAttributeView(PosixFileAttributeView.class), "WARNING: POSIX is not supported. Skipping testDumpDirNotWritable test."); // No easy way to setup readonly directory without POSIX
|
||||
|
||||
Path testDir = Path.of("readOnly");
|
||||
Path dumpDir = testDir.resolve(DUMP_LAMBDA_PROXY_CLASS_FILES);
|
||||
Files.createDirectory(testDir);
|
||||
Files.createDirectory(dumpDir,
|
||||
asFileAttribute(fromString("r-xr-xr-x")));
|
||||
try {
|
||||
Assumptions.assumeFalse(isWriteableDirectory(dumpDir), "WARNING: The dump directory is writeable. Skipping testDumpDirNotWritable test."); // Skipping the test: it's allowed to write into read-only directory
|
||||
// (e.g. current user is super user).
|
||||
|
||||
ProcessBuilder pb = createLimitedTestJavaProcessBuilder(
|
||||
"-cp", CLASSES.toString(),
|
||||
"-Djdk.invoke.LambdaMetafactory.dumpProxyClassFiles",
|
||||
"com.example.TestLambda").directory(testDir.toFile());
|
||||
executeProcess(pb)
|
||||
.shouldContain("DUMP_LAMBDA_PROXY_CLASS_FILES is not writable")
|
||||
.shouldNotHaveExitValue(0);
|
||||
} finally {
|
||||
TestUtil.removeAll(testDir);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoggingException() throws Exception {
|
||||
Path testDir = Path.of("dumpLong");
|
||||
Path dumpDir = testDir.resolve(DUMP_LAMBDA_PROXY_CLASS_FILES);
|
||||
Files.createDirectories(dumpDir.resolve("com/example/nonsense"));
|
||||
Files.createFile(dumpDir.resolve("com/example/nonsense/nonsense"));
|
||||
ProcessBuilder pb = createLimitedTestJavaProcessBuilder(
|
||||
"-cp", CLASSES.toString(),
|
||||
"-Djdk.invoke.LambdaMetafactory.dumpProxyClassFiles",
|
||||
longFQCN).directory(testDir.toFile());
|
||||
OutputAnalyzer outputAnalyzer = executeProcess(pb);
|
||||
outputAnalyzer.shouldHaveExitValue(0);
|
||||
assertEquals(2, outputAnalyzer.asLines().stream()
|
||||
.filter(s -> s.startsWith("WARNING: Exception"))
|
||||
.count(), "show error each capture");
|
||||
// dumpLong/DUMP_LAMBDA_PROXY_CLASS_FILES/com/example/nonsense/nonsense
|
||||
Path dumpPath = dumpDir.resolve("com/example/nonsense");
|
||||
Predicate<Path> filter = p -> p.getParent() == null || dumpPath.startsWith(p) || p.startsWith(dumpPath);
|
||||
boolean debug = true;
|
||||
if (debug) {
|
||||
Files.walk(dumpDir)
|
||||
.forEachOrdered(p -> {
|
||||
if (filter.test(p)) {
|
||||
System.out.println("accepted: " + p.toString());
|
||||
} else {
|
||||
System.out.println("filtered out: " + p.toString());
|
||||
}
|
||||
});
|
||||
}
|
||||
assertEquals(5, Files.walk(dumpDir)
|
||||
.filter(filter)
|
||||
.count(), "Two lambda captured failed to log");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,305 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8174222
|
||||
* @summary Validation of LambdaMetafactory arguments
|
||||
*/
|
||||
import java.lang.invoke.*;
|
||||
import java.util.*;
|
||||
|
||||
public class MetafactoryArgValidationTest {
|
||||
|
||||
public static void main(String... args) {
|
||||
testNPE();
|
||||
testIAE();
|
||||
testLCE();
|
||||
}
|
||||
|
||||
public static void testNPE() {
|
||||
MethodType toI = mt(I.class);
|
||||
MethodType toVoid = mt(void.class);
|
||||
MethodType toC = mt(C.class);
|
||||
MethodHandle impl = C.invokeStaticMH();
|
||||
MethodHandle impl2 = C.newInvokeSpecialMH();
|
||||
int flagSer = LambdaMetafactory.FLAG_SERIALIZABLE;
|
||||
int flagMark = LambdaMetafactory.FLAG_MARKERS;
|
||||
int flagBridge = LambdaMetafactory.FLAG_BRIDGES;
|
||||
|
||||
mfFail(NullPointerException.class, null, "m", toI, toVoid, impl, toVoid);
|
||||
mfFail(NullPointerException.class, C.lookup, null, toI, toVoid, impl, toVoid);
|
||||
mfFail(NullPointerException.class, C.lookup, "m", null, toVoid, impl, toVoid);
|
||||
mfFail(NullPointerException.class, C.lookup, "m", toI, null, impl, toVoid);
|
||||
mfFail(NullPointerException.class, C.lookup, "m", toI, toVoid, null, toVoid);
|
||||
mfFail(NullPointerException.class, C.lookup, "m", toI, toVoid, impl, null);
|
||||
|
||||
amfFail(NullPointerException.class, null, "m", toI, arr(toVoid, impl, toVoid, flagSer));
|
||||
amfFail(NullPointerException.class, C.lookup, null, toI, arr(toVoid, impl, toVoid, flagSer));
|
||||
amfFail(NullPointerException.class, C.lookup, "m", null, arr(toVoid, impl, toVoid, flagSer));
|
||||
amfFail(NullPointerException.class, C.lookup, "m", toI, null);
|
||||
amfFail(NullPointerException.class, C.lookup, "m", toI, arr(null, impl, toVoid, flagSer));
|
||||
amfFail(NullPointerException.class, C.lookup, "m", toI, arr(toVoid, null, toVoid, flagSer));
|
||||
amfFail(NullPointerException.class, C.lookup, "m", toI, arr(toVoid, impl, null, flagSer));
|
||||
amfFail(NullPointerException.class, C.lookup, "m", toI, arr(toVoid, impl, toVoid, null));
|
||||
amfFail(NullPointerException.class, C.lookup, "m", toI, arr(toVoid, impl, toVoid, flagMark, null));
|
||||
amfFail(NullPointerException.class, C.lookup, "m", toI, arr(toVoid, impl, toVoid, flagMark, 1, null));
|
||||
amfFail(NullPointerException.class, C.lookup, "m", toI, arr(toVoid, impl, toVoid, flagMark, 2, Runnable.class, null));
|
||||
amfFail(NullPointerException.class, C.lookup, "m", toI, arr(toC, impl2, toC, flagBridge, null));
|
||||
amfFail(NullPointerException.class, C.lookup, "m", toI, arr(toC, impl2, toC, flagBridge, 1, null));
|
||||
amfFail(NullPointerException.class, C.lookup, "m", toI, arr(toC, impl2, toC, flagBridge, 1, null));
|
||||
amfFail(NullPointerException.class, C.lookup, "m", toI, arr(toC, impl2, toC, flagBridge, 2, mt(Object.class), null));
|
||||
amfFail(NullPointerException.class, C.lookup, "m", toI, arr(toC, impl2, toC, flagBridge|flagMark|flagSer, 1, Runnable.class, 2, mt(Object.class), null));
|
||||
}
|
||||
|
||||
public static void testIAE() {
|
||||
MethodType toI = mt(I.class);
|
||||
MethodType toVoid = mt(void.class);
|
||||
MethodType toC = mt(C.class);
|
||||
MethodHandle impl = C.invokeStaticMH();
|
||||
MethodHandle impl2 = C.newInvokeSpecialMH();
|
||||
int flagSer = LambdaMetafactory.FLAG_SERIALIZABLE;
|
||||
int flagMark = LambdaMetafactory.FLAG_MARKERS;
|
||||
int flagBridge = LambdaMetafactory.FLAG_BRIDGES;
|
||||
|
||||
// missing arguments
|
||||
amfFail(IllegalArgumentException.class, C.lookup, "m", toI, arr());
|
||||
amfFail(IllegalArgumentException.class, C.lookup, "m", toI, arr(toVoid, impl, toVoid));
|
||||
amfSucceed(C.lookup, "m", toI, arr(toVoid, impl, toVoid, 0));
|
||||
amfFail(IllegalArgumentException.class, C.lookup, "m", toI, arr(toVoid, impl, toVoid, flagMark));
|
||||
amfFail(IllegalArgumentException.class, C.lookup, "m", toI, arr(toVoid, impl, toVoid, flagMark, 1));
|
||||
amfFail(IllegalArgumentException.class, C.lookup, "m", toI, arr(toVoid, impl, toVoid, flagMark, 2, Runnable.class));
|
||||
amfFail(IllegalArgumentException.class, C.lookup, "m", toI, arr(toC, impl2, toC, flagBridge));
|
||||
amfFail(IllegalArgumentException.class, C.lookup, "m", toI, arr(toC, impl2, toC, flagBridge, 1));
|
||||
amfFail(IllegalArgumentException.class, C.lookup, "m", toI, arr(toC, impl2, toC, flagBridge, 2, mt(Object.class)));
|
||||
amfFail(IllegalArgumentException.class, C.lookup, "m", toI, arr(toC, impl2, toC, flagBridge|flagMark|flagSer, 1, Runnable.class, 2, mt(Object.class)));
|
||||
|
||||
// too many arguments
|
||||
amfFail(IllegalArgumentException.class, C.lookup, "m", toI, arr(toVoid, impl, toVoid, 0, 1));
|
||||
amfFail(IllegalArgumentException.class, C.lookup, "m", toI, arr(toC, impl2, toC, flagMark|flagSer, 1, Runnable.class, 1, mt(Object.class)));
|
||||
|
||||
// wrong argument types
|
||||
amfFail(IllegalArgumentException.class, C.lookup, "m", toI, arr(impl, impl, toVoid, flagSer));
|
||||
amfFail(IllegalArgumentException.class, C.lookup, "m", toI, arr(toVoid, toVoid, toVoid, flagSer));
|
||||
amfFail(IllegalArgumentException.class, C.lookup, "m", toI, arr(toVoid, impl, impl, flagSer));
|
||||
amfFail(IllegalArgumentException.class, C.lookup, "m", toI, arr(toVoid, impl, toVoid, "hi"));
|
||||
amfFail(IllegalArgumentException.class, C.lookup, "m", toI, arr(toVoid, impl, toVoid, flagMark, Runnable.class));
|
||||
amfFail(IllegalArgumentException.class, C.lookup, "m", toI, arr(toVoid, impl, toVoid, flagBridge, 1, Runnable.class));
|
||||
amfFail(IllegalArgumentException.class, C.lookup, "m", toI, arr(toVoid, impl, toVoid, flagMark, 1, toVoid));
|
||||
|
||||
// negative count
|
||||
amfSucceed(C.lookup, "m", toI, arr(toC, impl2, toC, flagBridge|flagMark|flagSer, 0, 0));
|
||||
amfFail(IllegalArgumentException.class, C.lookup, "m", toI, arr(toC, impl2, toC, flagBridge|flagMark|flagSer, -1, 0));
|
||||
amfFail(IllegalArgumentException.class, C.lookup, "m", toI, arr(toC, impl2, toC, flagBridge|flagMark|flagSer, 0, -1));
|
||||
}
|
||||
|
||||
public static void testLCE() {
|
||||
MethodType toI = mt(I.class);
|
||||
MethodType toC = mt(C.class);
|
||||
MethodType toVoid = mt(void.class);
|
||||
MethodType cToVoid = mt(void.class, C.class);
|
||||
MethodType ccToVoid = mt(void.class, C.class, C.class);
|
||||
MethodType cToC = mt(C.class, C.class);
|
||||
MethodType cToString = mt(String.class, C.class);
|
||||
MethodHandle impl = C.invokeStaticMH();
|
||||
int flagSer = LambdaMetafactory.FLAG_SERIALIZABLE;
|
||||
int flagMark = LambdaMetafactory.FLAG_MARKERS;
|
||||
|
||||
// non-interface
|
||||
mfFail(LambdaConversionException.class, C.lookup, "m", mt(Object.class), toVoid, impl, toVoid);
|
||||
amfFail(LambdaConversionException.class, C.lookup, "m", mt(Object.class), arr(toVoid, impl, toVoid, flagSer));
|
||||
mfFail(LambdaConversionException.class, C.lookup, "m", mt(int.class), toVoid, impl, toVoid);
|
||||
amfFail(LambdaConversionException.class, C.lookup, "m", mt(int.class), arr(toVoid, impl, toVoid, flagSer));
|
||||
amfFail(LambdaConversionException.class, C.lookup, "m", toI, arr(toVoid, impl, toVoid, flagMark, 1, Object.class));
|
||||
amfFail(LambdaConversionException.class, C.lookup, "m", toI, arr(toVoid, impl, toVoid, flagMark, 1, int.class));
|
||||
amfFail(LambdaConversionException.class, C.lookup, "m", toI, arr(toVoid, impl, toVoid, flagMark, 2, Runnable.class, Object.class));
|
||||
|
||||
// lookup without private access
|
||||
mfFail(LambdaConversionException.class, MethodHandles.publicLookup(), "m", toI, toVoid, impl, toVoid);
|
||||
amfFail(LambdaConversionException.class, MethodHandles.publicLookup(), "m", toI, arr(toVoid, impl, toVoid, flagSer));
|
||||
mfFail(LambdaConversionException.class, C.lookup.dropLookupMode(MethodHandles.Lookup.PRIVATE), "m", toI, toVoid, impl, toVoid);
|
||||
amfFail(LambdaConversionException.class, C.lookup.dropLookupMode(MethodHandles.Lookup.PRIVATE), "m", toI, arr(toVoid, impl, toVoid, flagSer));
|
||||
|
||||
// unsupported MethodHandle
|
||||
mfFail(LambdaConversionException.class, C.lookup, "m", toI, cToC, C.getFieldMH(), cToC);
|
||||
amfFail(LambdaConversionException.class, C.lookup, "m", toI, arr(cToC, C.getFieldMH(), cToC, flagSer));
|
||||
mfFail(LambdaConversionException.class, C.lookup, "m", toI, toC, C.getStaticMH(), toC);
|
||||
amfFail(LambdaConversionException.class, C.lookup, "m", toI, arr(toC, C.getStaticMH(), toC, flagSer));
|
||||
mfFail(LambdaConversionException.class, C.lookup, "m", toI, ccToVoid, C.putFieldMH(), ccToVoid);
|
||||
amfFail(LambdaConversionException.class, C.lookup, "m", toI, arr(ccToVoid, C.putFieldMH(), ccToVoid, flagSer));
|
||||
mfFail(LambdaConversionException.class, C.lookup, "m", toI, cToVoid, C.putStaticMH(), cToVoid);
|
||||
amfFail(LambdaConversionException.class, C.lookup, "m", toI, arr(cToVoid, C.putStaticMH(), cToVoid, flagSer));
|
||||
mfSucceed(C.lookup, "m", toI, cToVoid, C.invokeVirtualMH(), cToVoid);
|
||||
amfSucceed(C.lookup, "m", toI, arr(cToVoid, C.invokeVirtualMH(), cToVoid, flagSer));
|
||||
mfSucceed(C.lookup, "m", toI, toVoid, C.invokeStaticMH(), toVoid);
|
||||
amfSucceed(C.lookup, "m", toI, arr(toVoid, C.invokeStaticMH(), toVoid, flagSer));
|
||||
mfSucceed(C.lookup, "m", toI, cToString, C.invokeSpecialMH(), cToString);
|
||||
amfSucceed(C.lookup, "m", toI, arr(cToString, C.invokeSpecialMH(), cToString, flagSer));
|
||||
mfSucceed(C.lookup, "m", toI, toC, C.newInvokeSpecialMH(), toC);
|
||||
amfSucceed(C.lookup, "m", toI, arr(toC, C.newInvokeSpecialMH(), toC, flagSer));
|
||||
mfSucceed(C.lookup, "m", toI, cToVoid, C.invokeInterfaceMH(), cToVoid);
|
||||
amfSucceed(C.lookup, "m", toI, arr(cToVoid, C.invokeInterfaceMH(), cToVoid, flagSer));
|
||||
mfFail(LambdaConversionException.class, C.lookup, "m", toI, toVoid, MethodHandles.empty(toVoid), toVoid);
|
||||
amfFail(LambdaConversionException.class, C.lookup, "m", toI, arr(toVoid, MethodHandles.empty(toVoid), toVoid, flagSer));
|
||||
}
|
||||
|
||||
static MethodType mt(Class<?> ret, Class<?>... params) {
|
||||
return MethodType.methodType(ret, params);
|
||||
}
|
||||
|
||||
static Object[] arr(Object... args) {
|
||||
return args;
|
||||
}
|
||||
|
||||
public static class C implements Runnable {
|
||||
|
||||
public static MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
|
||||
public static MethodHandle getFieldMH() {
|
||||
try { return lookup.findGetter(C.class, "iv", C.class); }
|
||||
catch (ReflectiveOperationException e) { throw new RuntimeException(e); }
|
||||
}
|
||||
|
||||
public static MethodHandle getStaticMH() {
|
||||
try { return lookup.findStaticGetter(C.class, "sv", C.class); }
|
||||
catch (ReflectiveOperationException e) { throw new RuntimeException(e); }
|
||||
}
|
||||
|
||||
public static MethodHandle putFieldMH() {
|
||||
try { return lookup.findSetter(C.class, "iv", C.class); }
|
||||
catch (ReflectiveOperationException e) { throw new RuntimeException(e); }
|
||||
}
|
||||
|
||||
public static MethodHandle putStaticMH() {
|
||||
try { return lookup.findStaticSetter(C.class, "sv", C.class); }
|
||||
catch (ReflectiveOperationException e) { throw new RuntimeException(e); }
|
||||
}
|
||||
|
||||
public static MethodHandle invokeVirtualMH() {
|
||||
try { return lookup.findVirtual(C.class, "im", mt(void.class)); }
|
||||
catch (ReflectiveOperationException e) { throw new RuntimeException(e); }
|
||||
}
|
||||
|
||||
public static MethodHandle invokeStaticMH() {
|
||||
try { return lookup.findStatic(C.class, "sm", mt(void.class)); }
|
||||
catch (ReflectiveOperationException e) { throw new RuntimeException(e); }
|
||||
}
|
||||
|
||||
public static MethodHandle invokeSpecialMH() {
|
||||
try { return lookup.findSpecial(Object.class, "toString", mt(String.class), C.class); }
|
||||
catch (ReflectiveOperationException e) { throw new RuntimeException(e); }
|
||||
}
|
||||
|
||||
public static MethodHandle newInvokeSpecialMH() {
|
||||
try { return lookup.findConstructor(C.class, mt(void.class)); }
|
||||
catch (ReflectiveOperationException e) { throw new RuntimeException(e); }
|
||||
}
|
||||
|
||||
public static MethodHandle invokeInterfaceMH() {
|
||||
try { return lookup.findVirtual(Runnable.class, "run", mt(void.class)); }
|
||||
catch (ReflectiveOperationException e) { throw new RuntimeException(e); }
|
||||
}
|
||||
|
||||
public static C sv;
|
||||
public C iv;
|
||||
public static void sm() {}
|
||||
public void im() {}
|
||||
public C() {}
|
||||
public void run() {}
|
||||
}
|
||||
|
||||
public interface I {}
|
||||
|
||||
static CallSite mfSucceed(MethodHandles.Lookup lookup,
|
||||
String name,
|
||||
MethodType capType,
|
||||
MethodType desc,
|
||||
MethodHandle impl,
|
||||
MethodType checked) {
|
||||
try {
|
||||
return LambdaMetafactory.metafactory(lookup, name, capType, desc, impl, checked);
|
||||
} catch (Throwable t) {
|
||||
String msg = String.format("Unexpected exception during linkage for metafactory(%s, %s, %s, %s, %s, %s)",
|
||||
lookup, name, capType, desc, impl, checked);
|
||||
throw new AssertionError(msg, t);
|
||||
}
|
||||
}
|
||||
|
||||
static void mfFail(Class<?> exceptionType,
|
||||
MethodHandles.Lookup lookup,
|
||||
String name,
|
||||
MethodType capType,
|
||||
MethodType desc,
|
||||
MethodHandle impl,
|
||||
MethodType checked) {
|
||||
try {
|
||||
LambdaMetafactory.metafactory(lookup, name, capType, desc, impl, checked);
|
||||
} catch (Throwable t) {
|
||||
if (exceptionType.isInstance(t)) {
|
||||
return;
|
||||
} else {
|
||||
String msg = String.format("Unexpected exception: expected %s during linkage for metafactory(%s, %s, %s, %s, %s, %s)",
|
||||
exceptionType.getName(), lookup, name, capType, desc, impl, checked);
|
||||
throw new AssertionError(msg, t);
|
||||
}
|
||||
}
|
||||
String msg = String.format("Unexpected success: expected %s during linkage for metafactory(%s, %s, %s, %s, %s, %s)",
|
||||
exceptionType.getName(), lookup, name, capType, desc, impl, checked);
|
||||
throw new AssertionError(msg);
|
||||
}
|
||||
|
||||
static CallSite amfSucceed(MethodHandles.Lookup lookup,
|
||||
String name,
|
||||
MethodType capType,
|
||||
Object[] args) {
|
||||
try {
|
||||
return LambdaMetafactory.altMetafactory(lookup, name, capType, args);
|
||||
} catch (Throwable t) {
|
||||
String msg = String.format("Unexpected exception during linkage for altMetafactory(%s, %s, %s, %s)",
|
||||
lookup, name, capType, Arrays.asList(args));
|
||||
throw new AssertionError(msg, t);
|
||||
}
|
||||
}
|
||||
|
||||
static void amfFail(Class<?> exceptionType,
|
||||
MethodHandles.Lookup lookup,
|
||||
String name,
|
||||
MethodType capType,
|
||||
Object[] args) {
|
||||
try {
|
||||
LambdaMetafactory.altMetafactory(lookup, name, capType, args);
|
||||
} catch (Throwable t) {
|
||||
if (exceptionType.isInstance(t)) {
|
||||
return;
|
||||
} else {
|
||||
String msg = String.format("Unexpected exception: expected %s during linkage for altMetafactory(%s, %s, %s, %s)",
|
||||
exceptionType.getName(), lookup, name, capType, Arrays.asList(args));
|
||||
throw new AssertionError(msg, t);
|
||||
}
|
||||
}
|
||||
String msg = String.format("Unexpected success: expected %s during linkage for altMetafactory(%s, %s, %s, %s)",
|
||||
exceptionType.getName(), lookup, name, capType, Arrays.asList(args));
|
||||
throw new AssertionError(msg);
|
||||
}
|
||||
|
||||
}
|
||||
169
test/jdk/java/lang/invoke/lambda/MetafactoryArityTest.java
Normal file
169
test/jdk/java/lang/invoke/lambda/MetafactoryArityTest.java
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8035776
|
||||
* @summary metafactory should fail if arities are mismatched
|
||||
*/
|
||||
import java.lang.invoke.*;
|
||||
import java.util.Arrays;
|
||||
import static java.lang.invoke.MethodType.methodType;
|
||||
|
||||
public class MetafactoryArityTest {
|
||||
|
||||
public interface I {}
|
||||
public static class C { public static String m(int arg) { return ""; } }
|
||||
|
||||
static final MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
static final Class<?>[] capInt = { int.class };
|
||||
static final MethodHandle C_m;
|
||||
static {
|
||||
try { C_m = lookup.findStatic(C.class, "m", methodType(String.class, int.class)); }
|
||||
catch (NoSuchMethodException | IllegalAccessException e) { throw new RuntimeException(e); }
|
||||
}
|
||||
|
||||
public static void main(String... args) {
|
||||
MethodType unary = methodType(String.class, int.class);
|
||||
MethodType nullary = methodType(String.class);
|
||||
MethodType binary = methodType(String.class, int.class, int.class);
|
||||
MethodType unaryCS = methodType(CharSequence.class, int.class);
|
||||
MethodType nullaryCS = methodType(CharSequence.class);
|
||||
MethodType binaryCS = methodType(CharSequence.class, int.class, int.class);
|
||||
MethodType unaryObj = methodType(Object.class, int.class);
|
||||
MethodType nullaryObj = methodType(Object.class);
|
||||
MethodType binaryObj = methodType(Object.class, int.class, int.class);
|
||||
|
||||
test(true, C_m, unary, unary);
|
||||
test(false, C_m, unary, nullary);
|
||||
test(false, C_m, nullary, unary);
|
||||
test(false, C_m, unary, binary);
|
||||
test(false, C_m, binary, unary);
|
||||
|
||||
testBridge(true, C_m, unary, unary, unaryCS);
|
||||
testBridge(false, C_m, unary, unary, nullaryCS);
|
||||
testBridge(false, C_m, unary, unary, binaryCS);
|
||||
|
||||
testBridge(true, C_m, unary, unary, unaryCS, unaryObj);
|
||||
testBridge(false, C_m, unary, unary, unaryCS, nullaryObj);
|
||||
testBridge(false, C_m, unary, unary, unaryCS, binaryObj);
|
||||
|
||||
testCapture(true, C_m, capInt, nullary, nullary);
|
||||
testCapture(false, C_m, capInt, binary, binary);
|
||||
testCapture(false, C_m, capInt, nullary, unary);
|
||||
testCapture(false, C_m, capInt, nullary, binary);
|
||||
testCapture(false, C_m, capInt, unary, nullary);
|
||||
testCapture(false, C_m, capInt, unary, binary);
|
||||
|
||||
testCaptureBridge(true, C_m, capInt, nullary, nullary, nullaryCS);
|
||||
testCaptureBridge(false, C_m, capInt, unary, unary, unaryCS);
|
||||
testCaptureBridge(false, C_m, capInt, nullary, nullary, unaryCS);
|
||||
testCaptureBridge(false, C_m, capInt, nullary, nullary, binaryCS);
|
||||
|
||||
testCaptureBridge(true, C_m, capInt, nullary, nullary, nullaryCS, nullaryObj);
|
||||
testCaptureBridge(false, C_m, capInt, unary, unary, unaryCS, unaryObj);
|
||||
testCaptureBridge(false, C_m, capInt, nullary, nullary, nullaryCS, unaryObj);
|
||||
testCaptureBridge(false, C_m, capInt, nullary, nullary, nullaryCS, binaryObj);
|
||||
}
|
||||
|
||||
static void test(boolean correct, MethodHandle mh, MethodType instMT, MethodType samMT) {
|
||||
tryMetafactory(correct, mh, new Class<?>[]{}, instMT, samMT);
|
||||
tryAltMetafactory(correct, mh, new Class<?>[]{}, instMT, samMT);
|
||||
}
|
||||
|
||||
static void testBridge(boolean correct, MethodHandle mh, MethodType instMT, MethodType samMT, MethodType... bridgeMTs) {
|
||||
tryAltMetafactory(correct, mh, new Class<?>[]{}, instMT, samMT, bridgeMTs);
|
||||
}
|
||||
|
||||
static void testCapture(boolean correct, MethodHandle mh, Class<?>[] captured, MethodType instMT, MethodType samMT) {
|
||||
tryMetafactory(correct, mh, captured, instMT, samMT);
|
||||
tryAltMetafactory(correct, mh, captured, instMT, samMT);
|
||||
}
|
||||
|
||||
static void testCaptureBridge(boolean correct, MethodHandle mh, Class<?>[] captured,
|
||||
MethodType instMT, MethodType samMT, MethodType... bridgeMTs) {
|
||||
tryAltMetafactory(correct, mh, captured, instMT, samMT, bridgeMTs);
|
||||
}
|
||||
|
||||
static void tryMetafactory(boolean correct, MethodHandle mh, Class<?>[] captured,
|
||||
MethodType instMT, MethodType samMT) {
|
||||
try {
|
||||
LambdaMetafactory.metafactory(lookup, "run", methodType(I.class, captured),
|
||||
samMT, mh, instMT);
|
||||
if (!correct) {
|
||||
throw new AssertionError("Uncaught linkage error:" +
|
||||
" impl=" + mh +
|
||||
", captured=" + Arrays.toString(captured) +
|
||||
", inst=" + instMT +
|
||||
", sam=" + samMT);
|
||||
}
|
||||
}
|
||||
catch (LambdaConversionException e) {
|
||||
if (correct) {
|
||||
throw new AssertionError("Unexpected linkage error:" +
|
||||
" e=" + e +
|
||||
", impl=" + mh +
|
||||
", captured=" + Arrays.toString(captured) +
|
||||
", inst=" + instMT +
|
||||
", sam=" + samMT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void tryAltMetafactory(boolean correct, MethodHandle mh, Class<?>[] captured,
|
||||
MethodType instMT, MethodType samMT, MethodType... bridgeMTs) {
|
||||
boolean bridge = bridgeMTs.length > 0;
|
||||
Object[] args = new Object[bridge ? 5+bridgeMTs.length : 4];
|
||||
args[0] = samMT;
|
||||
args[1] = mh;
|
||||
args[2] = instMT;
|
||||
args[3] = bridge ? LambdaMetafactory.FLAG_BRIDGES : 0;
|
||||
if (bridge) {
|
||||
args[4] = bridgeMTs.length;
|
||||
for (int i = 0; i < bridgeMTs.length; i++) args[5+i] = bridgeMTs[i];
|
||||
}
|
||||
try {
|
||||
LambdaMetafactory.altMetafactory(lookup, "run", methodType(I.class, captured), args);
|
||||
if (!correct) {
|
||||
throw new AssertionError("Uncaught linkage error:" +
|
||||
" impl=" + mh +
|
||||
", captured=" + Arrays.toString(captured) +
|
||||
", inst=" + instMT +
|
||||
", sam=" + samMT +
|
||||
", bridges=" + Arrays.toString(bridgeMTs));
|
||||
}
|
||||
}
|
||||
catch (LambdaConversionException e) {
|
||||
if (correct) {
|
||||
throw new AssertionError("Unexpected linkage error:" +
|
||||
" e=" + e +
|
||||
", impl=" + mh +
|
||||
", captured=" + Arrays.toString(captured) +
|
||||
", inst=" + instMT +
|
||||
", sam=" + samMT +
|
||||
", bridges=" + Arrays.toString(bridgeMTs));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
269
test/jdk/java/lang/invoke/lambda/MetafactoryDescriptorTest.java
Normal file
269
test/jdk/java/lang/invoke/lambda/MetafactoryDescriptorTest.java
Normal file
|
|
@ -0,0 +1,269 @@
|
|||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8035776 8173587
|
||||
* @summary metafactory should fail if instantiatedMethodType does not match sam/bridge descriptors
|
||||
*/
|
||||
import java.lang.invoke.*;
|
||||
import java.util.*;
|
||||
|
||||
public class MetafactoryDescriptorTest {
|
||||
|
||||
static final MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
|
||||
static MethodType mt(Class<?> ret, Class<?>... params) {
|
||||
return MethodType.methodType(ret, params);
|
||||
}
|
||||
|
||||
public interface I {}
|
||||
|
||||
public static class C {
|
||||
public static void m_void(String arg) {}
|
||||
public static boolean m_boolean(String arg) { return true; }
|
||||
public static char m_char(String arg) { return 'x'; }
|
||||
public static byte m_byte(String arg) { return 12; }
|
||||
public static short m_short(String arg) { return 12; }
|
||||
public static int m_int(String arg) { return 12; }
|
||||
public static long m_long(String arg) { return 12; }
|
||||
public static float m_float(String arg) { return 12; }
|
||||
public static double m_double(String arg) { return 12; }
|
||||
public static String m_String(String arg) { return ""; }
|
||||
public static Integer m_Integer(String arg) { return 23; }
|
||||
public static Object m_Object(String arg) { return new Object(); }
|
||||
|
||||
public static String n_boolean(boolean arg) { return ""; }
|
||||
public static String n_char(char arg) { return ""; }
|
||||
public static String n_byte(byte arg) { return ""; }
|
||||
public static String n_short(short arg) { return ""; }
|
||||
public static String n_int(int arg) { return ""; }
|
||||
public static String n_long(long arg) { return ""; }
|
||||
public static String n_float(float arg) { return ""; }
|
||||
public static String n_double(double arg) { return ""; }
|
||||
public static String n_String(String arg) { return ""; }
|
||||
public static String n_Integer(Integer arg) { return ""; }
|
||||
public static String n_Object(Object arg) { return ""; }
|
||||
|
||||
public static MethodHandle getM(Class<?> c) {
|
||||
try {
|
||||
return lookup.findStatic(C.class, "m_" + c.getSimpleName(), mt(c, String.class));
|
||||
}
|
||||
catch (NoSuchMethodException | IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static MethodHandle getN(Class<?> c) {
|
||||
if (c == void.class) return null;
|
||||
try {
|
||||
return lookup.findStatic(C.class, "n_" + c.getSimpleName(), mt(String.class, c));
|
||||
}
|
||||
catch (NoSuchMethodException | IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void main(String... args) {
|
||||
Class<?>[] t = { void.class, boolean.class, char.class,
|
||||
byte.class, short.class, int.class, long.class, float.class, double.class,
|
||||
String.class, Integer.class, Object.class };
|
||||
|
||||
for (int i = 0; i < t.length; i++) {
|
||||
MethodHandle m = C.getM(t[i]);
|
||||
MethodHandle n = C.getN(t[i]); // null for void.class
|
||||
for (int j = 0; j < t.length; j++) {
|
||||
boolean correctRet = t[j].isAssignableFrom(t[i]) || conversions.contains(t[i], t[j]);
|
||||
test(correctRet, m, mt(t[i], String.class), mt(t[j], String.class));
|
||||
testBridge(correctRet, m, mt(t[i], String.class), mt(t[i], String.class),
|
||||
mt(t[j], Object.class));
|
||||
testBridge(correctRet, m, mt(t[i], String.class), mt(t[i], String.class),
|
||||
mt(t[i], CharSequence.class), mt(t[j], Object.class));
|
||||
|
||||
if (t[i] != void.class && t[j] != void.class) {
|
||||
boolean correctParam = t[j].isAssignableFrom(t[i]);
|
||||
test(correctParam, n, mt(String.class, t[i]), mt(String.class, t[j]));
|
||||
testBridge(correctParam, n, mt(String.class, t[i]), mt(String.class, t[i]),
|
||||
mt(Object.class, t[j]));
|
||||
testBridge(correctParam, n, mt(String.class, t[i]), mt(String.class, t[i]),
|
||||
mt(CharSequence.class, t[i]), mt(Object.class, t[j]));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void test(boolean correct, MethodHandle mh, MethodType instMT, MethodType samMT) {
|
||||
tryMetafactory(correct, mh, instMT, samMT);
|
||||
tryAltMetafactory(correct, mh, instMT, samMT);
|
||||
}
|
||||
|
||||
static void testBridge(boolean correct, MethodHandle mh, MethodType instMT, MethodType samMT, MethodType... bridgeMTs) {
|
||||
tryAltMetafactory(correct, mh, instMT, samMT, bridgeMTs);
|
||||
}
|
||||
|
||||
static void tryMetafactory(boolean correct, MethodHandle mh, MethodType instMT, MethodType samMT) {
|
||||
try {
|
||||
LambdaMetafactory.metafactory(lookup, "run", mt(I.class),
|
||||
samMT, mh, instMT);
|
||||
if (!correct) {
|
||||
throw new AssertionError("Unexpected linkage without error:" +
|
||||
" impl=" + mh +
|
||||
", inst=" + instMT +
|
||||
", sam=" + samMT);
|
||||
}
|
||||
}
|
||||
catch (LambdaConversionException e) {
|
||||
if (correct) {
|
||||
throw new AssertionError("Unexpected linkage error:" +
|
||||
" e=" + e +
|
||||
", impl=" + mh +
|
||||
", inst=" + instMT +
|
||||
", sam=" + samMT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void tryAltMetafactory(boolean correct, MethodHandle mh, MethodType instMT, MethodType samMT,
|
||||
MethodType... bridgeMTs) {
|
||||
boolean bridge = bridgeMTs.length > 0;
|
||||
Object[] args = new Object[bridge ? 5+bridgeMTs.length : 4];
|
||||
args[0] = samMT;
|
||||
args[1] = mh;
|
||||
args[2] = instMT;
|
||||
args[3] = bridge ? LambdaMetafactory.FLAG_BRIDGES : 0;
|
||||
if (bridge) {
|
||||
args[4] = bridgeMTs.length;
|
||||
for (int i = 0; i < bridgeMTs.length; i++) args[5+i] = bridgeMTs[i];
|
||||
}
|
||||
try {
|
||||
LambdaMetafactory.altMetafactory(lookup, "run", mt(I.class), args);
|
||||
if (!correct) {
|
||||
throw new AssertionError("Unexpected linkage without error:" +
|
||||
" impl=" + mh +
|
||||
", inst=" + instMT +
|
||||
", sam=" + samMT +
|
||||
", bridges=" + Arrays.toString(bridgeMTs));
|
||||
}
|
||||
}
|
||||
catch (LambdaConversionException e) {
|
||||
if (correct) {
|
||||
throw new AssertionError("Unexpected linkage error:" +
|
||||
" e=" + e +
|
||||
", impl=" + mh +
|
||||
", inst=" + instMT +
|
||||
", sam=" + samMT +
|
||||
", bridges=" + Arrays.toString(bridgeMTs));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class ConversionTable {
|
||||
private final Map<Class<?>, Set<Class<?>>> pairs = new HashMap<>();
|
||||
|
||||
public void put(Class<?> from, Class<?> to) {
|
||||
Set<Class<?>> set = pairs.computeIfAbsent(from, f -> new HashSet<>());
|
||||
set.add(to);
|
||||
}
|
||||
|
||||
public boolean contains(Class<?> from, Class<?> to) {
|
||||
return pairs.containsKey(from) && pairs.get(from).contains(to);
|
||||
}
|
||||
}
|
||||
|
||||
private static ConversionTable conversions = new ConversionTable();
|
||||
static {
|
||||
conversions.put(char.class, int.class);
|
||||
conversions.put(char.class, long.class);
|
||||
conversions.put(char.class, float.class);
|
||||
conversions.put(char.class, double.class);
|
||||
conversions.put(char.class, Character.class);
|
||||
conversions.put(char.class, Object.class);
|
||||
conversions.put(Character.class, char.class);
|
||||
conversions.put(Character.class, int.class);
|
||||
conversions.put(Character.class, long.class);
|
||||
conversions.put(Character.class, float.class);
|
||||
conversions.put(Character.class, double.class);
|
||||
|
||||
conversions.put(byte.class, short.class);
|
||||
conversions.put(byte.class, int.class);
|
||||
conversions.put(byte.class, long.class);
|
||||
conversions.put(byte.class, float.class);
|
||||
conversions.put(byte.class, double.class);
|
||||
conversions.put(byte.class, Byte.class);
|
||||
conversions.put(byte.class, Object.class);
|
||||
conversions.put(Byte.class, byte.class);
|
||||
conversions.put(Byte.class, short.class);
|
||||
conversions.put(Byte.class, int.class);
|
||||
conversions.put(Byte.class, long.class);
|
||||
conversions.put(Byte.class, float.class);
|
||||
conversions.put(Byte.class, double.class);
|
||||
|
||||
conversions.put(short.class, int.class);
|
||||
conversions.put(short.class, long.class);
|
||||
conversions.put(short.class, float.class);
|
||||
conversions.put(short.class, double.class);
|
||||
conversions.put(short.class, Short.class);
|
||||
conversions.put(short.class, Object.class);
|
||||
conversions.put(Short.class, short.class);
|
||||
conversions.put(Short.class, int.class);
|
||||
conversions.put(Short.class, long.class);
|
||||
conversions.put(Short.class, float.class);
|
||||
conversions.put(Short.class, double.class);
|
||||
|
||||
conversions.put(int.class, long.class);
|
||||
conversions.put(int.class, float.class);
|
||||
conversions.put(int.class, double.class);
|
||||
conversions.put(int.class, Integer.class);
|
||||
conversions.put(int.class, Object.class);
|
||||
conversions.put(Integer.class, int.class);
|
||||
conversions.put(Integer.class, long.class);
|
||||
conversions.put(Integer.class, float.class);
|
||||
conversions.put(Integer.class, double.class);
|
||||
|
||||
conversions.put(long.class, float.class);
|
||||
conversions.put(long.class, double.class);
|
||||
conversions.put(long.class, Long.class);
|
||||
conversions.put(long.class, Object.class);
|
||||
conversions.put(Long.class, long.class);
|
||||
conversions.put(Long.class, float.class);
|
||||
conversions.put(Long.class, double.class);
|
||||
|
||||
conversions.put(float.class, double.class);
|
||||
conversions.put(float.class, Float.class);
|
||||
conversions.put(float.class, Object.class);
|
||||
conversions.put(Float.class, float.class);
|
||||
conversions.put(Float.class, double.class);
|
||||
|
||||
conversions.put(double.class, Double.class);
|
||||
conversions.put(double.class, Object.class);
|
||||
conversions.put(Double.class, double.class);
|
||||
|
||||
conversions.put(boolean.class, Boolean.class);
|
||||
conversions.put(boolean.class, Object.class);
|
||||
conversions.put(Boolean.class, boolean.class);
|
||||
}
|
||||
|
||||
}
|
||||
197
test/jdk/java/lang/invoke/lambda/MetafactoryMethodNameTest.java
Normal file
197
test/jdk/java/lang/invoke/lambda/MetafactoryMethodNameTest.java
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8173587
|
||||
* @summary metafactory should fail if the method name is not legal
|
||||
*/
|
||||
import java.lang.invoke.*;
|
||||
import java.util.*;
|
||||
|
||||
public class MetafactoryMethodNameTest {
|
||||
|
||||
public static void main(String... args) {
|
||||
goodName("x");
|
||||
goodName("xy");
|
||||
|
||||
goodName("]");
|
||||
goodName("x]");
|
||||
goodName("]y");
|
||||
goodName("x]y");
|
||||
|
||||
goodName("&");
|
||||
goodName("x&");
|
||||
goodName("&y");
|
||||
goodName("x&y");
|
||||
|
||||
badName(".");
|
||||
badName("x.");
|
||||
badName(".y");
|
||||
badName("x.y");
|
||||
|
||||
badName(";");
|
||||
badName("x;");
|
||||
badName(";y");
|
||||
badName("x;y");
|
||||
|
||||
badName("[");
|
||||
badName("x[");
|
||||
badName("[y");
|
||||
badName("x[y");
|
||||
|
||||
badName("/");
|
||||
badName("x/");
|
||||
badName("/y");
|
||||
badName("x/y");
|
||||
|
||||
badName("<");
|
||||
badName("x<");
|
||||
badName("<y");
|
||||
badName("x<y");
|
||||
|
||||
badName(">");
|
||||
badName("x>");
|
||||
badName(">y");
|
||||
badName("x>y");
|
||||
|
||||
badName("");
|
||||
badName("<init>");
|
||||
badName("<clinit>");
|
||||
}
|
||||
|
||||
static MethodType mt(Class<?> ret, Class<?>... params) {
|
||||
return MethodType.methodType(ret, params);
|
||||
}
|
||||
|
||||
static MethodHandle smh(Class<?> c, String name, MethodType desc) {
|
||||
try {
|
||||
return MethodHandles.lookup().findStatic(c, name, desc);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
static Object[] arr(Object... args) {
|
||||
return args;
|
||||
}
|
||||
|
||||
public static class C {
|
||||
public static void m() {}
|
||||
}
|
||||
|
||||
public interface I {}
|
||||
|
||||
private static MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
private static MethodType toI = mt(I.class);
|
||||
private static MethodType toVoid = mt(void.class);
|
||||
private static MethodHandle mh = smh(C.class, "m", toVoid);
|
||||
private static Class<?> lce = LambdaConversionException.class;
|
||||
|
||||
static void goodName(String name) {
|
||||
succeedMFLinkage(lookup, name, toI, toVoid, mh, toVoid);
|
||||
succeedAltMFLinkage(lookup, name, toI, arr(toVoid, mh, toVoid, LambdaMetafactory.FLAG_SERIALIZABLE));
|
||||
}
|
||||
|
||||
static void badName(String name) {
|
||||
failMFLinkage(lookup, name, toI, toVoid, mh, toVoid, lce);
|
||||
failAltMFLinkage(lookup, name, toI, arr(toVoid, mh, toVoid, LambdaMetafactory.FLAG_SERIALIZABLE), lce);
|
||||
}
|
||||
|
||||
static CallSite succeedMFLinkage(MethodHandles.Lookup lookup,
|
||||
String name,
|
||||
MethodType capType,
|
||||
MethodType desc,
|
||||
MethodHandle impl,
|
||||
MethodType checked) {
|
||||
try {
|
||||
return LambdaMetafactory.metafactory(lookup, name, capType, desc, impl, checked);
|
||||
} catch (Throwable t) {
|
||||
String msg = String.format("Unexpected exception during linkage for metafactory(%s, %s, %s, %s, %s, %s)",
|
||||
lookup, name, capType, desc, impl, checked);
|
||||
throw new AssertionError(msg, t);
|
||||
}
|
||||
}
|
||||
|
||||
static void failMFLinkage(MethodHandles.Lookup lookup,
|
||||
String name,
|
||||
MethodType capType,
|
||||
MethodType desc,
|
||||
MethodHandle impl,
|
||||
MethodType checked,
|
||||
Class<?> expectedExceptionType) {
|
||||
try {
|
||||
LambdaMetafactory.metafactory(lookup, name, capType, desc, impl, checked);
|
||||
} catch (Throwable t) {
|
||||
if (expectedExceptionType.isInstance(t)) {
|
||||
return;
|
||||
} else {
|
||||
String msg = String.format("Unexpected exception: expected %s during linkage for metafactory(%s, %s, %s, %s, %s, %s)",
|
||||
expectedExceptionType.getName(),
|
||||
lookup, name, capType, desc, impl, checked);
|
||||
throw new AssertionError(msg, t);
|
||||
}
|
||||
}
|
||||
String msg = String.format("Unexpected success: expected %s during linkage for metafactory(%s, %s, %s, %s, %s, %s)",
|
||||
expectedExceptionType.getName(),
|
||||
lookup, name, capType, desc, impl, checked);
|
||||
throw new AssertionError(msg);
|
||||
}
|
||||
|
||||
static CallSite succeedAltMFLinkage(MethodHandles.Lookup lookup,
|
||||
String name,
|
||||
MethodType capType,
|
||||
Object[] args) {
|
||||
try {
|
||||
return LambdaMetafactory.altMetafactory(lookup, name, capType, args);
|
||||
} catch (Throwable t) {
|
||||
String msg = String.format("Unexpected exception during linkage for metafactory(%s, %s, %s, %s)",
|
||||
lookup, name, capType, Arrays.asList(args));
|
||||
throw new AssertionError(msg, t);
|
||||
}
|
||||
}
|
||||
|
||||
static void failAltMFLinkage(MethodHandles.Lookup lookup,
|
||||
String name,
|
||||
MethodType capType,
|
||||
Object[] args,
|
||||
Class<?> expectedExceptionType) {
|
||||
try {
|
||||
LambdaMetafactory.altMetafactory(lookup, name, capType, args);
|
||||
} catch (Throwable t) {
|
||||
if (expectedExceptionType.isInstance(t)) {
|
||||
return;
|
||||
} else {
|
||||
String msg = String.format("Unexpected exception: expected %s during linkage for metafactory(%s, %s, %s, %s)",
|
||||
expectedExceptionType.getName(),
|
||||
lookup, name, capType, Arrays.asList(args));
|
||||
throw new AssertionError(msg, t);
|
||||
}
|
||||
}
|
||||
String msg = String.format("Unexpected success: expected %s during linkage for metafactory(%s, %s, %s, %s)",
|
||||
expectedExceptionType.getName(),
|
||||
lookup, name, capType, Arrays.asList(args));
|
||||
throw new AssertionError(msg);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,211 @@
|
|||
/*
|
||||
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8035776
|
||||
* @summary Ensure that invocation parameters are always cast to the instantiatedMethodType
|
||||
*/
|
||||
import java.lang.invoke.*;
|
||||
import java.util.Arrays;
|
||||
import static java.lang.invoke.MethodType.methodType;
|
||||
|
||||
public class MetafactoryParameterCastTest {
|
||||
|
||||
static final MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
|
||||
public static class A {
|
||||
}
|
||||
|
||||
public static class B extends A {
|
||||
void instance0() {}
|
||||
void instance1(B arg) {}
|
||||
static void static1(B arg) {}
|
||||
static void static2(B arg1, B arg2) {}
|
||||
}
|
||||
|
||||
public static class C extends B {}
|
||||
public static class NotC extends B {}
|
||||
|
||||
public interface ASink { void take(A arg); }
|
||||
public interface BSink { void take(B arg); }
|
||||
|
||||
public static void main(String... args) throws Throwable {
|
||||
new MetafactoryParameterCastTest().test();
|
||||
}
|
||||
|
||||
void test() throws Throwable {
|
||||
MethodType takeA = methodType(void.class, A.class);
|
||||
MethodType takeB = methodType(void.class, B.class);
|
||||
MethodType takeC = methodType(void.class, C.class);
|
||||
|
||||
Class<?>[] noCapture = {};
|
||||
Class<?>[] captureB = { B.class };
|
||||
|
||||
MethodHandle[] oneBParam = { lookup.findVirtual(B.class, "instance0", methodType(void.class)),
|
||||
lookup.findStatic(B.class, "static1", methodType(void.class, B.class)) };
|
||||
MethodHandle[] twoBParams = { lookup.findVirtual(B.class, "instance1", methodType(void.class, B.class)),
|
||||
lookup.findStatic(B.class, "static2", methodType(void.class, B.class, B.class)) };
|
||||
|
||||
for (MethodHandle mh : oneBParam) {
|
||||
// sam
|
||||
tryASink(invokeMetafactory(mh, ASink.class, "take", noCapture, takeC, takeA));
|
||||
tryBSink(invokeMetafactory(mh, BSink.class, "take", noCapture, takeC, takeB));
|
||||
tryASink(invokeAltMetafactory(mh, ASink.class, "take", noCapture, takeC, takeA));
|
||||
tryBSink(invokeAltMetafactory(mh, BSink.class, "take", noCapture, takeC, takeB));
|
||||
|
||||
// bridge
|
||||
tryASink(invokeAltMetafactory(mh, ASink.class, "take", noCapture, takeC, takeC, takeA));
|
||||
tryBSink(invokeAltMetafactory(mh, BSink.class, "take", noCapture, takeC, takeC, takeB));
|
||||
}
|
||||
|
||||
for (MethodHandle mh : twoBParams) {
|
||||
// sam
|
||||
tryCapASink(invokeMetafactory(mh, ASink.class, "take", captureB, takeC, takeA));
|
||||
tryCapBSink(invokeMetafactory(mh, BSink.class, "take", captureB, takeC, takeB));
|
||||
tryCapASink(invokeAltMetafactory(mh, ASink.class, "take", captureB, takeC, takeA));
|
||||
tryCapBSink(invokeAltMetafactory(mh, BSink.class, "take", captureB, takeC, takeB));
|
||||
|
||||
// bridge
|
||||
tryCapASink(invokeAltMetafactory(mh, ASink.class, "take", captureB, takeC, takeC, takeA));
|
||||
tryCapBSink(invokeAltMetafactory(mh, BSink.class, "take", captureB, takeC, takeC, takeB));
|
||||
}
|
||||
}
|
||||
|
||||
void tryASink(CallSite cs) throws Throwable {
|
||||
ASink sink = (ASink) cs.dynamicInvoker().invoke();
|
||||
tryASink(sink);
|
||||
}
|
||||
|
||||
void tryCapASink(CallSite cs) throws Throwable {
|
||||
ASink sink = (ASink) cs.dynamicInvoker().invoke(new B());
|
||||
tryASink(sink);
|
||||
}
|
||||
|
||||
void tryBSink(CallSite cs) throws Throwable {
|
||||
BSink sink = (BSink) cs.dynamicInvoker().invoke();
|
||||
tryBSink(sink);
|
||||
}
|
||||
|
||||
void tryCapBSink(CallSite cs) throws Throwable {
|
||||
BSink sink = (BSink) cs.dynamicInvoker().invoke(new B());
|
||||
tryBSink(sink);
|
||||
}
|
||||
|
||||
void tryASink(ASink sink) {
|
||||
try { sink.take(new C()); }
|
||||
catch (ClassCastException e) {
|
||||
throw new AssertionError("Unexpected cast failure: " + e + " " + lastMFParams());
|
||||
}
|
||||
|
||||
try {
|
||||
sink.take(new B());
|
||||
throw new AssertionError("Missing cast from A to C: " + lastMFParams());
|
||||
}
|
||||
catch (ClassCastException e) { /* expected */ }
|
||||
|
||||
try {
|
||||
sink.take(new NotC());
|
||||
throw new AssertionError("Missing cast from A to C: " + lastMFParams());
|
||||
}
|
||||
catch (ClassCastException e) { /* expected */ }
|
||||
}
|
||||
|
||||
void tryBSink(BSink sink) {
|
||||
try { sink.take(new C()); }
|
||||
catch (ClassCastException e) {
|
||||
throw new AssertionError("Unexpected cast failure: " + e + " " + lastMFParams());
|
||||
}
|
||||
|
||||
try {
|
||||
sink.take(new B());
|
||||
throw new AssertionError("Missing cast from B to C: " + lastMFParams());
|
||||
}
|
||||
catch (ClassCastException e) { /* expected */ }
|
||||
|
||||
try {
|
||||
sink.take(new NotC());
|
||||
throw new AssertionError("Missing cast from B to C: " + lastMFParams());
|
||||
}
|
||||
catch (ClassCastException e) { /* expected */ }
|
||||
}
|
||||
|
||||
MethodHandle lastMH;
|
||||
Class<?>[] lastCaptured;
|
||||
MethodType lastInstMT;
|
||||
MethodType lastSamMT;
|
||||
MethodType[] lastBridgeMTs;
|
||||
|
||||
String lastMFParams() {
|
||||
return "mh=" + lastMH +
|
||||
", captured=" + Arrays.toString(lastCaptured) +
|
||||
", instMT=" + lastInstMT +
|
||||
", samMT=" + lastSamMT +
|
||||
", bridgeMTs=" + Arrays.toString(lastBridgeMTs);
|
||||
}
|
||||
|
||||
CallSite invokeMetafactory(MethodHandle mh, Class<?> sam, String methodName,
|
||||
Class<?>[] captured, MethodType instMT, MethodType samMT) {
|
||||
lastMH = mh;
|
||||
lastCaptured = captured;
|
||||
lastInstMT = instMT;
|
||||
lastSamMT = samMT;
|
||||
lastBridgeMTs = new MethodType[]{};
|
||||
try {
|
||||
return LambdaMetafactory.metafactory(lookup, methodName, methodType(sam, captured),
|
||||
samMT, mh, instMT);
|
||||
}
|
||||
catch (LambdaConversionException e) {
|
||||
// unexpected linkage error
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
CallSite invokeAltMetafactory(MethodHandle mh, Class<?> sam, String methodName,
|
||||
Class<?>[] captured, MethodType instMT,
|
||||
MethodType samMT, MethodType... bridgeMTs) {
|
||||
lastMH = mh;
|
||||
lastCaptured = captured;
|
||||
lastInstMT = instMT;
|
||||
lastSamMT = samMT;
|
||||
lastBridgeMTs = bridgeMTs;
|
||||
try {
|
||||
boolean bridge = bridgeMTs.length > 0;
|
||||
Object[] args = new Object[bridge ? 5+bridgeMTs.length : 4];
|
||||
args[0] = samMT;
|
||||
args[1] = mh;
|
||||
args[2] = instMT;
|
||||
args[3] = bridge ? LambdaMetafactory.FLAG_BRIDGES : 0;
|
||||
if (bridge) {
|
||||
args[4] = bridgeMTs.length;
|
||||
for (int i = 0; i < bridgeMTs.length; i++) args[5+i] = bridgeMTs[i];
|
||||
}
|
||||
return LambdaMetafactory.altMetafactory(lookup, methodName, methodType(sam, captured), args);
|
||||
}
|
||||
catch (LambdaConversionException e) {
|
||||
// unexpected linkage error
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8027681
|
||||
* @summary Lambda serialization fails once reflection proxy generation kicks in
|
||||
* @author Robert Field
|
||||
* @run main/othervm RepetitiveLambdaSerialization
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
|
||||
public class RepetitiveLambdaSerialization {
|
||||
|
||||
static final int REPS = 20;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
LSI ls = z -> "[" + z + "]";
|
||||
for (int i = 0; i < REPS; ++i) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ObjectOutput out = new ObjectOutputStream(baos);
|
||||
out.writeObject(ls);
|
||||
out.flush();
|
||||
out.close();
|
||||
}
|
||||
System.out.println("Passed.");
|
||||
}
|
||||
}
|
||||
|
||||
interface LSI extends Serializable {
|
||||
String convert(String x);
|
||||
}
|
||||
69
test/jdk/java/lang/invoke/lambda/T8032697.java
Normal file
69
test/jdk/java/lang/invoke/lambda/T8032697.java
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8032697
|
||||
* @summary Issues with Lambda
|
||||
*/
|
||||
|
||||
import java.lang.invoke.LambdaMetafactory;
|
||||
import java.lang.invoke.LambdaConversionException;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
|
||||
import T8032697_anotherpkg.T8032697_A;
|
||||
|
||||
public class T8032697 extends T8032697_A {
|
||||
|
||||
interface I {
|
||||
int m();
|
||||
}
|
||||
|
||||
interface IA {
|
||||
int m(T8032697_A x);
|
||||
}
|
||||
|
||||
static MethodHandles.Lookup l;
|
||||
static MethodHandle h;
|
||||
private static MethodType mt(Class<?> k) { return MethodType.methodType(k); }
|
||||
private static MethodType mt(Class<?> k, Class<?> k2) { return MethodType.methodType(k, k2); }
|
||||
private static boolean mf(MethodType mti, MethodType mtf) {
|
||||
try {
|
||||
LambdaMetafactory.metafactory(l, "m", mti,mtf,h,mtf);
|
||||
} catch(LambdaConversionException e) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
l = MethodHandles.lookup();
|
||||
h = l.findVirtual(T8032697_A.class, "f", mt(int.class));
|
||||
if (mf(mt(I.class, T8032697.class), mt(int.class))) throw new AssertionError("Error: Should work");
|
||||
if (mf(mt(IA.class), mt(int.class, T8032697.class))) throw new AssertionError("Error: Should work");
|
||||
if (!mf(mt(I.class, T8032697_A.class), mt(int.class))) throw new AssertionError("Error: Should fail");
|
||||
if (!mf(mt(IA.class), mt(int.class, T8032697_A.class))) throw new AssertionError("Error: Should fail");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package T8032697_anotherpkg;
|
||||
|
||||
public class T8032697_A {
|
||||
protected final int f() { return 2; }
|
||||
}
|
||||
62
test/jdk/java/lang/invoke/lambda/T8032704.java
Normal file
62
test/jdk/java/lang/invoke/lambda/T8032704.java
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8032704
|
||||
* @summary Issues with lib perm in Lambda
|
||||
*/
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.lang.invoke.LambdaMetafactory;
|
||||
import java.lang.invoke.LambdaConversionException;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
|
||||
public class T8032704 {
|
||||
|
||||
public static void here() {}
|
||||
static MethodHandle h;
|
||||
private static MethodType mt(Class<?> k) { return MethodType.methodType(k); }
|
||||
private static boolean mf(MethodHandles.Lookup l) {
|
||||
try {
|
||||
LambdaMetafactory.metafactory(l, "close",
|
||||
mt(Closeable.class),mt(void.class),h,mt(void.class));
|
||||
} catch(LambdaConversionException e) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
MethodHandles.Lookup ll = MethodHandles.lookup();
|
||||
h = ll.findStatic(T8032704.class, "here", mt(void.class));
|
||||
if (mf(ll)) throw new AssertionError("Error: Should work");
|
||||
if (!mf(MethodHandles.publicLookup())) throw new AssertionError("Error: Should fail - public");
|
||||
if (!mf(ll.in(T8032704other.class))) throw new AssertionError("Error: Should fail - other");
|
||||
if (!mf(ll.in(Thread.class))) throw new AssertionError("Error: Should fail - Thread");
|
||||
}
|
||||
}
|
||||
|
||||
class T8032704other {}
|
||||
62
test/jdk/java/lang/invoke/lambda/T8032711.java
Normal file
62
test/jdk/java/lang/invoke/lambda/T8032711.java
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8032711
|
||||
* @summary Issue with Lambda in handling
|
||||
*/
|
||||
|
||||
import java.lang.invoke.LambdaMetafactory;
|
||||
import java.lang.invoke.LambdaConversionException;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
|
||||
public class T8032711 {
|
||||
|
||||
interface I {
|
||||
void m();
|
||||
}
|
||||
|
||||
static void here() {}
|
||||
static MethodHandles.Lookup l;
|
||||
static MethodHandle h;
|
||||
private static MethodType mt(Class<?> k) { return MethodType.methodType(k); }
|
||||
private static boolean mf(Class<?> k) {
|
||||
try {
|
||||
LambdaMetafactory.metafactory(l, "m",
|
||||
mt(I.class),mt(k),h,mt(void.class));
|
||||
} catch(LambdaConversionException e) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
l = MethodHandles.lookup();
|
||||
h = l.findStatic(T8032711.class, "here", mt(void.class));
|
||||
if (mf(void.class)) throw new AssertionError("Error: Should work");
|
||||
if (!mf(String.class)) throw new AssertionError("Error: Should fail");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.nio.charset.*;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
/*
|
||||
* Testcase for verifying deserializeLambda containing a non-ASCII mappable char
|
||||
* is correctly handled as UTF-8
|
||||
*/
|
||||
public class TestLambdaFileEncodingSerialization {
|
||||
public static class ABCâ implements Serializable {
|
||||
public String msg;
|
||||
public ABCâ() {
|
||||
msg = "Hello world";
|
||||
}
|
||||
public static Callable<ABCâ> getHello() {
|
||||
return (Callable<ABCâ> & Serializable) () -> {
|
||||
return new ABCâ();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Re-serialize the object containing the lambda
|
||||
private static <T> T reserialize(T o) throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ObjectOutputStream oos = new ObjectOutputStream(baos);
|
||||
|
||||
oos.writeObject(o);
|
||||
|
||||
oos.close();
|
||||
|
||||
ObjectInputStream iis = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()));
|
||||
|
||||
try {
|
||||
o = (T)iis.readObject();
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
iis.close();
|
||||
return o;
|
||||
}
|
||||
|
||||
public static void main(String args[]) throws Exception{
|
||||
System.out.println("Default charset = "+Charset.defaultCharset());
|
||||
|
||||
// Construct class containing suitable UTF-8 char
|
||||
Callable<ABCâ> foo = ABCâ.getHello();
|
||||
ABCâ hello = new ABCâ();
|
||||
|
||||
// re-serialize hello
|
||||
ABCâ rh = reserialize(hello);
|
||||
System.out.println(rh.msg);
|
||||
|
||||
// re-serialize foo and call()
|
||||
reserialize(foo).call();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
* Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8274848
|
||||
* @run junit InvokeSpecialMethodTest
|
||||
* @summary ensure REF_invokeSpecial on a non-private implementation method
|
||||
* behaves as if `super::m` is invoked regardless of its access flag
|
||||
*/
|
||||
|
||||
import java.lang.invoke.CallSite;
|
||||
import java.lang.invoke.LambdaMetafactory;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodHandles.Lookup;
|
||||
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import static java.lang.invoke.MethodType.methodType;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class InvokeSpecialMethodTest {
|
||||
static class MethodTest {
|
||||
static final Lookup LOOKUP = MethodHandles.lookup();
|
||||
|
||||
public String m_public() {
|
||||
return "test_public";
|
||||
}
|
||||
|
||||
protected String m_protected() {
|
||||
return "test_protected";
|
||||
}
|
||||
|
||||
private String m_private() {
|
||||
return "test_private";
|
||||
}
|
||||
|
||||
public static class SubClass extends MethodTest {
|
||||
@Override
|
||||
public String m_public() {
|
||||
return "subclass_public";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String m_protected() {
|
||||
return "subclass_protected";
|
||||
}
|
||||
|
||||
public String m_private() {
|
||||
return "subclass_private";
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* findSpecial with Test class as the special caller matching
|
||||
* the factory type `StringFactory(Test)`
|
||||
*/
|
||||
static MethodHandle mh(String name) {
|
||||
try {
|
||||
return LOOKUP.findSpecial(MethodTest.class, name, methodType(String.class), MethodTest.class);
|
||||
} catch (NoSuchMethodException | IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
static final MethodHandle M_PUBLIC = mh("m_public");
|
||||
static final MethodHandle M_PROTECTED = mh("m_protected");
|
||||
static final MethodHandle M_PRIVATE = mh("m_private");
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
interface StringFactory {
|
||||
String get();
|
||||
}
|
||||
|
||||
public static Object[][] methodProvider() {
|
||||
return new Object[][]{
|
||||
{MethodTest.M_PUBLIC, "test_public"},
|
||||
{MethodTest.M_PROTECTED, "test_protected"},
|
||||
{MethodTest.M_PRIVATE, "test_private"}
|
||||
};
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("methodProvider")
|
||||
void test(MethodHandle implMethod, String expected) throws Throwable {
|
||||
testMetafactory(implMethod, expected);
|
||||
testAltMetafactory(implMethod, expected);
|
||||
}
|
||||
|
||||
static void testMetafactory(MethodHandle implMethod, String expected) throws Throwable {
|
||||
CallSite cs = LambdaMetafactory.metafactory(MethodTest.LOOKUP, "get",
|
||||
methodType(StringFactory.class, MethodTest.class),
|
||||
methodType(String.class), implMethod, methodType(String.class));
|
||||
MethodTest o = new MethodTest.SubClass();
|
||||
StringFactory factory = (StringFactory) cs.dynamicInvoker().invokeExact(o);
|
||||
String actual = factory.get();
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
static void testAltMetafactory(MethodHandle implMethod, String expected) throws Throwable {
|
||||
CallSite cs = LambdaMetafactory.altMetafactory(MethodTest.LOOKUP, "get",
|
||||
methodType(StringFactory.class, MethodTest.class),
|
||||
methodType(String.class), implMethod, methodType(String.class),
|
||||
LambdaMetafactory.FLAG_SERIALIZABLE);
|
||||
MethodTest o = new MethodTest.SubClass();
|
||||
StringFactory factory = (StringFactory) cs.dynamicInvoker().invokeExact(o);
|
||||
String actual = factory.get();
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8239384
|
||||
* @modules jdk.compiler
|
||||
* @library /test/lib
|
||||
* @build jdk.test.lib.Utils
|
||||
* jdk.test.lib.compiler.CompilerUtils
|
||||
* @run junit/othervm InheritedProtectedMethod
|
||||
* @summary Test method reference to a method inherited from its
|
||||
* superclass in a different package. Such method's modifier
|
||||
* is changed from public to protected.
|
||||
*/
|
||||
|
||||
import jdk.test.lib.compiler.CompilerUtils;
|
||||
import jdk.test.lib.Utils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class InheritedProtectedMethod {
|
||||
private static final Path SRC_DIR = Paths.get(Utils.TEST_SRC, "src");
|
||||
private static final Path CLASSES_DIR = Paths.get("classes");
|
||||
|
||||
@BeforeAll
|
||||
static void setup() throws IOException {
|
||||
assertTrue(CompilerUtils.compile(SRC_DIR, CLASSES_DIR));
|
||||
|
||||
// compile the modified version of MethodSupplierOuter.java
|
||||
Path file = Paths.get(Utils.TEST_SRC, "modified", "MethodSupplierOuter.java");
|
||||
assertTrue(CompilerUtils.compile(file, CLASSES_DIR));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void run() throws Exception {
|
||||
URLClassLoader loader = new URLClassLoader("loader", new URL[]{ CLASSES_DIR.toUri().toURL()},
|
||||
ClassLoader.getPlatformClassLoader());
|
||||
Class<?> methodInvokeClass = Class.forName("MethodInvoker", false, loader);
|
||||
Method invokeMethod = methodInvokeClass.getMethod("invoke");
|
||||
|
||||
String result = (String)invokeMethod.invoke(null);
|
||||
assertEquals("protected inherited method", result);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,178 @@
|
|||
/*
|
||||
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8227415 8254975 8270056
|
||||
* @run junit/othervm p.ProtectedMethodInOtherPackage
|
||||
* @summary method reference to a protected method inherited from its
|
||||
* superclass in a different runtime package where
|
||||
* lambda proxy class has no access to it.
|
||||
*/
|
||||
|
||||
package p;
|
||||
|
||||
import q.I;
|
||||
import q.J;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class ProtectedMethodInOtherPackage {
|
||||
@Test
|
||||
public void remotePackageSameLoader() {
|
||||
Sub_I sub = new Sub_I();
|
||||
sub.test(Paths.get("test"));
|
||||
}
|
||||
|
||||
public static class Sub_J extends J {
|
||||
Sub_J(Function<Path,String> function) {
|
||||
super(function);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Sub_I extends I {
|
||||
public void test(Path path) {
|
||||
/*
|
||||
* The method reference to an inherited protected method
|
||||
* in another package is desugared with REF_invokeVirtual on
|
||||
* a bridge method to invoke protected q.I::filename method
|
||||
*/
|
||||
Sub_J c = new Sub_J(this::filename);
|
||||
c.check(path);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void splitPackage() throws Throwable {
|
||||
ClassLoader parent = new Loader("loader-A", null, A.class);
|
||||
ClassLoader loader = new Loader("loader-B", parent, B.class);
|
||||
Class<?> aClass = Class.forName(A.class.getName(), false, loader);
|
||||
Class<?> bClass = Class.forName(B.class.getName(), false, loader);
|
||||
assertSame(parent, aClass.getClassLoader());
|
||||
assertSame(loader, bClass.getClassLoader());
|
||||
assertEquals(bClass.getPackageName(), aClass.getPackageName());
|
||||
|
||||
Object b = bClass.getDeclaredConstructor().newInstance();
|
||||
|
||||
// verify subclass can access a protected member inherited from
|
||||
// its superclass in a split package
|
||||
MethodHandle test = MethodHandles.lookup()
|
||||
.findVirtual(bClass, "test", MethodType.methodType(void.class));
|
||||
test.invoke(b);
|
||||
|
||||
// verify lambda can access a protected member inherited from
|
||||
// a superclass of the host class where the superclass is in
|
||||
// a split package (not the same runtime package as the host class)
|
||||
MethodHandle get = MethodHandles.lookup()
|
||||
.findVirtual(bClass, "get", MethodType.methodType(Runnable.class));
|
||||
((Runnable) get.invoke(b)).run();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void protectedStaticMethodInSplitPackage() throws Throwable {
|
||||
ClassLoader parent = new Loader("loader-A1", null, A1.class);
|
||||
ClassLoader loader = new Loader("loader-B1", parent, B1.class);
|
||||
Class<?> aClass1 = Class.forName(A1.class.getName(), false, loader);
|
||||
Class<?> bClass1 = Class.forName(B1.class.getName(), false, loader);
|
||||
assertSame(parent, aClass1.getClassLoader());
|
||||
assertSame(loader, bClass1.getClassLoader());
|
||||
assertEquals(bClass1.getPackageName(), aClass1.getPackageName());
|
||||
|
||||
// verify subclass can access a static protected method inherited from
|
||||
// its superclass in a split package
|
||||
MethodHandle test = MethodHandles.lookup()
|
||||
.findStatic(bClass1, "test", MethodType.methodType(void.class));
|
||||
test.invoke();
|
||||
|
||||
// verify lambda can access a static protected method inherited from
|
||||
// a superclass of the host class where the superclass is in
|
||||
// a split package (not the same runtime package as the host class)
|
||||
MethodHandle get = MethodHandles.lookup()
|
||||
.findStatic(bClass1, "get", MethodType.methodType(Runnable.class));
|
||||
((Runnable) get.invoke()).run();
|
||||
}
|
||||
|
||||
static class Loader extends URLClassLoader {
|
||||
static final Path CLASSES_DIR = Paths.get(System.getProperty("test.class.path"));
|
||||
private final Class<?> c;
|
||||
Loader(String name, ClassLoader parent, Class<?> c) {
|
||||
super(name, new URL[]{}, parent);
|
||||
this.c = c;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> findClass(String name) throws ClassNotFoundException {
|
||||
if (name.equals(c.getName())) {
|
||||
try {
|
||||
String path = name.replace('.', '/') + ".class";
|
||||
byte[] bytes = Files.readAllBytes(CLASSES_DIR.resolve(path));
|
||||
return defineClass(name, bytes, 0, bytes.length);
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
return super.findClass(name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class A {
|
||||
protected void func() { }
|
||||
}
|
||||
|
||||
public static class B extends A {
|
||||
public Runnable get() {
|
||||
return this::func;
|
||||
}
|
||||
public void test() {
|
||||
func();
|
||||
}
|
||||
}
|
||||
|
||||
public static class A1 {
|
||||
protected static void func() { }
|
||||
}
|
||||
|
||||
public static class B1 extends A1 {
|
||||
public static Runnable get() {
|
||||
return A1::func;
|
||||
}
|
||||
public static void test() {
|
||||
func();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package anotherpkg;
|
||||
|
||||
public class MethodSupplierOuter {
|
||||
// MethodSupplier is "public" for javac compilation, modified to "protected" for test.
|
||||
public static class MethodSupplier {
|
||||
protected String m()
|
||||
{
|
||||
return "protected inherited method";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package q;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class I {
|
||||
protected String filename(Path file) {
|
||||
return file.toString();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package q;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class J {
|
||||
protected final Function<Path,String> fileReader;
|
||||
|
||||
public J(Function<Path,String> fileReader) {
|
||||
this.fileReader = fileReader;
|
||||
}
|
||||
|
||||
public void check(Path file) {
|
||||
fileReader.apply(file);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import anotherpkg.MethodSupplierOuter;
|
||||
|
||||
public class MethodInvoker extends MethodSupplierOuter.MethodSupplier {
|
||||
public static String invoke() {
|
||||
MyFunctionalInterface fi = new MethodInvoker()::m;
|
||||
return fi.invokeMethodReference();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
interface MyFunctionalInterface {
|
||||
String invokeMethodReference();
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package anotherpkg;
|
||||
|
||||
public class MethodSupplierOuter {
|
||||
// MethodSupplier is "public" for javac compilation, modified to "protected" for test.
|
||||
public static class MethodSupplier {
|
||||
public String m()
|
||||
{
|
||||
return "public inherited method";
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue