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 }