< 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,35 **** --- 26,36 ---- 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,72 **** 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; --- 62,71 ----
*** 126,135 **** --- 125,139 ---- * {@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,813 **** --- 808,821 ---- * 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,892 **** --- 891,908 ---- // 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,1644 **** if (canonicalName != null) return canonicalName + "[]"; else return ReflectionData.NULL_SENTINEL; } ! if (isLocalOrAnonymousClass()) return ReflectionData.NULL_SENTINEL; Class<?> enclosingClass = getEnclosingClass(); if (enclosingClass == null) { // top level class return getName(); } else { --- 1650,1660 ---- if (canonicalName != null) return canonicalName + "[]"; else return ReflectionData.NULL_SENTINEL; } ! if (isHiddenClass() || isLocalOrAnonymousClass()) return ReflectionData.NULL_SENTINEL; Class<?> enclosingClass = getEnclosingClass(); if (enclosingClass == null) { // top level class return getName(); } else {
*** 1649,1659 **** } } /** * Returns {@code true} if and only if the underlying class ! * is an anonymous class. * * @return {@code true} if and only if this class is an anonymous class. * @since 1.5 */ public boolean isAnonymousClass() { --- 1665,1676 ---- } } /** * Returns {@code true} if and only if the underlying 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,2883 **** --- 2891,2905 ---- 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,2898 **** pd = allPermDomain; } return pd; } - /** * Returns the ProtectionDomain of this class. */ private native java.security.ProtectionDomain getProtectionDomain0(); --- 2910,2919 ----
*** 4006,4038 **** 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. * ! * <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. * * @return the nest host of this class or interface * * @throws SecurityException * If the returned class is not the current class, and --- 4027,4052 ---- 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 belongs to exactly one nest. * ! * 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,4069 **** @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) { return this; } // returning a different class requires a security check SecurityManager sm = System.getSecurityManager(); if (sm != null) { --- 4063,4075 ---- @CallerSensitive public Class<?> getNestHost() { if (isPrimitive() || isArray()) { return 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,4146 **** } if (isPrimitive() || isArray() || c.isPrimitive() || c.isArray()) { return false; } ! try { ! return getNestHost0() == c.getNestHost0(); ! } catch (LinkageError e) { ! return false; ! } } 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 * {@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. * * @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() */ @CallerSensitive public Class<?>[] getNestMembers() { if (isPrimitive() || isArray()) { return new Class<?>[] { this }; --- 4097,4155 ---- } if (isPrimitive() || isArray() || c.isPrimitive() || c.isArray()) { 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. * ! * 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}. * ! * @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 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,4227 **** --- 4231,4254 ---- */ @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 >