mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 23:04:50 +02:00
8310242: Clarify the name parameter to Class::forName
Reviewed-by: rriggs, liach, alanb, dholmes
This commit is contained in:
parent
297c799631
commit
7db2f08756
2 changed files with 138 additions and 32 deletions
|
@ -377,7 +377,7 @@ public final class Class<T> implements java.io.Serializable,
|
||||||
* the current class.
|
* the current class.
|
||||||
*
|
*
|
||||||
* <p> For example, the following code fragment returns the
|
* <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}:
|
* {@code java.lang.Thread}:
|
||||||
*
|
*
|
||||||
* {@snippet lang="java" :
|
* {@snippet lang="java" :
|
||||||
|
@ -392,9 +392,10 @@ public final class Class<T> implements java.io.Serializable,
|
||||||
* caller frame on the stack (e.g. when called directly from a JNI
|
* caller frame on the stack (e.g. when called directly from a JNI
|
||||||
* attached thread), the system class loader is used.
|
* attached thread), the system class loader is used.
|
||||||
*
|
*
|
||||||
* @param className the fully qualified name of the desired class.
|
* @param className the {@linkplain ClassLoader##binary-name binary name}
|
||||||
* @return the {@code Class} object for the class with the
|
* of the class or the string representing an array type
|
||||||
* specified name.
|
* @return the {@code Class} object for the class with the
|
||||||
|
* specified name.
|
||||||
* @throws LinkageError if the linkage fails
|
* @throws LinkageError if the linkage fails
|
||||||
* @throws ExceptionInInitializerError if the initialization provoked
|
* @throws ExceptionInInitializerError if the initialization provoked
|
||||||
* by this method fails
|
* by this method fails
|
||||||
|
@ -423,45 +424,52 @@ public final class Class<T> implements java.io.Serializable,
|
||||||
/**
|
/**
|
||||||
* Returns the {@code Class} object associated with the class or
|
* Returns the {@code Class} object associated with the class or
|
||||||
* interface with the given string name, using the given class loader.
|
* interface with the given string name, using the given class loader.
|
||||||
* Given the fully qualified name for a class or interface (in the same
|
* Given the {@linkplain ClassLoader##binary-name binary name} for a class or interface,
|
||||||
* format returned by {@code getName}) this method attempts to
|
* this method attempts to locate and load the class or interface. The specified
|
||||||
* locate and load the class or interface. The specified class
|
* class loader is used to load the class or interface. If the parameter
|
||||||
* loader is used to load the class or interface. If the parameter
|
* {@code loader} is {@code null}, the class is loaded through the bootstrap
|
||||||
* {@code loader} is null, the class is loaded through the bootstrap
|
|
||||||
* class loader. The class is initialized only if the
|
* class loader. The class is initialized only if the
|
||||||
* {@code initialize} parameter is {@code true} and if it has
|
* {@code initialize} parameter is {@code true} and if it has
|
||||||
* not been initialized earlier.
|
* not been initialized earlier.
|
||||||
*
|
*
|
||||||
* <p> If {@code name} denotes a primitive type or void, an attempt
|
* <p> This method cannot be used to obtain any of the {@code Class} objects
|
||||||
* will be made to locate a user-defined class in the unnamed package whose
|
* representing primitive types or void, hidden classes or interfaces,
|
||||||
* name is {@code name}. Therefore, this method cannot be used to
|
* or array classes whose element type is a hidden class or interface.
|
||||||
* obtain any of the {@code Class} objects representing primitive
|
* If {@code name} denotes a primitive type or void, for example {@code I},
|
||||||
* types or void.
|
* 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
|
* <p> To obtain the {@code Class} object associated with an array class,
|
||||||
* the array class is loaded but not initialized.
|
* the name consists of one or more {@code '['} representing the depth
|
||||||
*
|
* of the array nesting, followed by the element type as encoded in
|
||||||
* <p> For example, in an instance method the expression:
|
* {@linkplain ##nameFormat the table} specified in {@code Class.getName()}.
|
||||||
*
|
*
|
||||||
|
* <p> Examples:
|
||||||
* {@snippet lang="java" :
|
* {@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 of int[][][]
|
||||||
|
* Class<?> nestedClass = Class.forName("java.lang.Character$UnicodeBlock", false, currentLoader);
|
||||||
|
* 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" :
|
* <p> A call to {@code forName("[L}<i>N</i>{@code ;")} causes the element type
|
||||||
* Class.forName("Foo", true, this.getClass().getClassLoader())
|
* 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
|
* @apiNote
|
||||||
* or initializing as specified in Sections {@jls 12.2}, {@jls
|
* This method throws errors related to loading, linking or initializing
|
||||||
* 12.3}, and {@jls 12.4} of <cite>The Java Language
|
* as specified in Sections {@jls 12.2}, {@jls 12.3}, and {@jls 12.4} of
|
||||||
* Specification</cite>.
|
* <cite>The Java Language Specification</cite>.
|
||||||
* Note that this method does not check whether the requested class
|
* In addition, this method does not check whether the requested class
|
||||||
* is accessible to its caller.
|
* 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
|
* @param initialize if {@code true} the class will be initialized
|
||||||
* (which implies linking). See Section {@jls
|
* (which implies linking). See Section {@jls
|
||||||
* 12.4} of <cite>The Java Language
|
* 12.4} of <cite>The Java Language
|
||||||
|
@ -486,6 +494,7 @@ public final class Class<T> implements java.io.Serializable,
|
||||||
* @jls 12.2 Loading of Classes and Interfaces
|
* @jls 12.2 Loading of Classes and Interfaces
|
||||||
* @jls 12.3 Linking of Classes and Interfaces
|
* @jls 12.3 Linking of Classes and Interfaces
|
||||||
* @jls 12.4 Initialization of Classes and Interfaces
|
* @jls 12.4 Initialization of Classes and Interfaces
|
||||||
|
* @jls 13.1 The Form of a Binary
|
||||||
* @since 1.2
|
* @since 1.2
|
||||||
*/
|
*/
|
||||||
@CallerSensitive
|
@CallerSensitive
|
||||||
|
@ -548,7 +557,9 @@ public final class Class<T> implements java.io.Serializable,
|
||||||
* accessible to its caller. </p>
|
* accessible to its caller. </p>
|
||||||
*
|
*
|
||||||
* @apiNote
|
* @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
|
* throwing a {@link ClassNotFoundException}, as is done by
|
||||||
* the {@link #forName(String, boolean, ClassLoader)} method.
|
* the {@link #forName(String, boolean, ClassLoader)} method.
|
||||||
* The security check is a stack-based permission check if the caller
|
* The security check is a stack-based permission check if the caller
|
||||||
|
@ -898,7 +909,7 @@ public final class Class<T> implements java.io.Serializable,
|
||||||
* representing the depth of the array nesting, followed by the element
|
* representing the depth of the array nesting, followed by the element
|
||||||
* type as encoded using the following table:
|
* 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>
|
* <caption style="display:none">Element types and encodings</caption>
|
||||||
* <thead>
|
* <thead>
|
||||||
* <tr><th scope="col"> Element Type <th scope="col"> Encoding
|
* <tr><th scope="col"> Element Type <th scope="col"> Encoding
|
||||||
|
@ -925,6 +936,8 @@ public final class Class<T> implements java.io.Serializable,
|
||||||
* <blockquote><pre>
|
* <blockquote><pre>
|
||||||
* String.class.getName()
|
* String.class.getName()
|
||||||
* returns "java.lang.String"
|
* returns "java.lang.String"
|
||||||
|
* Character.UnicodeBlock.class.getName()
|
||||||
|
* returns "java.lang.Character$UnicodeBlock"
|
||||||
* byte.class.getName()
|
* byte.class.getName()
|
||||||
* returns "byte"
|
* returns "byte"
|
||||||
* (new Object[3]).getClass().getName()
|
* (new Object[3]).getClass().getName()
|
||||||
|
|
93
test/jdk/java/lang/Class/forName/ForNameNames.java
Normal file
93
test/jdk/java/lang/Class/forName/ForNameNames.java
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
* @bug 8310242
|
||||||
|
* @run junit ForNameNames
|
||||||
|
* @summary Verify class names for Class.forName
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
|
import org.junit.jupiter.params.provider.Arguments;
|
||||||
|
import org.junit.jupiter.params.provider.MethodSource;
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
public class ForNameNames {
|
||||||
|
static class Inner {}
|
||||||
|
static Stream<Arguments> testCases() {
|
||||||
|
return Stream.of(
|
||||||
|
Arguments.of("java.lang.String", String.class),
|
||||||
|
Arguments.of("[Ljava.lang.String;", String[].class),
|
||||||
|
Arguments.of("ForNameNames$Inner", Inner.class),
|
||||||
|
Arguments.of("[LForNameNames$Inner;", Inner.class),
|
||||||
|
Arguments.of("[[I", int[][].class)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test 1-arg and 3-arg Class::forName. Class::getName on the returned
|
||||||
|
* Class object returns the name passed to Class::forName.
|
||||||
|
*/
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("testCases")
|
||||||
|
void testForName(String cn, Class<?> expected) throws ClassNotFoundException {
|
||||||
|
ClassLoader loader = ForNameNames.class.getClassLoader();
|
||||||
|
Class<?> c1 = Class.forName(cn, false, loader);
|
||||||
|
assertEquals(expected, c1);
|
||||||
|
assertEquals(cn, c1.getName());
|
||||||
|
|
||||||
|
Class<?> c2 = Class.forName(cn);
|
||||||
|
assertEquals(expected, c2);
|
||||||
|
assertEquals(cn, c2.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
static Stream<Arguments> invalidNames() {
|
||||||
|
return Stream.of(
|
||||||
|
Arguments.of("I"), // primitive type
|
||||||
|
Arguments.of("int[]"), // fully-qualified name of int array
|
||||||
|
Arguments.of("ForNameNames.Inner"), // fully-qualified name of nested type
|
||||||
|
Arguments.of("[java.lang.String"), // missing L and ;
|
||||||
|
Arguments.of("[Ljava.lang.String"), // missing ;
|
||||||
|
Arguments.of("[Ljava/lang/String;") // type descriptor
|
||||||
|
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("invalidNames")
|
||||||
|
void testInvalidNames(String cn) {
|
||||||
|
ClassLoader loader = ForNameNames.class.getClassLoader();
|
||||||
|
assertThrows(ClassNotFoundException.class, () -> Class.forName(cn, false, loader));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testModule() {
|
||||||
|
// Class.forName(Module, String) does not allow class name for array types
|
||||||
|
Class<?> c = Class.forName(Object.class.getModule(), "[Ljava.lang.String;");
|
||||||
|
assertNull(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue