Skip to content

Commit

Permalink
8278863: Add method ClassDesc::ofInternalName
Browse files Browse the repository at this point in the history
Reviewed-by: jvernee
  • Loading branch information
asotona committed Sep 20, 2022
1 parent 4020ed5 commit 0fa7d9e
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 0 deletions.
29 changes: 29 additions & 0 deletions src/java.base/share/classes/java/lang/constant/ClassDesc.java
Expand Up @@ -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
Expand Down Expand Up @@ -125,6 +152,8 @@ static ClassDesc of(String packageName, String className) {
* 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);
Expand Down
17 changes: 17 additions & 0 deletions src/java.base/share/classes/java/lang/constant/ConstantUtils.java
Expand Up @@ -58,6 +58,23 @@ static String validateBinaryClassName(String name) {
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
*
Expand Down
15 changes: 15 additions & 0 deletions test/jdk/java/lang/constant/ClassDescTest.java
Expand Up @@ -133,6 +133,7 @@ public void testPrimitiveClassDesc() throws ReflectiveOperationException {
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(),
Expand All @@ -149,6 +150,9 @@ public void testSimpleClassDesc() throws ReflectiveOperationException {
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"));
Expand Down Expand Up @@ -261,6 +265,17 @@ public void testBadClassDescs() {
}
}

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");
Expand Down

0 comments on commit 0fa7d9e

Please sign in to comment.