jdk/src/java.base/share/classes/java/lang/Class.java
changeset 36511 9d0388c6b336
parent 34882 ce2a8ec851c1
child 37363 329dba26ffd2
--- a/jdk/src/java.base/share/classes/java/lang/Class.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/Class.java	Thu Mar 17 19:04:16 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1994, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 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
@@ -25,6 +25,8 @@
 
 package java.lang;
 
+import java.lang.annotation.Annotation;
+import java.lang.module.ModuleReader;
 import java.lang.reflect.AnnotatedElement;
 import java.lang.reflect.Array;
 import java.lang.reflect.GenericArrayType;
@@ -33,15 +35,19 @@
 import java.lang.reflect.Field;
 import java.lang.reflect.Executable;
 import java.lang.reflect.Method;
+import java.lang.reflect.Module;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Modifier;
 import java.lang.reflect.Type;
 import java.lang.reflect.TypeVariable;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.AnnotatedType;
+import java.lang.reflect.Proxy;
 import java.lang.ref.SoftReference;
+import java.io.IOException;
 import java.io.InputStream;
 import java.io.ObjectStreamField;
+import java.net.URL;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.util.ArrayList;
@@ -55,9 +61,11 @@
 import java.util.HashMap;
 import java.util.Objects;
 import java.util.StringJoiner;
+import jdk.internal.HotSpotIntrinsicCandidate;
+import jdk.internal.loader.BootLoader;
+import jdk.internal.loader.BuiltinClassLoader;
 import jdk.internal.misc.Unsafe;
 import jdk.internal.misc.VM;
-import jdk.internal.HotSpotIntrinsicCandidate;
 import sun.reflect.CallerSensitive;
 import sun.reflect.ConstantPool;
 import sun.reflect.Reflection;
@@ -69,8 +77,6 @@
 import sun.reflect.generics.repository.ConstructorRepository;
 import sun.reflect.generics.scope.ClassScope;
 import sun.security.util.SecurityConstants;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Proxy;
 import sun.reflect.annotation.*;
 import sun.reflect.misc.ReflectUtil;
 
@@ -378,6 +384,86 @@
                                             Class<?> caller)
         throws ClassNotFoundException;
 
+
+    /**
+     * Returns the {@code Class} with the given <a href="ClassLoader.html#name">
+     * binary name</a> in the given module.
+     *
+     * <p> This method attempts to locate, load, and link the class or interface.
+     * It does not run the class initializer.  If the class is not found, this
+     * method returns {@code null}. </p>
+     *
+     * <p> If the class loader of the given module defines other modules and
+     * the given name is a class defined in a different module, this method
+     * returns {@code null} after the class is loaded. </p>
+     *
+     * <p> This method does not check whether the requested class is
+     * accessible to its caller. </p>
+     *
+     * @apiNote
+     * This method returns {@code null} on failure rather than
+     * throwing a {@link ClassNotFoundException}, as is done by
+     * the {@link #forName(String, boolean, ClassLoader)} method.
+     * The security check is a stack-based permission check if the caller
+     * loads a class in another module.
+     *
+     * @param  module   A module
+     * @param  name     The <a href="ClassLoader.html#name">binary name</a>
+     *                  of the class
+     * @return {@code Class} object of the given name defined in the given module;
+     *         {@code null} if not found.
+     *
+     * @throws NullPointerException if the given module or name is {@code null}
+     *
+     * @throws LinkageError if the linkage fails
+     *
+     * @throws SecurityException
+     *         <ul>
+     *         <li> if the caller is not the specified module and
+     *         {@code RuntimePermission("getClassLoader")} permission is denied; or</li>
+     *         <li> access to the module content is denied. For example,
+     *         permission check will be performed when a class loader calls
+     *         {@link ModuleReader#open(String)} to read the bytes of a class file
+     *         in a module.</li>
+     *         </ul>
+     *
+     * @since 9
+     */
+    @CallerSensitive
+    public static Class<?> forName(Module module, String name) {
+        Objects.requireNonNull(module);
+        Objects.requireNonNull(name);
+
+        Class<?> caller = Reflection.getCallerClass();
+        if (caller != null && caller.getModule() != module) {
+            // if caller is null, Class.forName is the last java frame on the stack.
+            // java.base has all permissions
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null) {
+                sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
+            }
+        }
+
+        PrivilegedAction<ClassLoader> pa = module::getClassLoader;
+        ClassLoader cl = AccessController.doPrivileged(pa);
+        if (module.isNamed() && cl != null) {
+            return cl.loadLocalClass(module, name);
+        }
+
+        final Class<?> c;
+        if (cl != null) {
+            c = cl.loadLocalClass(name);
+        } else {
+            c = BootLoader.loadClassOrNull(name);
+        }
+
+        if (c != null && c.getModule() == module) {
+            return c;
+        } else {
+            return null;
+        }
+    }
+
     /**
      * Creates a new instance of the class represented by this {@code Class}
      * object.  The class is instantiated as if by a {@code new}
@@ -453,13 +539,11 @@
         }
         Constructor<T> tmpConstructor = cachedConstructor;
         // Security check (same as in java.lang.reflect.Constructor)
-        int modifiers = tmpConstructor.getModifiers();
-        if (!Reflection.quickCheckMemberAccess(this, modifiers)) {
-            Class<?> caller = Reflection.getCallerClass();
-            if (newInstanceCallerCache != caller) {
-                Reflection.ensureMemberAccess(caller, this, null, modifiers);
-                newInstanceCallerCache = caller;
-            }
+        Class<?> caller = Reflection.getCallerClass();
+        if (newInstanceCallerCache != caller) {
+            int modifiers = tmpConstructor.getModifiers();
+            Reflection.ensureMemberAccess(caller, this, null, modifiers);
+            newInstanceCallerCache = caller;
         }
         // Run constructor
         try {
@@ -717,6 +801,29 @@
     // Package-private to allow ClassLoader access
     ClassLoader getClassLoader0() { return classLoader; }
 
+    /**
+     * Returns the module that this class or interface is a member of.
+     *
+     * If this class represents an array type then this method returns the
+     * {@code Module} for the element type. If this class represents a
+     * primitive type or void, then the {@code Module} object for the
+     * {@code java.base} module is returned.
+     *
+     * If this class is in an unnamed module then the {@link
+     * ClassLoader#getUnnamedModule() unnamed} {@code Module} of the class
+     * loader for this class is returned.
+     *
+     * @return the module that this class or interface is a member of
+     *
+     * @since 9
+     */
+    public Module getModule() {
+        return module;
+    }
+
+    // set by VM
+    private transient Module module;
+
     // Initialized in JVM not by private constructor
     // This field is filtered from reflection access, i.e. getDeclaredField
     // will throw NoSuchFieldException
