--- old/src/java.base/share/classes/java/lang/Class.java 2019-12-03 19:37:18.000000000 -0800 +++ new/src/java.base/share/classes/java/lang/Class.java 2019-12-03 19:37:18.000000000 -0800 @@ -28,6 +28,7 @@ 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; @@ -62,8 +63,6 @@ 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; @@ -128,6 +127,11 @@ * other members are the classes and interfaces whose declarations are * enclosed within the top-level class declaration. * + *
Some methods of class {@code Class} expose some characteristics of + * hidden classes. Hidden classes are created by calling + * {@link java.lang.invoke.MethodHandles.Lookup#defineHiddenClass(byte[], boolean, MethodHandles.Lookup.ClassOption...) + * Lookup::defineHiddenClass}. + * *
The following example uses a {@code Class} object to print the * class name of an object: * @@ -457,7 +461,7 @@ * @param name The binary name * of the class * @return {@code Class} object of the given name defined in the given module; - * {@code null} if not found. + * {@code null} if not found * * @throws NullPointerException if the given module or name is {@code null} * @@ -786,6 +790,16 @@ * * * + * + *
If this class object represents a {@linkplain #isHiddenClass() hidden class}, + * then the name is defined by the JVM of the following format: + *
+ * {@code+ * where the fully-qualified binary name is the class name in the {@code ClassFile} + * from which this {@code Class} object was derived and the suffix is an unique + * unqualified name as specified in JVMS 4.2.2. + * *+ '/' + } + *
The class or interface name classname is the binary name of * the class specified above. * @@ -803,6 +817,8 @@ * * @return the name of the class or interface * represented by this object. + * + * @jvms 4.2.2 Unqualified Names */ public String getName() { String name = this.name; @@ -1631,7 +1647,7 @@ else return ReflectionData.NULL_SENTINEL; } - if (isLocalOrAnonymousClass()) + if (isHiddenClass() || isLocalOrAnonymousClass()) return ReflectionData.NULL_SENTINEL; Class> enclosingClass = getEnclosingClass(); if (enclosingClass == null) { // top level class @@ -1646,7 +1662,8 @@ /** * 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 @@ -2807,6 +2824,11 @@ 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) { @@ -2821,7 +2843,6 @@ return pd; } - /** * Returns the ProtectionDomain of this class. */ @@ -3913,6 +3934,14 @@ * 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. * + *
If this class is a {@linkplain Class#isHiddenClass() hidden class}
+ * created by calling
+ * {@link MethodHandles.Lookup#defineHiddenClass(byte[], boolean, MethodHandles.Lookup.ClassOption...)
+ * Lookup::defineHiddenClass} with {@link MethodHandles.Lookup.ClassOption#NESTMATE
+ * NESTMATE} option, then the hidden class is added as a member to
+ * the nest of a {@linkplain MethodHandles.Lookup#lookupClass() lookup class}
+ * dynamically and it has the same nest host as the lookup class.
+ *
* @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
@@ -3941,18 +3970,16 @@
if (isPrimitive() || isArray()) {
return this;
}
- Class> host;
- try {
+
+ Class> host = this.nest;
+ if (host == null) {
host = getNestHost0();
- } catch (LinkageError e) {
- // if we couldn't load our nest-host then we
+ // if null then nest membership validation failed, so 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;
+ if (host == null || host == this) {
+ return this.nest = this;
+ }
+ this.nest = host;
}
// returning a different class requires a security check
SecurityManager sm = System.getSecurityManager();
@@ -3963,6 +3990,9 @@
return host;
}
+ // keep a strong reference to the nest host
+ private transient Class> nest;
+
/**
* Determines if the given {@code Class} is a nestmate of the
* class or interface represented by this {@code Class} object.
@@ -3983,11 +4013,8 @@
c.isPrimitive() || c.isArray()) {
return false;
}
- try {
- return getNestHost0() == c.getNestHost0();
- } catch (LinkageError e) {
- return false;
- }
+
+ return getNestHost() == c.getNestHost();
}
private native Class>[] getNestMembers0();
@@ -4013,6 +4040,13 @@
* interface records itself as a member of that same nest. Any exceptions
* that occur during this validation are rethrown by this method.
*
+ * @apiNote
+ * This method returns the nest members listed in the {@code NestMembers}
+ * attribute. The returned array does not include any hidden class that
+ * were added to the nest of this class 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
*
@@ -4113,5 +4147,23 @@
@Override
public Optional A hidden class 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 14
+ * @see MethodHandles.Lookup#defineHiddenClass
+ */
+ @HotSpotIntrinsicCandidate
+ public native boolean isHiddenClass();
+
}