< prev index next >

src/java.base/share/classes/java/lang/Class.java

Print this page
rev 58565 : 8238358: Implementation of JEP 371: Hidden Classes
Reviewed-by: duke
Contributed-by: mandy.chung@oracle.com, lois.foltan@oracle.com, david.holmes@oracle.com, harold.seigel@oracle.com, serguei.spitsyn@oracle.com, alex.buckley@oracle.com, jamsheed.c.m@oracle.com

@@ -26,10 +26,11 @@
 package java.lang;
 
 import java.lang.annotation.Annotation;
 import java.lang.constant.ClassDesc;
 import java.lang.invoke.TypeDescriptor;
+import java.lang.invoke.MethodHandles;
 import java.lang.module.ModuleReader;
 import java.lang.ref.SoftReference;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.ObjectStreamField;

@@ -61,12 +62,10 @@
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
-import java.util.StringJoiner;
-import java.util.stream.Stream;
 import java.util.stream.Collectors;
 
 import jdk.internal.HotSpotIntrinsicCandidate;
 import jdk.internal.loader.BootLoader;
 import jdk.internal.loader.BuiltinClassLoader;

@@ -126,10 +125,15 @@
  * {@code class} files are generated, for example, a Java compiler
  * will typically record a top-level class as the host of a nest where the
  * other members are the classes and interfaces whose declarations are
  * enclosed within the top-level class declaration.
  *