@@ -808,24 +915,60 @@
     }
 
     /**
-     * Gets the package for this class.  The class loader of this class is used
-     * to find the package.  If the class was loaded by the bootstrap class
-     * loader the set of packages loaded from CLASSPATH is searched to find the
-     * package of the class. Null is returned if no package object was created
-     * by the class loader of this class.
+     * Gets the package of this class.
      *
-     * <p> Packages have attributes for versions and specifications only if the
-     * information was defined in the manifests that accompany the classes, and
-     * if the class loader created the package instance with the attributes
-     * from the manifest.
+     * <p>If this class represents an array type, a primitive type or void,
+     * this method returns {@code null}.
      *
-     * @return the package of the class, or null if no package
-     *         information is available from the archive or codebase.
+     * @return the package of this class.
      */
     public Package getPackage() {
-        return Package.getPackage(this);
+        if (isPrimitive() || isArray()) {
+            return null;
+        }
+        ClassLoader cl = getClassLoader0();
+        return cl != null ? cl.definePackage(this)
+                          : BootLoader.definePackage(this);
     }
 
+    /**
+     * Returns the fully qualified package name.
+     *
+     * <p> If this class is a top level class, then this method returns the fully
+     * qualified name of the package that the class is a member of, or the
+     * empty string if the class is in an unnamed package.
+     *
+     * <p> If this class is a member class, then this method is equivalent to
+     * invoking {@code getPackageName()} on the {@link #getEnclosingClass
+     * enclosing class}.
+     *
+     * <p> If this class is a {@link #isLocalClass local class} or an {@link
+     * #isAnonymousClass() anonymous class}, then this method is equivalent to
+     * invoking {@code getPackageName()} on the {@link #getDeclaringClass
+     * declaring class} of the {@link #getEnclosingMethod enclosing method} or
+     * {@link #getEnclosingConstructor enclosing constructor}.
+     *
+     * <p> This method returns {@code null} if this class represents an array type,
+     * a primitive type or void.
+     *
+     * @return the fully qualified package name
+     *
+     * @since 9
+     * @jls 6.7  Fully Qualified Names
+     */
+    public String getPackageName() {
+        String pn = this.packageName;
+        if (pn == null && !isArray() && !isPrimitive()) {
+            String cn = getName();
+            int dot = cn.lastIndexOf('.');
+            pn = (dot != -1) ? cn.substring(0, dot).intern() : "";
+            this.packageName = pn;
+        }
+        return pn;
+    }
+
+    // cached package name
+    private String packageName;
 
     /**
      * Returns the interfaces directly implemented by the class or interface
@@ -2213,15 +2356,19 @@
     }
 
     /**
-     * Finds a resource with a given name.  The rules for searching resources
+     * Finds a resource with a given name. If this class is in a named {@link
+     * Module Module}, and the caller of this method is in the same module,
+     * then this method will attempt to find the resource in that module.
+     * Otherwise, the rules for searching resources
      * associated with a given class are implemented by the defining
      * {@linkplain ClassLoader class loader} of the class.  This method
      * delegates to this object's class loader.  If this object was loaded by
      * the bootstrap class loader, the method delegates to {@link
      * ClassLoader#getSystemResourceAsStream}.
      *
-     * <p> Before delegation, an absolute resource name is constructed from the
-     * given resource name using this algorithm:
+     * <p> Before finding a resource in the caller's module or delegation to a
+     * class loader, an absolute resource name is constructed from the given
+     * resource name using this algorithm:
      *
      * <ul>
      *
@@ -2242,26 +2389,60 @@
      * </ul>
      *
      * @param  name name of the desired resource
-     * @return      A {@link java.io.InputStream} object or {@code null} if
-     *              no resource with this name is found
+     * @return  A {@link java.io.InputStream} object or {@code null} if
+     *          no resource with this name is found
      * @throws  NullPointerException If {@code name} is {@code null}
      * @since  1.1
      */
