< prev index next >
src/java.base/share/classes/java/lang/Class.java
Print this page
*** 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;
*** 60,71 ****
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;
--- 61,70 ----
*** 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) {
*** 455,465 ****
*
* @param module A module
* @param name The <a href="ClassLoader.html#binary-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
*
--- 459,469 ----
*
* @param module A module
* @param name The <a href="ClassLoader.html#binary-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
*
*** 784,793 ****
--- 788,807 ----
* <tr><th scope="row"> long <td style="text-align:center"> J
* <tr><th scope="row"> short <td style="text-align:center"> S
* </tbody>
* </table></blockquote>
*
+ *
+ * <p> If this class object represents a {@linkplain #isHiddenClass() hidden class},
+ * then the name is defined by the JVM of the following format:
+ * <blockquote>
+ * {@code <fully-qualified binary name> + '/' + <suffix>}
+ * </blockquote>
+ * 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.
+ *
* <p> The class or interface name <i>classname</i> is the binary name of
* the class specified above.
*
* <p> Examples:
* <blockquote><pre>
*** 801,810 ****
--- 815,826 ----
* returns "[[[[[[[I"
* </pre></blockquote>
*
* @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;
return name != null ? name : initClassName();
}
*** 1629,1639 ****
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 {
--- 1645,1655 ----
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 {
*** 1644,1654 ****
}
}
/**
* 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() {
--- 1660,1671 ----
}
}
/**
* 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() {
*** 2805,2814 ****
--- 2822,2836 ----
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();
*** 2819,2829 ****
pd = allPermDomain;
}
return pd;
}
-
/**
* Returns the ProtectionDomain of this class.
*/
private native java.security.ProtectionDomain getProtectionDomain0();
--- 2841,2850 ----
*** 3911,3920 ****
--- 3932,3949 ----
* <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.
*
+ * <p>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
* version 55.0 or greater may act as a nest host by enumerating the nest's
* other members with the
*** 3939,3970 ****
@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) {
checkPackageAccess(sm,
ClassLoader.getClassLoader(Reflection.getCallerClass()), true);
}
return host;
}
/**
* Determines if the given {@code Class} is a nestmate of the
* class or interface represented by this {@code Class} object.
* Two classes or interfaces are nestmates
* if they have the same {@linkplain #getNestHost() nest host}.
--- 3968,4000 ----
@CallerSensitive
public Class<?> getNestHost() {
if (isPrimitive() || isArray()) {
return this;
}
!
! Class<?> host = this.nest;
! if (host == null) {
host = getNestHost0();
// 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.nest = this;
! }
! this.nest = host;
}
// returning a different class requires a security check
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkPackageAccess(sm,
ClassLoader.getClassLoader(Reflection.getCallerClass()), true);
}
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.
* Two classes or interfaces are nestmates
* if they have the same {@linkplain #getNestHost() nest host}.
*** 3981,3995 ****
}
if (isPrimitive() || isArray() ||
c.isPrimitive() || c.isArray()) {
return false;
}
! try {
! return getNestHost0() == c.getNestHost0();
! } catch (LinkageError e) {
! return false;
! }
}
private native Class<?>[] getNestMembers0();
/**
--- 4011,4022 ----
}
if (isPrimitive() || isArray() ||
c.isPrimitive() || c.isArray()) {
return false;
}
!
! return getNestHost() == c.getNestHost();
}
private native Class<?>[] getNestMembers0();
/**
*** 4011,4020 ****
--- 4038,4054 ----
* <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
+ * 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
*
* @throws LinkageError
* If there is any problem loading or validating a nest member or
*** 4112,4117 ****
--- 4146,4169 ----
*/
@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 14
+ * @see MethodHandles.Lookup#defineHiddenClass
+ */
+ @HotSpotIntrinsicCandidate
+ public native boolean isHiddenClass();
+
}
< prev index next >