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

Class.forName should be able to load, but not link, a class

    Details

    • Type: CSR
    • Status: Closed
    • Priority: P3
    • Resolution: Approved
    • Fix Version/s: 14
    • Component/s: core-libs
    • Labels:
      None
    • Subcomponent:
    • Compatibility Kind:
      behavioral
    • Compatibility Risk:
      minimal
    • Compatibility Risk Description:
      The change being reverted has only been in JDK 14 for a few builds.
    • Interface Kind:
      Java API, add/remove/modify command line option
    • Scope:
      SE

      Description

      Summary

      The spec changes made in CSR JDK-8222071 should be reverted.

      Problem

      The specification of the three-arg method Class::forName(String, boolean, ClassLoader) always stated that the method "attempts to locate, load, and link the class or interface [named by the specified String, using the specified class loader to load the class or interface]." The idea that linkage always happens is supported by the presence of "Throws: LinkageError - if the linkage fails" in the method's specification; there is no qualification or conditioning on the requirement for linkage. Whether the linked class or interface is subsequently initialized -- a process distinct from linking -- is specified to be under the control of the boolean argument.

      Unfortunately, the implementation of the three-arg method in the JDK never followed the specification. The implementation linked the loaded class or interface only if the boolean was true, just prior to initializing the class or interface. The implementation did not link the loaded class or interface if the boolean was false.

      JDK-8212117 changed the long-standing implementation to match the specification, so that on JDK 14, the three-arg method would always link the loaded class or interface whether the boolean is true or false. This implementation change was not expected to have widespread effects. It was anticipated that some code in the wild would be using the three-arg method (with the boolean false) to load a class but do nothing with it until much later; on JDK 13, the three-arg method would not throw LinkageError because the class was not linked, but on JDK 14, the three-arg method would throw LinkageError if the class is malformed in certain ways, and it was hoped that code would catch this.

      Within a few promoted builds of this change, problems were reported on Early Access releases of JDK 14, e.g., JDK-8231924 - "Field::getGenericType triggers loading and linking that may fail with LinkageError". As a practical matter, the developers of popular Java libraries which perform introspection on user classes have never seen and thus do not expect LinkageError from the three-arg method at run time (and they are not obligated to catch it at compile time). An unexpected error of this sort can be time-consuming to debug, even though the stack trace is clear about what happened. It is easy to imagine additional problems being uncovered if more programs are tried on JDK 14.

      Solution

      The JDK-8212117 changes will be backed out, restoring the longstanding behavior, and the spec restored to its state prior to CSR JDK-8222071.

      The Class::forName spec will be updated to match the long-standing behavior in a separate issue JDK-8233272.

      Specification

      The JDK-specific compatibility flag, -XX:+ClassForNameDeferLinking, will be removed.

      src/java.base/share/classes/java/lang/invoke/MethodHandles.java

      @@ -1925,21 +1925,16 @@
      
               /**
      -         * Looks up a class by name from the lookup context defined by this {@code Lookup} object.
      -         * This method attempts to locate, load, and link the class, and then determines whether
      -         * the class is accessible to this {@code Lookup} object.  The static
      +         * Looks up a class by name from the lookup context defined by this {@code Lookup} object. The static
                * initializer of the class is not run.
                * <p>
                * The lookup context here is determined by the {@linkplain #lookupClass() lookup class}, its class
      -         * loader, and the {@linkplain #lookupModes() lookup modes}.
      -         * <p>
      -         * Note that this method throws errors related to loading and linking as
      -         * specified in Sections 12.2 and 12.3 of <em>The Java Language
      -         * Specification</em>.
      +         * loader, and the {@linkplain #lookupModes() lookup modes}. In particular, the method first attempts to
      +         * load the requested class, and then determines whether the class is accessible to this lookup object.
                *
      
      @@ -1947,13 +1942,10 @@
      -         *
      -         * @jls 12.2 Loading of Classes and Interfaces
      -         * @jls 12.3 Linking of Classes and Interfaces
                * @since 9
                */
               public Class<?> findClass(String targetName) throws ClassNotFoundException, IllegalAccessException {

      src/java.base/share/classes/java/lang/Class.java

      @@ -390,14 +390,10 @@
      -     *
      -     * @jls 12.2 Loading of Classes and Interfaces
      -     * @jls 12.3 Linking of Classes and Interfaces
      -     * @jls 12.4 Initialization of Classes and Interfaces
            * @since     1.2
            */
           @CallerSensitive
           public static Class<?> forName(String name, boolean initialize,
                                          ClassLoader loader)
      
      @@ -440,14 +436,10 @@
            *
      -     * <p> Note that this method throws errors related to loading and linking as
      -     * specified in Sections 12.2 and 12.3 of <em>The Java Language
      -     * Specification</em>.
      -     *
      
      @@ -471,12 +463,10 @@
            *
      -     * @jls 12.2 Loading of Classes and Interfaces
      -     * @jls 12.3 Linking of Classes and Interfaces
            * @since 9
            * @spec JPMS
            */
           @CallerSensitive
           public static Class<?> forName(Module module, String name)

        Attachments

          Issue Links

            Activity

              People

              • Assignee:
                bchristi Brent Christian
                Reporter:
                bchristi Brent Christian
                Reviewed By:
                Alan Bateman, David Holmes, Mandy Chung
              • Votes:
                0 Vote for this issue
                Watchers:
                1 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved: