--- old/src/java.base/share/classes/java/lang/Class.java 2020-04-15 11:02:22.000000000 -0700
+++ new/src/java.base/share/classes/java/lang/Class.java 2020-04-15 11:02:22.000000000 -0700
@@ -163,10 +163,18 @@
*
* The {@linkplain #getName() name of a hidden class or interface} is
* not a binary name,
- * which means that a hidden class or interface cannot be
- * referenced by the constant pools of other classes and interfaces,
- * and cannot be discovered by {@link #forName Class::forName} or
- * {@link ClassLoader#loadClass(String, boolean) ClassLoader::loadClass}.
+ * which means the following:
+ *
+ * - A hidden class or interface cannot be referenced by the constant pools
+ * of other classes and interfaces.
+ *
- A hidden class or interface cannot be described in
+ * {@linkplain java.lang.constant.ConstantDesc nominal form} by
+ * {@link #describeConstable() Class::describeConstable},
+ * {@link ClassDesc#of(String) ClassDesc::of}, or
+ * {@link ClassDesc#ofDescriptor(String) ClassDesc::ofDescriptor}.
+ *
- A hidden class or interface cannot be discovered by {@link #forName Class::forName}
+ * or {@link ClassLoader#loadClass(String, boolean) ClassLoader::loadClass}.
+ *
*
* A hidden class or interface is never an array class, but may be
* the element type of an array. In all other respects, the fact that
@@ -1065,10 +1073,7 @@
public String getPackageName() {
String pn = this.packageName;
if (pn == null) {
- Class> c = this;
- while (c.isArray()) {
- c = c.getComponentType();
- }
+ Class> c = isArray() ? elementType() : this;
if (c.isPrimitive()) {
pn = "java.lang";
} else {
@@ -1226,6 +1231,20 @@
private final Class> componentType;
+ /*
+ * Returns the {@code Class} representing the element type of an array class.
+ * If this class does not represent an array class, then this method returns
+ * {@code null}.
+ */
+ private Class> elementType() {
+ if (!isArray()) return null;
+
+ Class> c = this;
+ while (c.isArray()) {
+ c = c.getComponentType();
+ }
+ return c;
+ }
/**
* Returns the Java language modifiers for this class or interface, encoded
@@ -3023,10 +3042,7 @@
*/
private String resolveName(String name) {
if (!name.startsWith("/")) {
- Class> c = this;
- while (c.isArray()) {
- c = c.getComponentType();
- }
+ Class> c = isArray() ? elementType() : this;
String baseName = c.getPackageName();
if (baseName != null && !baseName.isEmpty()) {
name = baseName.replace('.', '/') + "/" + name;
@@ -4241,13 +4257,57 @@
}
/**
- * Returns the type descriptor string for this class.
- *
- * Note that this is not a strict inverse of {@link #forName};
+ * Returns the descriptor string of the entity (class, interface, array class,
+ * primitive type, or {@code void}) represented by this {@code Class} object.
+ *
+ *
If this {@code Class} object represents a class or interface,
+ * not an array class, then:
+ *
+ * - If the class or interface is not {@linkplain Class#isHidden() hidden},
+ * then the result is a field descriptor (JVMS {@jvms 4.3.2})
+ * for the class or interface. Calling
+ * {@link ClassDesc#ofDescriptor(String) ClassDesc::ofDescriptor}
+ * with the result descriptor string produces a {@link ClassDesc ClassDesc}
+ * describing this class or interface.
+ *
- If the class or interface is {@linkplain Class#isHidden() hidden},
+ * then the result is a string of the form:
+ *
+ * {@code "L" +} N {@code + "." + + ";"}
+ *
+ * where N is the binary name
+ * encoded in internal form indicated by the {@code class} file passed to
+ * {@link MethodHandles.Lookup#defineHiddenClass(byte[], boolean, MethodHandles.Lookup.ClassOption...)
+ * Lookup::defineHiddenClass}, and {@code } is an unqualified name.
+ * A hidden class or interface has no {@linkplain ClassDesc nominal descriptor}.
+ * The result string is not a type descriptor.
+ *
+ *
+ * If this {@code Class} object represents an array class, then
+ * the result is a string consisting of one or more '{@code [}' characters
+ * representing the depth of the array nesting, followed by the
+ * descriptor string of the element type.
+ *
+ * - If the element type is not a {@linkplain Class#isHidden() hidden} class
+ * or interface, then this array class can be described nominally.
+ * Calling {@link ClassDesc#ofDescriptor(String) ClassDesc::ofDescriptor}
+ * with the result descriptor string produces a {@link ClassDesc ClassDesc}
+ * describing this array class.
+ *
- If the element type is a {@linkplain Class#isHidden() hidden} class or
+ * interface, then this array class cannot be described nominally.
+ * The result string is not a type descriptor.
+ *
+ *
+ * If this {@code Class} object represents a primitive type or
+ * {@code void}, then the result is a field descriptor string which
+ * is a one-letter code corresponding to a primitive type or {@code void}
+ * ({@code "B", "C", "D", "F", "I", "J", "S", "Z", "V"}) (JVMS {@jvms 4.3.2}).
+ *
+ * @apiNote
+ * This is not a strict inverse of {@link #forName};
* distinct classes which share a common name but have different class loaders
* will have identical descriptor strings.
*
- * @return the type descriptor representation
+ * @return the descriptor string for this {@code Class} object
* @jvms 4.3.2 Field Descriptors
* @since 12
*/
@@ -4255,10 +4315,15 @@
public String descriptorString() {
if (isPrimitive())
return Wrapper.forPrimitiveType(this).basicTypeString();
- else if (isArray()) {
+
+ if (isArray()) {
return "[" + componentType.descriptorString();
- }
- else {
+ } else if (isHidden()) {
+ String name = getName();
+ int index = name.indexOf('/');
+ return "L" + name.substring(0, index).replace('.', '/')
+ + "." + name.substring(index+1) + ";";
+ } else {
return "L" + getName().replace('.', '/') + ";";
}
}
@@ -4301,7 +4366,9 @@
*/
@Override
public Optional describeConstable() {
- return Optional.of(ClassDesc.ofDescriptor(descriptorString()));
+ Class> c = isArray() ? elementType() : this;
+ return c.isHidden() ? Optional.empty()
+ : Optional.of(ClassDesc.ofDescriptor(descriptorString()));
}
/**