8310242: Clarify the name parameter to Class::forName
Reviewed-by: rriggs, liach, alanb, dholmes
This commit is contained in:
parent
297c799631
commit
7db2f08756
@ -377,7 +377,7 @@ public final class Class<T> implements java.io.Serializable,
|
||||
* 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" :
|
||||
@ -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
|
||||
* 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
|
||||
@ -423,45 +424,52 @@ public final class Class<T> implements java.io.Serializable,
|
||||
/**
|
||||
* 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 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" :
|
||||
* 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
|
||||
@ -486,6 +494,7 @@ public final class Class<T> implements java.io.Serializable,
|
||||
* @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
|
||||
@ -548,7 +557,9 @@ public final class Class<T> implements java.io.Serializable,
|
||||
* 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
|
||||
@ -898,7 +909,7 @@ public final class Class<T> implements java.io.Serializable,
|
||||
* 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
|
||||
@ -925,6 +936,8 @@ public final class Class<T> implements java.io.Serializable,
|
||||
* <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()
|
||||
|
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…
x
Reference in New Issue
Block a user