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:
russell@unturf.com 2026-03-26 17:11:57 -04:00
commit 0a580b313d
70422 changed files with 17213626 additions and 0 deletions

View 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());
}
}

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

View file

@ -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");
}
}
}

View 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();
}
}

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

View file

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

View 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());
}
}

View file

@ -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");
}
}
}

View 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();
}
}

View file

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

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

View 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");
}
}

View 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");
}
}

View file

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

View 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());
}
}
}

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

View 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");
}
}

View 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");
}
}

View file

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

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

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

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

View file

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

View file

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

View 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");
}
}

View file

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

View 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 {}

View 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");
}
}

View file

@ -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();
}
}

View file

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

View file

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

View file

@ -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();
}
}
}

View file

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

View file

@ -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();
}
}

View file

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

View 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();
}
}

View file

@ -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();
}

View file

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