< 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 >