-     public InputStream getResourceAsStream(String name) {
+    @CallerSensitive
+    public InputStream getResourceAsStream(String name) {
         name = resolveName(name);
+
+        // if this Class and the caller are in the same named module
+        // then attempt to get an input stream to the resource in the
+        // module
+        Module module = getModule();
+        if (module.isNamed()) {
+            Class<?> caller = Reflection.getCallerClass();
+            if (caller != null && caller.getModule() == module) {
+                ClassLoader cl = getClassLoader0();
+                String mn = module.getName();
+                try {
+
+                    // special-case built-in class loaders to avoid the
+                    // need for a URL connection
+                    if (cl == null) {
+                        return BootLoader.findResourceAsStream(mn, name);
+                    } else if (cl instanceof BuiltinClassLoader) {
+                        return ((BuiltinClassLoader) cl).findResourceAsStream(mn, name);
+                    } else {
+                        URL url = cl.findResource(mn, name);
+                        return (url != null) ? url.openStream() : null;
+                    }
+
+                } catch (IOException | SecurityException e) {
+                    return null;
+                }
+            }
+        }
+
+        // this Class and caller not in the same named module
         ClassLoader cl = getClassLoader0();
-        if (cl==null) {
-            // A system class.
+        if (cl == null) {
             return ClassLoader.getSystemResourceAsStream(name);
+        } else {
+            return cl.getResourceAsStream(name);
         }
-        return cl.getResourceAsStream(name);
     }
 
     /**
-     * Finds a resource with a given name.  The rules for searching resources
+     * Finds a resource with a given name. If this class is in a named {@link
+     * Module Module}, and the caller of this method is in the same module,
+     * then this method will attempt to find the resource in that module.
+     * Otherwise, the rules for searching resources
      * associated with a given class are implemented by the defining
      * {@linkplain ClassLoader class loader} of the class.  This method
-     * delegates to this object's class loader.  If this object was loaded by
+     * delegates to this object's class loader. If this object was loaded by
      * the bootstrap class loader, the method delegates to {@link
      * ClassLoader#getSystemResource}.
      *
@@ -2287,22 +2468,43 @@
      * </ul>
      *
      * @param  name name of the desired resource
-     * @return      A  {@link java.net.URL} object or {@code null} if no
-     *              resource with this name is found
+     * @return A {@link java.net.URL} object; {@code null} if no
+     *         resource with this name is found or the resource cannot
+     *         be located by a URL.
      * @since  1.1
      */
-    public java.net.URL getResource(String name) {
+    @CallerSensitive
+    public URL getResource(String name) {
         name = resolveName(name);
+
+        // if this Class and the caller are in the same named module
+        // then attempt to get URL to the resource in the module
+        Module module = getModule();
+        if (module.isNamed()) {
+            Class<?> caller = Reflection.getCallerClass();
+            if (caller != null && caller.getModule() == module) {
+                String mn = getModule().getName();
+                ClassLoader cl = getClassLoader0();
+                try {
+                    if (cl == null) {
+                        return BootLoader.findResource(mn, name);
+                    } else {
+                        return cl.findResource(mn, name);
+                    }
+                } catch (IOException ioe) {
+                    return null;
+                }
+            }
+        }
+
         ClassLoader cl = getClassLoader0();
-        if (cl==null) {
-            // A system class.
+        if (cl == null) {
             return ClassLoader.getSystemResource(name);
+        } else {
+            return cl.getResource(name);
         }
-        return cl.getResource(name);
     }
 
-
-
     /** protection domain returned when the internal domain is null */
     private static java.security.ProtectionDomain allPermDomain;
 
@@ -2845,15 +3047,15 @@
         private void remove(int i) {
             if (methods[i] != null && methods[i].isDefault())
                 defaults--;
-            methods[i] = null;
-        }
+                    methods[i] = null;
+                }
 
         private boolean matchesNameAndDescriptor(Method m1, Method m2) {
             return m1.getReturnType() == m2.getReturnType() &&
                    m1.getName() == m2.getName() && // name is guaranteed to be interned
                    arrayContentsEq(m1.getParameterTypes(),
                            m2.getParameterTypes());
-        }
+            }
 
         void compactAndTrim() {
             int newPos = 0;