diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java index 70791273212..dea7d6c6c14 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java @@ -99,13 +99,16 @@ public class MethodHandles { *
* As a matter of pure convention, the {@linkplain Lookup#lookupClass lookup class} * of this lookup object will be {@link java.lang.Object}. + * Consequently, the lookup context of this lookup object will be the bootstrap + * class loader, which means it cannot find user classes. * *
* Discussion: * The lookup class can be changed to any other class {@code C} using an expression of the form * {@link Lookup#in publicLookup().in(C.class)}. * Since all classes have equal access to public names, - * such a change would confer no new access rights. + * such a change would confer no new access rights, + * but may change the lookup context by virtue of changing the class loader. * A public lookup object is always subject to * security manager checks. * Also, it cannot access @@ -641,6 +644,11 @@ public class MethodHandles { * then no members, not even public members, will be accessible. * (In all other cases, public members will continue to be accessible.) * + *
+ * The resulting lookup's capabilities for loading classes + * (used during {@link #findClass} invocations) + * are determined by the lookup class' loader, + * which may change due to this operation. * * @param requestedLookupClass the desired lookup class for the new lookup object * @return a lookup object which reports the desired lookup class @@ -939,13 +947,17 @@ assertEquals("[x, y, z]", pb.command().toString()); /** * Looks up a class by name from the lookup context defined by this {@code Lookup} object. The static * initializer of the class is not run. + *
+ * The lookup context here is determined by the {@linkplain #lookupClass() lookup class}, its class + * loader, and the {@linkplain #lookupModes() lookup modes}. In particular, the method first attempts to + * load the requested class, and then determines whether the class is accessible to this lookup object. * * @param targetName the fully qualified name of the class to be looked up. * @return the requested class. * @exception SecurityException if a security manager is present and it * refuses access * @throws LinkageError if the linkage fails - * @throws ClassNotFoundException if the class does not exist. + * @throws ClassNotFoundException if the class cannot be loaded by the lookup class' loader. * @throws IllegalAccessException if the class is not accessible, using the allowed access * modes. * @exception SecurityException if a security manager is present and it @@ -960,6 +972,9 @@ assertEquals("[x, y, z]", pb.command().toString()); /** * Determines if a class can be accessed from the lookup context defined by this {@code Lookup} object. The * static initializer of the class is not run. + *
+ * The lookup context here is determined by the {@linkplain #lookupClass() lookup class} and the + * {@linkplain #lookupModes() lookup modes}. * * @param targetClass the class to be access-checked * diff --git a/jdk/test/java/lang/invoke/t8150782/TestAccessClass.java b/jdk/test/java/lang/invoke/t8150782/TestAccessClass.java new file mode 100644 index 00000000000..5acf3f3bee0 --- /dev/null +++ b/jdk/test/java/lang/invoke/t8150782/TestAccessClass.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2016, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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 + * @compile TestAccessClass.java TestCls.java + * @run testng/othervm -ea -esa test.java.lang.invoke.t8150782.TestAccessClass + */ +package test.java.lang.invoke.t8150782; + +import java.lang.invoke.*; + +import static java.lang.invoke.MethodHandles.*; + +import static org.testng.AssertJUnit.*; + +import org.testng.annotations.*; + +public class TestAccessClass { + + private static boolean initializedClass1; + + private static class Class1 { + static { + initializedClass1 = true; + } + } + + @Test + public void initializerNotRun() throws IllegalAccessException { + lookup().accessClass(Class1.class); + assertFalse(initializedClass1); + } + + @Test + public void returnsSameClass() throws IllegalAccessException, ClassNotFoundException { + Class> aClass = lookup().accessClass(Class1.class); + assertEquals(Class1.class, aClass); + } + + @DataProvider + Object[][] illegalAccessAccess() { + return new Object[][] { + {publicLookup(), Class1.class}, + {publicLookup(), TestCls.getPrivateSIC()} + }; + } + + @Test(dataProvider = "illegalAccessAccess", expectedExceptions = {IllegalAccessException.class}) + public void illegalAccessExceptionTest(Lookup lookup, Class> klass) throws IllegalAccessException, ClassNotFoundException { + lookup.accessClass(klass); + } + + @Test + public void okAccess() throws IllegalAccessException { + lookup().accessClass(TestCls.getPrivateSIC()); + } + +} diff --git a/jdk/test/java/lang/invoke/t8150782/TestCls.java b/jdk/test/java/lang/invoke/t8150782/TestCls.java new file mode 100644 index 00000000000..1aec2657d0a --- /dev/null +++ b/jdk/test/java/lang/invoke/t8150782/TestCls.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2016, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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 test.java.lang.invoke.t8150782; + +import static java.lang.invoke.MethodHandles.*; + +public class TestCls { + + public static final Lookup LOOKUP = lookup(); + + private static class PrivateSIC {} + public static Class getPrivateSIC() { return PrivateSIC.class; } + public static Lookup getLookupForPrivateSIC() { return lookup(); } + +} + diff --git a/jdk/test/java/lang/invoke/t8150782/TestFindClass.java b/jdk/test/java/lang/invoke/t8150782/TestFindClass.java new file mode 100644 index 00000000000..b49118c2b16 --- /dev/null +++ b/jdk/test/java/lang/invoke/t8150782/TestFindClass.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2016, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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 + * @compile TestFindClass.java TestCls.java + * @run testng/othervm -ea -esa test.java.lang.invoke.t8150782.TestFindClass + */ +package test.java.lang.invoke.t8150782; + +import java.lang.invoke.*; + +import static java.lang.invoke.MethodHandles.*; + +import static org.testng.AssertJUnit.*; + +import org.testng.annotations.*; + +public class TestFindClass { + + private static final String PACKAGE_PREFIX = "test.java.lang.invoke.t8150782."; + + private static boolean initializedClass1; + + private static class Class1 { + static { + initializedClass1 = true; + } + } + + @Test + public void initializerNotRun() throws IllegalAccessException, ClassNotFoundException { + lookup().findClass(PACKAGE_PREFIX + "TestFindClass$Class1"); + assertFalse(initializedClass1); + } + + @Test + public void returnsRequestedClass() throws IllegalAccessException, ClassNotFoundException { + Class> aClass = lookup().findClass(PACKAGE_PREFIX + "TestFindClass$Class1"); + assertEquals(Class1.class, aClass); + } + + @Test(expectedExceptions = {ClassNotFoundException.class}) + public void classNotFoundExceptionTest() throws IllegalAccessException, ClassNotFoundException { + lookup().findClass(PACKAGE_PREFIX + "TestFindClass$NonExistent"); + } + + @DataProvider + Object[][] illegalAccessFind() { + return new Object[][] { + {publicLookup(), PACKAGE_PREFIX + "TestFindClass$Class1"}, + {publicLookup(), PACKAGE_PREFIX + "TestCls$PrivateSIC"} + }; + } + + /** + * Assertion: @throws IllegalAccessException if the class is not accessible, using the allowed access modes. + */ + @Test(dataProvider = "illegalAccessFind", expectedExceptions = {ClassNotFoundException.class}) + public void illegalAccessExceptionTest(Lookup lookup, String className) throws IllegalAccessException, ClassNotFoundException { + lookup.findClass(className); + } + + @Test + public void okAccess() throws IllegalAccessException, ClassNotFoundException { + lookup().findClass(PACKAGE_PREFIX + "TestCls$PrivateSIC"); + } + +} diff --git a/jdk/test/java/lang/invoke/t8150782/TestLookup.java b/jdk/test/java/lang/invoke/t8150782/TestLookup.java new file mode 100644 index 00000000000..9a3e2cd9085 --- /dev/null +++ b/jdk/test/java/lang/invoke/t8150782/TestLookup.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2016, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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 + * @run testng/othervm -ea -esa test.java.lang.invoke.t8150782.TestLookup + */ +package test.java.lang.invoke.t8150782; + +import org.testng.annotations.Test; + +import static java.lang.invoke.MethodHandles.*; + +import static org.testng.AssertJUnit.*; + +public class TestLookup { + + @Test + public void testClassLoaderChange() { + Lookup lookup = lookup(); + assertNotNull(lookup.lookupClass().getClassLoader()); + Lookup lookup2 = lookup.in(Object.class); + assertNull(lookup2.lookupClass().getClassLoader()); + } + + @Test(expectedExceptions = {ClassNotFoundException.class}) + public void testPublicCannotLoadUserClass() throws IllegalAccessException, ClassNotFoundException { + Lookup lookup = publicLookup(); + lookup.findClass("test.java.lang.invoke.t8150782.TestCls"); + } + + @Test + public void testPublicCanLoadSystemClass() throws IllegalAccessException, ClassNotFoundException { + Lookup lookup = publicLookup(); + lookup.findClass("java.util.HashMap"); + } + + @Test + public void testPublicInChangesClassLoader() { + Lookup lookup = publicLookup(); + assertNull(lookup.lookupClass().getClassLoader()); + Lookup lookup2 = lookup.in(TestCls.class); + assertNotNull(lookup2.lookupClass().getClassLoader()); + } + +}