1 /* 2 * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package jdk.internal.constant; 26 27 import java.lang.constant.ClassDesc; 28 import java.lang.invoke.MethodHandles; 29 30 import static jdk.internal.constant.ConstantUtils.*; 31 32 /** 33 * A <a href="package-summary.html#nominal">nominal descriptor</a> for a class, 34 * interface, or array type. A {@linkplain ReferenceClassDescImpl} corresponds to a 35 * {@code Constant_Class_info} entry in the constant pool of a classfile. 36 */ 37 public final class ReferenceClassDescImpl implements ClassDesc { 38 private final String descriptor; 39 40 private ReferenceClassDescImpl(String descriptor) { 41 this.descriptor = descriptor; 42 } 43 44 /** 45 * Creates a {@linkplain ClassDesc} from a descriptor string for a class or 46 * interface type or an array type. 47 * 48 * @param descriptor a field descriptor string for a class or interface type 49 * @throws IllegalArgumentException if the descriptor string is not a valid 50 * field descriptor string, or does not describe a class or interface type 51 * @jvms 4.3.2 Field Descriptors 52 */ 53 public static ReferenceClassDescImpl of(String descriptor) { 54 int dLen = descriptor.length(); 55 int len = ConstantUtils.skipOverFieldSignature(descriptor, 0, dLen, false); 56 if (len <= 1 || len != dLen) 57 throw new IllegalArgumentException(String.format("not a valid reference type descriptor: %s", descriptor)); 58 return new ReferenceClassDescImpl(descriptor); 59 } 60 61 /** 62 * Creates a {@linkplain ClassDesc} from a pre-validated descriptor string 63 * for a class or interface type or an array type. 64 * 65 * @param descriptor a field descriptor string for a class or interface type 66 * @jvms 4.3.2 Field Descriptors 67 */ 68 public static ReferenceClassDescImpl ofValidated(String descriptor) { 69 assert ConstantUtils.skipOverFieldSignature(descriptor, 0, descriptor.length(), false) 70 == descriptor.length() : descriptor; 71 return new ReferenceClassDescImpl(descriptor); 72 } 73 74 @Override 75 public String descriptorString() { 76 return descriptor; 77 } 78 79 @Override 80 public Class<?> resolveConstantDesc(MethodHandles.Lookup lookup) 81 throws ReflectiveOperationException { 82 if (isArray()) { 83 if (isPrimitiveArray()) { 84 return lookup.findClass(descriptor); 85 } 86 // Class.forName is slow on class or interface arrays 87 int depth = ConstantUtils.arrayDepth(descriptor); 88 Class<?> clazz = lookup.findClass(internalToBinary(descriptor.substring(depth + 1, descriptor.length() - 1))); 89 for (int i = 0; i < depth; i++) 90 clazz = clazz.arrayType(); 91 return clazz; 92 } 93 return lookup.findClass(internalToBinary(dropFirstAndLastChar(descriptor))); 94 } 95 96 /** 97 * Whether the descriptor is one of a primitive array, given this is 98 * already a valid reference type descriptor. 99 */ 100 private boolean isPrimitiveArray() { 101 // All L-type descriptors must end with a semicolon; same for reference 102 // arrays, leaving primitive arrays the only ones without a final semicolon 103 return descriptor.charAt(descriptor.length() - 1) != ';'; 104 } 105 106 /** 107 * Returns {@code true} if this {@linkplain ReferenceClassDescImpl} is 108 * equal to another {@linkplain ReferenceClassDescImpl}. Equality is 109 * determined by the two class descriptors having equal class descriptor 110 * strings. 111 * 112 * @param o the {@code ClassDesc} to compare to this 113 * {@code ClassDesc} 114 * @return {@code true} if the specified {@code ClassDesc} 115 * is equal to this {@code ClassDesc}. 116 */ 117 @Override 118 public boolean equals(Object o) { 119 if (this == o) return true; 120 if (o instanceof ReferenceClassDescImpl constant) { 121 return descriptor.equals(constant.descriptor); 122 } 123 return false; 124 } 125 126 @Override 127 public int hashCode() { 128 return descriptor.hashCode(); 129 } 130 131 @Override 132 public String toString() { 133 return String.format("ClassDesc[%s]", displayName()); 134 } 135 }