8278863: Add method ClassDesc::ofInternalName

Reviewed-by: jvernee
This commit is contained in:
Adam Sotona 2022-09-20 07:50:03 +00:00
parent 4020ed53dd
commit 0fa7d9e8cd
3 changed files with 61 additions and 0 deletions

View File

@ -72,12 +72,39 @@ public sealed interface ClassDesc
* @throws NullPointerException if the argument is {@code null}
* @throws IllegalArgumentException if the name string is not in the
* correct format
* @see ClassDesc#ofDescriptor(String)
* @see ClassDesc#ofInternalName(String)
*/
static ClassDesc of(String name) {
ConstantUtils.validateBinaryClassName(requireNonNull(name));
return ClassDesc.ofDescriptor("L" + binaryToInternal(name) + ";");
}
/**
* Returns a {@linkplain ClassDesc} for a class or interface type,
* given the name of the class or interface in internal form,
* such as {@code "java/lang/String"}.
*
* @apiNote
* To create a descriptor for an array type, either use {@link #ofDescriptor(String)}
* or {@link #arrayType()}; to create a descriptor for a primitive type, use
* {@link #ofDescriptor(String)} or use the predefined constants in
* {@link ConstantDescs}.
*
* @param name the fully qualified class name, in internal (slash-separated) form
* @return a {@linkplain ClassDesc} describing the desired class
* @throws NullPointerException if the argument is {@code null}
* @throws IllegalArgumentException if the name string is not in the
* correct format
* @jvms 4.2.1 Binary Class and Interface Names
* @see ClassDesc#of(String)
* @see ClassDesc#ofDescriptor(String)
*/
static ClassDesc ofInternalName(String name) {
ConstantUtils.validateInternalClassName(requireNonNull(name));
return ClassDesc.ofDescriptor("L" + name + ";");
}
/**
* Returns a {@linkplain ClassDesc} for a class or interface type,
* given a package name and the unqualified (simple) name for the
@ -125,6 +152,8 @@ public sealed interface ClassDesc
* correct format
* @jvms 4.3.2 Field Descriptors
* @jvms 4.4.1 The CONSTANT_Class_info Structure
* @see ClassDesc#of(String)
* @see ClassDesc#ofInternalName(String)
*/
static ClassDesc ofDescriptor(String descriptor) {
requireNonNull(descriptor);

View File

@ -58,6 +58,23 @@ class ConstantUtils {
return name;
}
/**
* Validates the correctness of an internal class name.
* In particular checks for the presence of invalid characters in the name.
*
* @param name the class name
* @return the class name passed if valid
* @throws IllegalArgumentException if the class name is invalid
*/
static String validateInternalClassName(String name) {
for (int i=0; i<name.length(); i++) {
char ch = name.charAt(i);
if (ch == ';' || ch == '[' || ch == '.')
throw new IllegalArgumentException("Invalid class name: " + name);
}
return name;
}
/**
* Validates a member name
*

View File

@ -133,6 +133,7 @@ public class ClassDescTest extends SymbolicDescTest {
public void testSimpleClassDesc() throws ReflectiveOperationException {
List<ClassDesc> stringClassDescs = Arrays.asList(ClassDesc.ofDescriptor("Ljava/lang/String;"),
ClassDesc.ofInternalName("java/lang/String"),
ClassDesc.of("java.lang", "String"),
ClassDesc.of("java.lang.String"),
ClassDesc.of("java.lang.String").arrayType().componentType(),
@ -149,6 +150,9 @@ public class ClassDescTest extends SymbolicDescTest {
testClassDesc(ClassDesc.of("java.lang.String").arrayType(), String[].class);
testClassDesc(ClassDesc.of("java.util.Map").nested("Entry"), Map.Entry.class);
assertEquals(ClassDesc.of("java.lang.String"), ClassDesc.ofDescriptor("Ljava/lang/String;"));
assertEquals(ClassDesc.of("java.lang.String"), ClassDesc.ofInternalName("java/lang/String"));
ClassDesc thisClassDesc = ClassDesc.ofDescriptor("LClassDescTest;");
assertEquals(thisClassDesc, ClassDesc.of("", "ClassDescTest"));
assertEquals(thisClassDesc, ClassDesc.of("ClassDescTest"));
@ -261,6 +265,17 @@ public class ClassDescTest extends SymbolicDescTest {
}
}
List<String> badInternalNames = List.of("I;", "[]", "[Ljava/lang/String;",
"Ljava.lang.String;", "java.lang.String");
for (String d : badInternalNames) {
try {
ClassDesc constant = ClassDesc.ofInternalName(d);
fail(d);
} catch (IllegalArgumentException e) {
// good
}
}
for (Primitives p : Primitives.values()) {
testBadNestedClasses(ClassDesc.ofDescriptor(p.descriptor), "any");
testBadNestedClasses(ClassDesc.ofDescriptor(p.descriptor), "any", "other");