-
CSR
-
Resolution: Approved
-
P3
-
None
-
behavioral
-
low
-
-
Java API, add/remove/modify command line option
Summary
Two variants of the Class.forName()
method:
Class.forName(String,boolean,ClassLoader)
(usingfalse
forinitialize
)Class.forName(Module,String)
are specified to locate, load, and link a Class, but may return classes that have not been linked.
Problem
The 3-arg Class.forName(String,boolean,ClassLoader)
has a boolean argument to specify whether or not to initialize the loaded class. If true, the class is linked, and then initialized. If false, the Class should still be linked, per the spec ("this method attempts to locate, load, and link the class or interface"). But as it is, the Class does not get linked until it is used.
This is not a problem for most usages, but can be for debugging/servicability/etc. (JDK-8181144, for example - a class loaded and unused in this way will not show up in VirtualMachine.allClasses()
.)
Conforming to the spec and linking classes in Class.forName() would change long-standing behavior. Various LinkageError
subtypes can be thrown at class link time. Linking during Class.forName() could change such exceptions to be thrown earlier. Consider a Class loaded (and not initialized) by forName(), but never used. There could be latent linkage errors which have never been encountered. With this change in behavior, LinkageError would now be thrown from Class.forName().
Solution
The behavior of the following methods will be updated to conform to the spec, linking the class before returning:
Class.forName(String,boolean,ClassLoader)
(wheninitialize
isfalse
)Class.forName(Module,String)
MethodHandles.Lookup.findClass(String)
Lookup.findClass() and the 2-arg Class.forName() were added in JDK 9, so they're unlikely to be widely used.
The 3-arg Class.forName() is already specified to throw LinkageError (all 3 above methods are), so developers should expect that it could occur. However such checking is not required by the language (unchecked Error). A -XX:+ClassForNameDeferLinking
flag will be added to restore the previous behavior.
The spec for MethodHandles.Lookup.findClass(String) will be updated to mention that it loads and links the class.
An alternative solution that was considered would be to leave the implementation as is, update the spec to match the current behavior of not linking the class, and add a new, 4-arg Class.forName() variant with two boolean arguments - one to request linking (or not), and one to request initialization (or not).
Changing the behavior is preferred to adding a likely rarely-used method, given that the compatibility risk is believed to be manageable.
Specification
java.lang.invoke.MethodHandles.Lookup
in src/java.base/share/classes/java/lang/invoke/MethodHandles.java:
@@ -1927,12 +1927,17 @@
/**
- * Looks up a class by name from the lookup context defined by this {@code Lookup} object. The static
+ * 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
* 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}. In particular, the method first attempts to
- * load the requested class, and then determines whether the class is accessible to this lookup object.
+ * 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>.
*
@@ -1944,6 +1949,9 @@
+ *
+ * @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
java.lang.Class
in src/java.base/share/classes/java/lang/Class.java:
@@ -390,10 +390,14 @@
+ *
+ * @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)
...
@@ -436,10 +440,14 @@
* accessible to its caller. </p>
*
+ * <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>.
+ *
* @apiNote
* This method returns {@code null} on failure rather than
@@ -463,10 +471,12 @@
* in a module.</li>
* </ul>
*
+ * @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)
A new JDK-specific VM product flag is added for backward compatibility:
Setting -XX:+ClassForNameDeferLinking
will restore the previous behavior, where a class is not necessarily linked by Class.forName()
, but when the class is first used.
- csr of
-
JDK-8212117 Class.forName may return a reference to a loaded but not linked Class
-
- Resolved
-
- relates to
-
JDK-8233260 Class.forName should be able to load, but not link, a class
-
- Closed
-