1 /* 2 * Copyright (c) 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 26 package java.lang.reflect.code.type; 27 28 import java.lang.constant.ClassDesc; 29 import java.lang.constant.ConstantDescs; 30 import java.lang.invoke.MethodHandles; 31 import java.lang.invoke.MethodHandles.Lookup; 32 import java.lang.reflect.Executable; 33 import java.lang.reflect.GenericArrayType; 34 import java.lang.reflect.GenericDeclaration; 35 import java.lang.reflect.ParameterizedType; 36 import java.lang.reflect.Type; 37 import java.lang.reflect.TypeVariable; 38 import java.lang.reflect.code.TypeElement; 39 import java.lang.reflect.code.type.WildcardType.BoundKind; 40 import java.util.List; 41 import java.util.Objects; 42 import java.util.stream.Stream; 43 44 /** 45 * The symbolic description of a Java type. Java types can be classified as follows: 46 * <ul> 47 * <li>{@linkplain PrimitiveType primitive types}, e.g. {@code int}, {@code void}</li> 48 * <li>{@linkplain ClassType class types}, e.g. {@code String}, {@code List<? extends Number>}</li> 49 * <li>{@linkplain ArrayType array types}, e.g. {@code Object[][]}, {@code List<Runnable>[]}</li> 50 * <li>{@linkplain WildcardType wildcard types}, e.g. {@code ? extends Number}, {@code ? super ArrayList<String>}</li> 51 * <li>{@linkplain TypeVarRef type-variables}, e.g. {@code T extends Runnable}</li> 52 * </ul> 53 * Java types can be constructed from either {@linkplain ClassDesc nominal descriptors} or 54 * {@linkplain Type reflective type mirrors}. Conversely, Java types can be 55 * {@linkplain #toNominalDescriptor() turned} into nominal descriptors, 56 * or be {@linkplain #resolve(Lookup) resolved} into reflective type mirrors. 57 * @sealedGraph 58 */ 59 public sealed interface JavaType extends TypeElement permits ClassType, ArrayType, 60 PrimitiveType, WildcardType, TypeVarRef { 61 62 /** {@link JavaType} representing {@code void} */ 63 PrimitiveType VOID = new PrimitiveType(ConstantDescs.CD_void); 64 65 /** {@link JavaType} representing {@code boolean} */ 66 PrimitiveType BOOLEAN = new PrimitiveType(ConstantDescs.CD_boolean); 67 68 /** {@link JavaType} representing {@link Boolean} */ 69 ClassType J_L_BOOLEAN = new ClassType(ConstantDescs.CD_Boolean); 70 71 /** {@link JavaType} representing {@code boolean[]} */ 72 ArrayType BOOLEAN_ARRAY = new ArrayType(BOOLEAN); 73 74 /** {@link JavaType} representing {@code byte} */ 75 PrimitiveType BYTE = new PrimitiveType(ConstantDescs.CD_byte); 76 77 /** {@link JavaType} representing {@link Byte} */ 78 ClassType J_L_BYTE = new ClassType(ConstantDescs.CD_Byte); 79 80 /** {@link JavaType} representing {@code byte[]} */ 81 ArrayType BYTE_ARRAY = new ArrayType(BYTE); 82 83 /** {@link JavaType} representing {@code char} */ 84 PrimitiveType CHAR = new PrimitiveType(ConstantDescs.CD_char); 85 86 /** {@link JavaType} representing {@link Character} */ 87 ClassType J_L_CHARACTER = new ClassType(ConstantDescs.CD_Character); 88 89 /** {@link JavaType} representing {@code char[]} */ 90 ArrayType CHAR_ARRAY = new ArrayType(CHAR); 91 92 /** {@link JavaType} representing {@code short} */ 93 PrimitiveType SHORT = new PrimitiveType(ConstantDescs.CD_short); 94 95 /** {@link JavaType} representing {@link Short} */ 96 ClassType J_L_SHORT = new ClassType(ConstantDescs.CD_Short); 97 98 /** {@link JavaType} representing {@code short[]} */ 99 ArrayType SHORT_ARRAY = new ArrayType(SHORT); 100 101 /** {@link JavaType} representing {@code int} */ 102 PrimitiveType INT = new PrimitiveType(ConstantDescs.CD_int); 103 104 /** {@link JavaType} representing {@link Integer} */ 105 ClassType J_L_INTEGER = new ClassType(ConstantDescs.CD_Integer); 106 107 /** {@link JavaType} representing {@code int[]} */ 108 ArrayType INT_ARRAY = new ArrayType(INT); 109 110 /** {@link JavaType} representing {@code long} */ 111 PrimitiveType LONG = new PrimitiveType(ConstantDescs.CD_long); 112 113 /** {@link JavaType} representing {@link Long} */ 114 ClassType J_L_LONG = new ClassType(ConstantDescs.CD_Long); 115 116 /** {@link JavaType} representing {@code long[]} */ 117 ArrayType LONG_ARRAY = new ArrayType(LONG); 118 119 /** {@link JavaType} representing {@code float} */ 120 PrimitiveType FLOAT = new PrimitiveType(ConstantDescs.CD_float); 121 122 /** {@link JavaType} representing {@link Float} */ 123 ClassType J_L_FLOAT = new ClassType(ConstantDescs.CD_Float); 124 125 /** {@link JavaType} representing {@code float[]} */ 126 ArrayType FLOAT_ARRAY = new ArrayType(FLOAT); 127 128 /** {@link JavaType} representing {@code double} */ 129 PrimitiveType DOUBLE = new PrimitiveType(ConstantDescs.CD_double); 130 131 /** {@link JavaType} representing {@link Double} */ 132 ClassType J_L_DOUBLE = new ClassType(ConstantDescs.CD_Double); 133 134 /** {@link JavaType} representing {@code double[]} */ 135 ArrayType DOUBLE_ARRAY = new ArrayType(DOUBLE); 136 137 /** {@link JavaType} representing {@link Object} */ 138 ClassType J_L_OBJECT = new ClassType(ConstantDescs.CD_Object); 139 140 /** {@link JavaType} representing {@link Object[]} */ 141 ArrayType J_L_OBJECT_ARRAY = new ArrayType(J_L_OBJECT); 142 143 /** {@link JavaType} representing {@link Class} */ 144 ClassType J_L_CLASS = new ClassType(ConstantDescs.CD_Class); 145 146 /** {@link JavaType} representing {@link String} */ 147 ClassType J_L_STRING = new ClassType(ConstantDescs.CD_String); 148 149 /** {@link JavaType} representing {@link List} */ 150 ClassType J_U_LIST = new ClassType(ConstantDescs.CD_List); 151 152 // Conversions 153 154 /** 155 * {@return the basic type associated with this Java type}. A basic type is one of the following 156 * types: 157 * <ul> 158 * <li>{@link JavaType#VOID}</li> 159 * <li>{@link JavaType#INT}</li> 160 * <li>{@link JavaType#LONG}</li> 161 * <li>{@link JavaType#FLOAT}</li> 162 * <li>{@link JavaType#DOUBLE}</li> 163 * <li>{@link JavaType#J_L_OBJECT}</li> 164 * </ul> 165 * 166 */ 167 JavaType toBasicType(); 168 169 /** 170 * {@return the nominal descriptor associated with this Java type} 171 */ 172 ClassDesc toNominalDescriptor(); 173 174 /** 175 * Resolve this Java type to a reflective type mirror. 176 * @param lookup the lookup used to create the reflective type mirror 177 * @return a reflective type mirror for this type 178 * @throws ReflectiveOperationException if this Java type cannot be resolved 179 */ 180 Type resolve(MethodHandles.Lookup lookup) throws ReflectiveOperationException; 181 182 /** 183 * {@return the erasure of this Java type, as per JLS 4.6} 184 */ 185 JavaType erasure(); 186 187 // Factories 188 189 /** 190 * Constructs a Java type from a reflective type mirror. 191 * 192 * @param reflectiveType the reflective type mirror 193 */ 194 static JavaType type(Type reflectiveType) { 195 return switch (reflectiveType) { 196 case Class<?> c -> type(c.describeConstable().get()); 197 case ParameterizedType pt -> parameterized(type(pt.getRawType()), 198 Stream.of(pt.getActualTypeArguments()).map(JavaType::type).toList()); 199 case java.lang.reflect.WildcardType wt -> wt.getLowerBounds().length == 0 ? 200 wildcard(BoundKind.EXTENDS, type(wt.getUpperBounds()[0])) : 201 wildcard(BoundKind.SUPER, type(wt.getLowerBounds()[0])); 202 case TypeVariable<?> tv -> typeVarRef(tv.getName(), owner(tv.getGenericDeclaration()), type(tv.getBounds()[0])); 203 case GenericArrayType at -> array(type(at.getGenericComponentType())); 204 default -> throw new InternalError(); 205 }; 206 } 207 208 private static TypeVarRef.Owner owner(GenericDeclaration genDecl) { 209 return switch (genDecl) { 210 case Executable e -> MethodRef.method(e); 211 case Class<?> t -> (ClassType)type(t); 212 default -> throw new InternalError(); 213 }; 214 } 215 216 /** 217 * Constructs a Java type from a nominal descriptor. 218 * 219 * @param desc the nominal descriptor 220 */ 221 static JavaType type(ClassDesc desc) { 222 if (desc.isPrimitive()) { 223 return switch (desc.descriptorString().charAt(0)) { 224 case 'V' -> JavaType.VOID; 225 case 'I' -> JavaType.INT; 226 case 'J' -> JavaType.LONG; 227 case 'C' -> JavaType.CHAR; 228 case 'S' -> JavaType.SHORT; 229 case 'B' -> JavaType.BYTE; 230 case 'F' -> JavaType.FLOAT; 231 case 'D' -> JavaType.DOUBLE; 232 case 'Z' -> JavaType.BOOLEAN; 233 default -> throw new InternalError(); 234 }; 235 } else if (desc.isArray()) { 236 return array(type(desc.componentType())); 237 } else { 238 // class 239 return new ClassType(desc, List.of()); 240 } 241 } 242 243 /** 244 * Constructs a parameterized class type. 245 * 246 * @param type the base type of the parameterized type 247 * @param typeArguments the type arguments of the parameterized type 248 * @return a parameterized class type 249 * @throws IllegalArgumentException if {@code type} is not a {@linkplain ClassType class type} 250 * @throws IllegalArgumentException if {@code type} is {@linkplain ClassType class type} with 251 * a non-empty {@linkplain ClassType#typeArguments() type argument list}. 252 */ 253 static ClassType parameterized(JavaType type, JavaType... typeArguments) { 254 return parameterized(type, List.of(typeArguments)); 255 } 256 257 /** 258 * Constructs a parameterized class type. 259 * 260 * @param type the base type of the parameterized type 261 * @param typeArguments the type arguments of the parameterized type 262 * @return a parameterized class type 263 * @throws IllegalArgumentException if {@code type} is not a {@linkplain ClassType class type} 264 * @throws IllegalArgumentException if {@code type} is {@linkplain ClassType class type} with 265 * a non-empty {@linkplain ClassType#typeArguments() type argument list}. 266 */ 267 static ClassType parameterized(JavaType type, List<JavaType> typeArguments) { 268 if (!(type instanceof ClassType ct)) { 269 throw new IllegalArgumentException("Not a class type: " + type); 270 } 271 if (ct.hasTypeArguments()) { 272 throw new IllegalArgumentException("Already parameterized: " + type); 273 } 274 return new ClassType(type.toNominalDescriptor(), typeArguments); 275 } 276 277 /** 278 * Constructs an array type. 279 * 280 * @param elementType the array type's element type. 281 * @return an array type. 282 */ 283 static ArrayType array(JavaType elementType) { 284 Objects.requireNonNull(elementType); 285 return new ArrayType(elementType); 286 } 287 288 /** 289 * Constructs an array type. 290 * 291 * @param elementType the array type's element type. 292 * @param dims the array type dimension 293 * @return an array type. 294 * @throws IllegalArgumentException if {@code dims < 1}. 295 */ 296 static ArrayType array(JavaType elementType, int dims) { 297 Objects.requireNonNull(elementType); 298 if (dims < 1) { 299 throw new IllegalArgumentException("Invalid dimension: " + dims); 300 } 301 for (int i = 1 ; i < dims ; i++) { 302 elementType = array(elementType); 303 } 304 return array(elementType); 305 } 306 307 /** 308 * Constructs an unbounded wildcard type. 309 * 310 * @return an unbounded wildcard type. 311 */ 312 static WildcardType wildcard() { 313 return new WildcardType(BoundKind.EXTENDS, JavaType.J_L_OBJECT); 314 } 315 316 /** 317 * Constructs a bounded wildcard type of the given kind. 318 * 319 * @return a bounded wildcard type. 320 */ 321 static WildcardType wildcard(BoundKind kind, JavaType bound) { 322 return new WildcardType(kind, bound); 323 } 324 325 /** 326 * Constructs a reference to a type-variable with the given owner. 327 * 328 * @param bound the type-variable bound. 329 * @param owner the type-variable owner. 330 * @return a type-variable reference. 331 */ 332 static TypeVarRef typeVarRef(String name, TypeVarRef.Owner owner, JavaType bound) { 333 return new TypeVarRef(name, owner, bound); 334 } 335 336 /** 337 * Constructs a Java type from a string representation. 338 * @param s string representation 339 * @return a Java type corresponding to the provided string representation 340 */ 341 // Copied code in jdk.compiler module throws UOE 342 static JavaType ofString(String s) { 343 /*__throw new UnsupportedOperationException();__*/ return (JavaType) CoreTypeFactory.JAVA_TYPE_FACTORY.constructType(java.lang.reflect.code.parser.impl.DescParser.parseExTypeElem(s)); 344 } 345 }