jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java
changeset 42338 a60f280f803c
parent 41829 224facf0da6e
child 42703 20c39ea4a507
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Wed Nov 23 16:16:35 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Thu Dec 01 08:57:53 2016 +0000
@@ -42,6 +42,7 @@
 import java.lang.reflect.Member;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
+import java.lang.reflect.Module;
 import java.lang.reflect.ReflectPermission;
 import java.nio.ByteOrder;
 import java.util.ArrayList;
@@ -142,6 +143,59 @@
     }
 
     /**
+     * Returns a {@link Lookup lookup object} with full capabilities to emulate all
+     * supported bytecode behaviors, including <a href="MethodHandles.Lookup.html#privacc">
+     * private access</a>, on a target class.
+     * This method checks that a caller, specified as a {@code Lookup} object, is allowed to
+     * do <em>deep reflection</em> on the target class. If {@code m1} is the module containing
+     * the {@link Lookup#lookupClass() lookup class}, and {@code m2} is the module containing
+     * the target class, then this check ensures that
+     * <ul>
+     *     <li>{@code m1} {@link Module#canRead reads} {@code m2}.</li>
+     *     <li>{@code m2} {@link Module#isOpen(String,Module) opens} the package containing
+     *     the target class to at least {@code m1}.</li>
+     *     <li>The lookup has the {@link Lookup#MODULE MODULE} lookup mode.</li>
+     * </ul>
+     * <p>
+     * If there is a security manager, its {@code checkPermission} method is called to
+     * check {@code ReflectPermission("suppressAccessChecks")}.
+     * @apiNote The {@code MODULE} lookup mode serves to authenticate that the lookup object
+     * was created by code in the caller module (or derived from a lookup object originally
+     * created by the caller). A lookup object with the {@code MODULE} lookup mode can be
+     * shared with trusted parties without giving away {@code PRIVATE} and {@code PACKAGE}
+     * access to the caller.
+     * @param targetClass the target class
+     * @param lookup the caller lookup object
+     * @return a lookup object for the target class, with private access
+     * @throws IllegalArgumentException if {@code targetClass} is a primitve type or array class
+     * @throws NullPointerException if {@code targetClass} or {@code caller} is {@code null}
+     * @throws IllegalAccessException if the access check specified above fails
+     * @throws SecurityException if denied by the security manager
+     * @since 9
+     */
+    public static Lookup privateLookupIn(Class<?> targetClass, Lookup lookup) throws IllegalAccessException {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) sm.checkPermission(ACCESS_PERMISSION);
+        if (targetClass.isPrimitive())
+            throw new IllegalArgumentException(targetClass + " is a primitive class");
+        if (targetClass.isArray())
+            throw new IllegalArgumentException(targetClass + " is an array class");
+        Module targetModule = targetClass.getModule();
+        Module callerModule = lookup.lookupClass().getModule();
+        if (callerModule != targetModule && targetModule.isNamed()) {
+            if (!callerModule.canRead(targetModule))
+                throw new IllegalAccessException(callerModule + " does not read " + targetModule);
+            String pn = targetClass.getPackageName();
+            assert pn != null && pn.length() > 0 : "unnamed package cannot be in named module";
+            if (!targetModule.isOpen(pn, callerModule))
+                throw new IllegalAccessException(targetModule + " does not open " + pn + " to " + callerModule);
+        }
+        if ((lookup.lookupModes() & Lookup.MODULE) == 0)
+            throw new IllegalAccessException("lookup does not have MODULE lookup mode");
+        return new Lookup(targetClass);
+    }
+
+    /**
      * Performs an unchecked "crack" of a
      * <a href="MethodHandleInfo.html#directmh">direct method handle</a>.
      * The result is as if the user had obtained a lookup object capable enough
@@ -1807,7 +1861,12 @@
             return callerClass;
         }
 
-        private boolean hasPrivateAccess() {
+        /**
+         * Returns {@code true} if this lookup has {@code PRIVATE} access.
+         * @return {@code true} if this lookup has {@code PRIVATE} acesss.
+         * @since 9
+         */
+        public boolean hasPrivateAccess() {
             return (allowedModes & PRIVATE) != 0;
         }