+ * <p> Some methods of class {@code Class} expose some characteristics of
+ * <em>hidden classes</em>.  Hidden classes are created by calling
+ * {@link java.lang.invoke.MethodHandles.Lookup#defineHiddenClass(byte[], boolean, MethodHandles.Lookup.ClassOption...)
+ * Lookup::defineHiddenClass}.
+ *
  * <p> The following example uses a {@code Class} object to print the
  * class name of an object:
  *
  * <blockquote><pre>
  *     void printClassName(Object obj) {

@@ -804,10 +808,14 @@
      *     returns "[Ljava.lang.Object;"
      * (new int[3][4][5][6][7][8][9]).getClass().getName()
      *     returns "[[[[[[[I"
      * </pre></blockquote>
      *
+     * <p> If this class object represents a {@linkplain #isHiddenClass() hidden class},
+     * then the name of a hidden class is not a binary name and contains
+     * a ASCII {@code '/'} character.
+     *
      * @return  the name of the class or interface
      *          represented by this object.
      */
     public String getName() {
         String name = this.name;

@@ -883,10 +891,18 @@
     // Initialized in JVM not by private constructor
     // This field is filtered from reflection access, i.e. getDeclaredField
     // will throw NoSuchFieldException
     private final ClassLoader classLoader;
 
+    // Set by VM
+    private transient Object classData;
+
+    // package-private
+    Object getClassData() {
+        return classData;
+    }
+
     /**
      * Returns an array of {@code TypeVariable} objects that represent the
      * type variables declared by the generic declaration represented by this
      * {@code GenericDeclaration} object, in declaration order.  Returns an
      * array of length 0 if the underlying generic declaration declares no type

@@ -1634,11 +1650,11 @@
             if (canonicalName != null)
                 return canonicalName + "[]";
             else
                 return ReflectionData.NULL_SENTINEL;
         }
-        if (isLocalOrAnonymousClass())
+        if (isHiddenClass() || isLocalOrAnonymousClass())
             return ReflectionData.NULL_SENTINEL;
         Class<?> enclosingClass = getEnclosingClass();
         if (enclosingClass == null) { // top level class
             return getName();
         } else {

@@ -1649,11 +1665,12 @@
         }
     }
 
     /**
      * Returns {@code true} if and only if the underlying class
-     * is an anonymous class.
+     * is an anonymous class.  An anonymous class is not a
+     * {@linkplain #isHiddenClass() hidden class}.
      *
      * @return {@code true} if and only if this class is an anonymous class.
      * @since 1.5
      */
     public boolean isAnonymousClass() {

@@ -2874,10 +2891,15 @@
     public java.security.ProtectionDomain getProtectionDomain() {
         SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
             sm.checkPermission(SecurityConstants.GET_PD_PERMISSION);
         }
+        return protectionDomain();
+    }
+
+    // package-private
+    java.security.ProtectionDomain protectionDomain() {
         java.security.ProtectionDomain pd = getProtectionDomain0();
         if (pd == null) {
             if (allPermDomain == null) {
                 java.security.Permissions perms =
                     new java.security.Permissions();

@@ -2888,11 +2910,10 @@
             pd = allPermDomain;
         }
         return pd;
     }
 
-
     /**
      * Returns the ProtectionDomain of this class.
      */
     private native java.security.ProtectionDomain getProtectionDomain0();
 

@@ -4006,33 +4027,26 @@
     private native Class<?> getNestHost0();
 
     /**
      * Returns the nest host of the <a href=#nest>nest</a> to which the class
      * or interface represented by this {@code Class} object belongs.
-     * Every class and interface is a member of exactly one nest.
-     * A class or interface that is not recorded as belonging to a nest
-     * belongs to the nest consisting only of itself, and is the nest
-     * host.
-     *
-     * <p>Each of the {@code Class} objects representing array types,
-     * primitive types, and {@code void} returns {@code this} to indicate
-     * that the represented entity belongs to the nest consisting only of
-     * itself, and is the nest host.
+     * Every class and interface belongs to exactly one nest.
      *
-     * <p>If there is a {@linkplain LinkageError linkage error} accessing
-     * the nest host, or if this class or interface is not enumerated as
-     * a member of the nest by the nest host, then it is considered to belong
-     * to its own nest and {@code this} is returned as the host.
-     *
-     * @apiNote A {@code class} file of version 55.0 or greater may record the
-     * host of the nest to which it belongs by using the {@code NestHost}
-     * attribute (JVMS 4.7.28). Alternatively, a {@code class} file of
-     * version 55.0 or greater may act as a nest host by enumerating the nest's
-     * other members with the
-     * {@code NestMembers} attribute (JVMS 4.7.29).
-     * A {@code class} file of version 54.0 or lower does not use these
-     * attributes.
+     * If the nest host of this class or interface has previously
+     * been determined, then this method returns the nest host.
+     * If the nest host of this class or interface has
+     * not previously been determined, then this method determines the nest
+     * host using the algorithm of JVMS 5.4.4, and returns it.
+     *
+     * Often, a class or interface belongs to a nest consisting only of itself,
+     * in which case this method returns {@code this} to indicate that the class
+     * or interface is the nest host.
+     *
+     * <p>If this {@code Class} object represents a primitive type, an array type,
+     * or {@code void}, then this method returns {@code this},
+     * indicating that the represented entity belongs to the nest consisting only of
+     * itself, and is the nest host.
      *
      * @return the nest host of this class or interface
      *
      * @throws SecurityException
      *         If the returned class is not the current class, and

@@ -4049,21 +4063,13 @@
     @CallerSensitive
     public Class<?> getNestHost() {
         if (isPrimitive() || isArray()) {
             return this;
         }
-        Class<?> host;
-        try {
-            host = getNestHost0();
-        } catch (LinkageError e) {
-            // if we couldn't load our nest-host then we
-            // act as-if we have no nest-host attribute
-            return this;
-        }
-        // if null then nest membership validation failed, so we
-        // act as-if we have no nest-host attribute
-        if (host == null || host == this) {
+
+        Class<?> host = getNestHost0();
+        if (host == this) {
             return this;
         }
         // returning a different class requires a security check
         SecurityManager sm = System.getSecurityManager();
         if (sm != null) {

@@ -4091,56 +4097,59 @@
         }
         if (isPrimitive() || isArray() ||
             c.isPrimitive() || c.isArray()) {
             return false;
         }
-        try {
-            return getNestHost0() == c.getNestHost0();
-        } catch (LinkageError e) {
-            return false;
-        }
+
+        return getNestHost() == c.getNestHost();
     }
 
     private native Class<?>[] getNestMembers0();
 
     /**
      * Returns an array containing {@code Class} objects representing all the
      * classes and interfaces that are members of the nest to which the class
      * or interface represented by this {@code Class} object belongs.
-     * The {@linkplain #getNestHost() nest host} of that nest is the zeroth
-     * element of the array. Subsequent elements represent any classes or
-     * interfaces that are recorded by the nest host as being members of
-     * the nest; the order of such elements is unspecified. Duplicates are
-     * permitted.
-     * If the nest host of that nest does not enumerate any members, then the
-     * array has a single element containing {@code this}.
      *
-     * <p>Each of the {@code Class} objects representing array types,
-     * primitive types, and {@code void} returns an array containing only
+     * First, this method obtains the {@linkplain #getNestHost() nest host}, {@code H}, of the nest
+     * to which the class or interface represented by this {@code Class} object belongs.
+     * The zeroth element of the returned array is {@code H}.
+     *
+     * Then, for each class or interface {@code C} which is recorded by {@code H} as being a member
+     * of its nest, this method attempts to obtain the {@code Class} object for {@code C}
+     * (using {@linkplain #getClassLoader() the defining class loader} of the current {@code Class} object),
+     * and then obtains the {@linkplain #getNestHost() nest host} of the nest to which {@code C} belongs.
+     * The classes and interfaces which are recorded by {@code H} as being members of its nest,
+     * and for which {@code H} can be determined as their nest host, are indicated by subsequent elements
+     * of the returned array. The order of such elements is unspecified.
+     * Duplicates are permitted.
+     *
+     * <p>If this {@code Class} object represents a primitive type, an array type,
+     * or {@code void}, then this method returns a single-element array containing
      * {@code this}.
      *
-     * <p>This method validates that, for each class or interface which is
-     * recorded as a member of the nest by the nest host, that class or
-     * interface records itself as a member of that same nest. Any exceptions
-     * that occur during this validation are rethrown by this method.
+     * @apiNote
+     * The returned array includes only the nest members recorded in the {@code NestMembers}
+     * attribute, and not any hidden classes that were added to the nest via
+     * {@link MethodHandles.Lookup#defineHiddenClass(byte[], boolean, MethodHandles.Lookup.ClassOption...)
+     * Lookup::defineHiddenClass}.
      *
      * @return an array of all classes and interfaces in the same nest as
      * this class
      *
-     * @throws LinkageError
-     *         If there is any problem loading or validating a nest member or
-     *         its nest host
      * @throws SecurityException
      *         If any returned class is not the current class, and
      *         if a security manager, <i>s</i>, is present and the caller's
      *         class loader is not the same as or an ancestor of the class
      *         loader for that returned class and invocation of {@link
      *         SecurityManager#checkPackageAccess s.checkPackageAccess()}
      *         denies access to the package of that returned class
      *
      * @since 11
      * @see #getNestHost()
+     * @jvms 4.7.28 The {@code NestHost} Attribute
+     * @jvms 4.7.29 The {@code NestMembers} Attribute
      */
     @CallerSensitive
     public Class<?>[] getNestMembers() {
         if (isPrimitive() || isArray()) {
             return new Class<?>[] { this };

@@ -4222,6 +4231,24 @@
      */
     @Override
     public Optional<ClassDesc> describeConstable() {
         return Optional.of(ClassDesc.ofDescriptor(descriptorString()));
     }
+
+    /**
+     * Returns {@code true} if and only if the underlying class is a hidden class.
+     *
+     * <p> A <em>hidden class</em> is created by calling
+     * {@link MethodHandles.Lookup#defineHiddenClass(byte[], boolean, MethodHandles.Lookup.ClassOption...)
+     * Lookup::defineHiddenClass}.   A hidden class is non-discoverable
+     * by name via {@link Class#forName(String) Class::forName},
+     * {@link ClassLoader#loadClass(String) ClassLoader::loadClass}, and bytecode linkage.
+     *
+     * @return {@code true} if and only if this class is a hidden class.
+     *
+     * @since 15
+     * @see MethodHandles.Lookup#defineHiddenClass
+     */
+    @HotSpotIntrinsicCandidate
+    public native boolean isHiddenClass();
+
 }
< prev index next >