Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8310244

Clarify the name parameter to Class::forName

XMLWordPrintable

    • Icon: CSR CSR
    • Resolution: Approved
    • Icon: P4 P4
    • 21, 22
    • core-libs
    • None
    • minimal
    • The spec is updated to match the long-standing behavior.
    • Java API
    • SE

      Summary

      Clarify the specification of the name parameter of Class::forName to match the implementation.

      Problem

      The 1-arg and 3-arg Class::forName methods specify the name as a "fully qualified name" that does not match the long standing implementation. For a (non-hidden) class or interface, the name must be a binary name e.g. to find a nested type, the binary name is C$M but not C.M. For an array class, the name consists of one or more [, followed by:

      1. LN; where N is the binary name of the element type, or
      2. the type descriptor of a primitive type

      Solution

      Update the specification of Class::forName to match the long-standing behavior. The name must be a binary name to find a class or interface. Specify the format of the string to find an array class. Also add a note in the 2-arg Class::forName as it does not support loading of array types which is different than 1-arg and 3-arg Class::forName.

      Specification

      1. Update the @param className of Class.forName(String name)
      2. Update the javadoc of Class.forName(String name, boolean initialize, ClassLoader loader) about the name parameter
      3. Add an API note in the Class.forName(Module m, String cn) method that it does not allow class names for array types, unlike the 3-arg Class.forName
      4. Add an example of nested type in Class.getName

      Specdiff is attached.

      diff a/src/java.base/share/classes/java/lang/Class.java b/src/java.base/share/classes/java/lang/Class.java
      --- a/src/java.base/share/classes/java/lang/Class.java
      +++ b/src/java.base/share/classes/java/lang/Class.java
      @@ -375,11 +375,11 @@
            *
            * where {@code currentLoader} denotes the defining class loader of
            * the current class.
            *
            * <p> For example, the following code fragment returns the
      -     * runtime {@code Class} descriptor for the class named
      +     * runtime {@code Class} object for the class named
            * {@code java.lang.Thread}:
            *
            * {@snippet lang="java" :
            * Class<?> t = Class.forName("java.lang.Thread");
            * }
      @@ -390,13 +390,14 @@
            * <p>
            * In cases where this method is called from a context where there is no
            * caller frame on the stack (e.g. when called directly from a JNI
            * attached thread), the system class loader is used.
            *
      -     * @param      className   the fully qualified name of the desired class.
      -     * @return     the {@code Class} object for the class with the
      -     *             specified name.
      +     * @param     className the {@linkplain ClassLoader##binary-name binary name}
      +     *                      of the class or the string representing an array type
      +     * @return    the {@code Class} object for the class with the
      +     *            specified name.
            * @throws    LinkageError if the linkage fails
            * @throws    ExceptionInInitializerError if the initialization provoked
            *            by this method fails
            * @throws    ClassNotFoundException if the class cannot be located
            *
           /**
            * Returns the {@code Class} object associated with the class or
            * interface with the given string name, using the given class loader.
      -     * Given the fully qualified name for a class or interface (in the same
      -     * format returned by {@code getName}) this method attempts to
      -     * locate and load the class or interface.  The specified class
      -     * loader is used to load the class or interface.  If the parameter
      -     * {@code loader} is null, the class is loaded through the bootstrap
      +     * Given the {@linkplain ClassLoader##binary-name binary name} for a class or interface,
      +     * this method attempts to locate and load the class or interface. The specified
      +     * class loader is used to load the class or interface.  If the parameter
      +     * {@code loader} is {@code null}, the class is loaded through the bootstrap
            * class loader.  The class is initialized only if the
            * {@code initialize} parameter is {@code true} and if it has
            * not been initialized earlier.
            *
      -     * <p> If {@code name} denotes a primitive type or void, an attempt
      -     * will be made to locate a user-defined class in the unnamed package whose
      -     * name is {@code name}. Therefore, this method cannot be used to
      -     * obtain any of the {@code Class} objects representing primitive
      -     * types or void.
      +     * <p> This method cannot be used to obtain any of the {@code Class} objects
      +     * representing primitive types or void, hidden classes or interfaces,
      +     * or array classes whose element type is a hidden class or interface.
      +     * If {@code name} denotes a primitive type or void, for example {@code I},
      +     * an attempt will be made to locate a user-defined class in the unnamed package
      +     * whose name is {@code I} instead.
            *
      -     * <p> If {@code name} denotes an array class, the component type of
      -     * the array class is loaded but not initialized.
      -     *
      -     * <p> For example, in an instance method the expression:
      +     * <p> To obtain the {@code Class} object associated with an array class,
      +     * the name consists of one or more {@code '['} representing the depth
      +     * of the array nesting, followed by the element type as encoded in
      +     * {@linkplain ##nameFormat the table} specified in {@code Class.getName()}.
            *
      +     * <p> Examples:
            * {@snippet lang="java" :
      -     * Class.forName("Foo")
      +     * Class<?> threadClass = Class.forName("java.lang.Thread", false, currentLoader);
      +     * Class<?> stringArrayClass = Class.forName("[Ljava.lang.String;", false, currentLoader);
      +     * Class<?> intArrayClass = Class.forName("[[[I", false, currentLoader);
      +     * Class<?> nestedClass = Class.forName("java.lang.Character$UnicodeBlock", false, currentLoader);   // Class of int[][][]
      +     * Class<?> fooClass = Class.forName("Foo", true, currentLoader);
            * }
            *
      -     * is equivalent to:
      +     * <p> A call to {@code getName()} on the {@code Class} object returned
      +     * from {@code forName(}<i>N</i>{@code )} returns <i>N</i>.
            *
      -     * {@snippet lang="java" :
      -     * Class.forName("Foo", true, this.getClass().getClassLoader())
      -     * }
      +     * <p> A call to {@code forName("[L}<i>N</i>{@code ;")} causes the element type
      +     * named <i>N</i> to be loaded but not initialized regardless of the value
      +     * of the {@code initialize} parameter.
            *
      -     * Note that this method throws errors related to loading, linking
      -     * or initializing as specified in Sections {@jls 12.2}, {@jls
      -     * 12.3}, and {@jls 12.4} of <cite>The Java Language
      -     * Specification</cite>.
      -     * Note that this method does not check whether the requested class
      +     * @apiNote
      +     * This method throws errors related to loading, linking or initializing
      +     * as specified in Sections {@jls 12.2}, {@jls 12.3}, and {@jls 12.4} of
      +     * <cite>The Java Language Specification</cite>.
      +     * In addition, this method does not check whether the requested class
            * is accessible to its caller.
            *
      -     * @param name       fully qualified name of the desired class
      +     * @param name       the {@linkplain ClassLoader##binary-name binary name}
      +     *                   of the class or the string representing an array class
      +     *
            * @param initialize if {@code true} the class will be initialized
            *                   (which implies linking). See Section {@jls
            *                   12.4} of <cite>The Java Language
            *                   Specification</cite>.
            * @param loader     class loader from which the class must be loaded
      @@ -484,10 +492,11 @@
            * @see       java.lang.ClassLoader
            *
            * @jls 12.2 Loading of Classes and Interfaces
            * @jls 12.3 Linking of Classes and Interfaces
            * @jls 12.4 Initialization of Classes and Interfaces
      +     * @jls 13.1 The Form of a Binary
            * @since     1.2
            */
           @CallerSensitive
           public static Class<?> forName(String name, boolean initialize,
                                          ClassLoader loader)
            *
            * <p> This method does not check whether the requested class is
            * accessible to its caller. </p>
            *
            * @apiNote
      -     * This method returns {@code null} on failure rather than
      +     * This method does not support loading of array types, unlike
      +     * {@link #forName(String, boolean, ClassLoader)}. The class name must be
      +     * a binary name.  This method returns {@code null} on failure rather than
            * throwing a {@link ClassNotFoundException}, as is done by
            * the {@link #forName(String, boolean, ClassLoader)} method.
            * The security check is a stack-based permission check if the caller
            * loads a class in another module.
            *
      @@ -886,11 +897,11 @@
            * <p> 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 element
            * type as encoded using the following table:
            *
      -     * <blockquote><table class="striped">
      +     * <blockquote><table class="striped" id="nameFormat">
            * <caption style="display:none">Element types and encodings</caption>
            * <thead>
            * <tr><th scope="col"> Element Type <th scope="col"> Encoding
            * </thead>
            * <tbody style="text-align:left">
      @@ -913,10 +924,12 @@
            *
            * <p> Examples:
            * <blockquote><pre>
            * String.class.getName()
            *     returns "java.lang.String"
      +     * Character.UnicodeBlock.class.getName()
      +     *     returns "java.lang.Character$UnicodeBlock"
            * byte.class.getName()
            *     returns "byte"
            * (new Object[3]).getClass().getName()
            *     returns "[Ljava.lang.Object;"
      
      • (new int[3]
      [4][5][6][7][8][9]).getClass().getName()

            mchung Mandy Chung
            mchung Mandy Chung
            Alan Bateman, David Holmes
            Votes:
            0 Vote for this issue
            Watchers:
            5 Start watching this issue

              Created:
              Updated:
              Resolved: