1 package com.fasterxml.classmate;
2
3 import java.io.Serializable;
4 import java.lang.reflect.*;
5 import java.util.*;
6
7 import com.fasterxml.classmate.types.*;
8 import com.fasterxml.classmate.util.ClassKey;
9 import com.fasterxml.classmate.util.ClassStack;
10 import com.fasterxml.classmate.util.LRUTypeCache;
11 import com.fasterxml.classmate.util.ResolvedTypeCache;
12 import com.fasterxml.classmate.util.ResolvedTypeKey;
13
14 /**
15 * Object that is used for resolving generic type information of a class
16 * so that it is accessible using simple API. Resolved types are also starting
17 * point for accessing resolved (generics aware) return and argument types
18 * of class members (methods, fields, constructors).
19 *<p>
20 * Note that resolver instances are stateful in that resolvers cache resolved
21 * types for efficiency. Since this is internal state and not directly visible
22 * to callers, access to state is fully synchronized so that access from
23 * multiple threads is safe.
24 */
25 @SuppressWarnings("serial")
26 public class TypeResolver implements Serializable
27 {
28 private final static ResolvedType[] NO_TYPES = new ResolvedType[0];
29
30 /*
31 /**********************************************************************
32 /* Pre-created instances
33 /**********************************************************************
34 */
35
36 /**
37 * We will also need to return "unknown" type for cases where type variable binding
38 * is not found ('raw' instances of generic types); easiest way is to
39 * pre-create type for <code>java.lang.Object</code>
40 */
41 private final static ResolvedObjectType sJavaLangObject =
42 ResolvedObjectType.create(Object.class, null, null, null);
43
44 /**
45 * Since number of primitive types is small, and they are frequently needed,
46 * let's actually pre-create them for efficient reuse. Same goes for limited number
47 * of other "standard" types...
48 */
49 protected final static HashMap<ClassKey, ResolvedType> _primitiveTypes;
50 static {
51 _primitiveTypes = new HashMap<ClassKey, ResolvedType>(16);
52 for (ResolvedPrimitiveType type : ResolvedPrimitiveType.all()) {
53 _primitiveTypes.put(new ClassKey(type.getErasedType()), type);
54 }
55 // should we include "void"? might as well...
56 _primitiveTypes.put(new ClassKey(Void.TYPE), ResolvedPrimitiveType.voidType());
57 // and at least java.lang.Object should be added too.
58 _primitiveTypes.put(new ClassKey(Object.class), sJavaLangObject);
59 // but most other types can be added dynamically
60 }
61
62 /*
63 /**********************************************************************
64 /* Caching
65 /**********************************************************************
66 */
67
68 /**
69 * Simple cache of types resolved by this resolver.
70 * Caching works because type instances themselves are mostly immutable;
71 * and properly synchronized in cases where transient data (raw members) are
72 * accessed.
73 */
74 protected final ResolvedTypeCache _resolvedTypes;
75
76 /*
77 /**********************************************************************
78 /* Life cycle
79 /**********************************************************************
80 */
81
82 /**
83 * Constructs type cache; equivalent to:
84 *<pre>
85 * TypeResolver(ResolvedTypeCache.lruCache(200));
86 *</pre>
87 */
88 public TypeResolver() {
89 this(ResolvedTypeCache.lruCache(200));
90 }
91
92 /**
93 * Constructor that specifies type cache to use.
94 *
95 * @param typeCache Cache to use for avoiding repeated resolution of already resolved
96 * types
97 *
98 * @since 1.4
99 */
100 public TypeResolver(ResolvedTypeCache typeCache) {
101 _resolvedTypes = typeCache;
102 }
103
104 /*
105 /**********************************************************************
106 /* Factory methods, with explicit parameterization
107 /**********************************************************************
108 */
109
110 /**
111 * Factory method for resolving given base type
112 * using specified types as type parameters.
113 * Sample usage would be:
114 *<pre>
115 * ResolvedType type = TypeResolver.resolve(List.class, Integer.class);
116 *</pre>
117 * which would be equivalent to
118 *<pre>
119 * ResolvedType type = TypeResolver.resolve(new GenericType<List<Integer>>() { });
120 *</pre>
121 * Note that you can mix different types of type parameters, whether already
122 * resolved ({@link ResolvedType}), type-erased ({@link java.lang.Class}) or
123 * generic type reference ({@link GenericType}).
124 */
125 public ResolvedType resolve(Type type, Type... typeParameters)
126 {
127 boolean noParams = (typeParameters == null || typeParameters.length == 0);
128 TypeBindings bindings;
129 Class<?> rawBase;
130
131 if (type instanceof Class<?>) {
132 bindings = TypeBindings.emptyBindings();
133 if (noParams) {
134 return _fromClass(null, (Class<?>) type, bindings);
135 }
136 rawBase = (Class<?>) type;
137 } else if (type instanceof GenericType<?>) {
138 bindings = TypeBindings.emptyBindings();
139 if (noParams) {
140 return _fromGenericType(null, (GenericType<?>) type, bindings);
141 }
142 ResolvedType rt = _fromAny(null, type, bindings);
143 rawBase = rt.getErasedType();
144 } else if (type instanceof ResolvedType) {
145 ResolvedType rt = (ResolvedType) type;
146 if (noParams) {
147 return rt;
148 }
149 bindings = rt.getTypeBindings();
150 rawBase = rt.getErasedType();
151 } else {
152 bindings = TypeBindings.emptyBindings();
153 if (noParams) {
154 return resolve(bindings, type);
155 }
156 // Quite convoluted... but necessary to find Class<?> underlying it all
157 ResolvedType rt = _fromAny(null, type, bindings);
158 rawBase = rt.getErasedType();
159 }
160
161 // Next: resolve type parameters
162 int len = typeParameters.length;
163 ResolvedType[] resolvedParams = new ResolvedType[len];
164 for (int i = 0; i < len; ++i) {
165 resolvedParams[i] = _fromAny(null, typeParameters[i], bindings);
166 }
167 return _fromClass(null, rawBase, TypeBindings.create(rawBase, resolvedParams));
168 }
169
170 /**
171 * Factory method for constructing array type of given element type.
172 */
173 public ResolvedArrayType arrayType(Type elementType)
174 {
175 ResolvedType resolvedElementType = resolve(TypeBindings.emptyBindings(), elementType);
176 // Arrays are cumbersome for some reason:
177 Object emptyArray = Array.newInstance(resolvedElementType.getErasedType(), 0);
178 // Should we try to use cache? It's bit tricky, so let's not bother yet
179 return new ResolvedArrayType(emptyArray.getClass(), TypeBindings.emptyBindings(),
180 resolvedElementType);
181 }
182
183 /**
184 * Factory method for resolving specified Java {@link java.lang.reflect.Type}, given
185 * {@link TypeBindings} needed to resolve any type variables.
186 *<p>
187 * Use of this method is discouraged (use if and only if you really know what you
188 * are doing!); but if used, type bindings passed should come from {@link ResolvedType}
189 * instance of declaring class (or interface).
190 *<p>
191 * NOTE: order of arguments was reversed for 0.8, to avoid problems with
192 * overload varargs method.
193 */
194 public ResolvedType resolve(TypeBindings typeBindings, Type jdkType)
195 {
196 return _fromAny(null, jdkType, typeBindings);
197 }
198
199 /**
200 * Factory method for constructing sub-classing specified type; class specified
201 * as sub-class must be compatible according to basic Java inheritance rules
202 * (subtype must properly extend or implement specified supertype).
203 *<p>
204 * A typical use case here is to refine a generic type; for example, given
205 * that we have generic type like <code>List<Integer></code>, but we want
206 * a more specific implementation type like
207 * class <code>ArrayList</code> but with same parameterization (here just <code>Integer</code>),
208 * we could achieve it by:
209 *<pre>
210 * ResolvedType mapType = typeResolver.resolve(List.class, Integer.class);
211 * ResolveType concreteMapType = typeResolver.resolveSubType(mapType, ArrayList.class);
212 *</pre>
213 * (in this case, it would have been simpler to resolve directly; but in some
214 * cases we are handled supertype and want to refine it, in which case steps
215 * would be the same but separated by other code)
216 *<p>
217 * Note that this method will fail if extension can not succeed; either because
218 * this type is not extendable (sub-classable) -- which is true for primitive
219 * and array types -- or because given class is not a subtype of this type.
220 * To check whether subtyping could succeed, you can call
221 * {@link ResolvedType#canCreateSubtypes()} to see if supertype can ever
222 * be extended.
223 *
224 * @param supertype Type to subtype (extend)
225 * @param subtype Type-erased sub-class or sub-interface
226 *
227 * @return Resolved subtype
228 *
229 * @throws IllegalArgumentException If this type can be extended in general, but not into specified sub-class
230 * @throws UnsupportedOperationException If this type can not be sub-classed
231 */
232 public ResolvedType resolveSubtype(ResolvedType supertype, final Class<?> subtype)
233 throws IllegalArgumentException, UnsupportedOperationException
234 {
235 // first: if it's a recursive reference, find out referred-to type
236 ResolvedType refType = supertype.getSelfReferencedType();
237 if (refType != null) {
238 supertype = refType;
239 }
240 // Then, trivial check for case where subtype is supertype...
241 final Class<?> superclass = supertype.getErasedType();
242 if (superclass == subtype) { // unlikely but cheap check so let's just do it
243 return supertype;
244 }
245 // First: can not sub-class primitives, or array types
246 if (!supertype.canCreateSubtypes()) {
247 throw new UnsupportedOperationException("Can not subtype primitive or array types (type "+supertype.getFullDescription()+")");
248 }
249 // And in general must be able to subtype as per JVM rules:
250 if (!superclass.isAssignableFrom(subtype)) {
251 throw new IllegalArgumentException("Can not sub-class "+supertype.getBriefDescription()
252 +" into "+subtype.getName());
253 }
254 // Ok, then, let us instantiate type with placeholders
255 ResolvedType resolvedSubtype;
256 int paramCount = subtype.getTypeParameters().length;
257 TypePlaceHolder[] placeholders;
258 TypeBindings tbForPlaceholders;
259
260 if (paramCount == 0) { // no generics
261 placeholders = null;
262 // 26-Oct-2015, tatu: Used to do "full" call:
263 // resolvedSubtype = resolve(subtype);
264 // but should be able to streamline
265 tbForPlaceholders = TypeBindings.emptyBindings();
266 } else {
267 placeholders = new TypePlaceHolder[paramCount];
268 ResolvedType[] resolvedParams = new ResolvedType[paramCount];
269 for (int i = 0; i < paramCount; ++i) {
270 resolvedParams[i] = placeholders[i] = new TypePlaceHolder(i);
271 }
272 tbForPlaceholders = TypeBindings.create(subtype, resolvedParams);
273 }
274 resolvedSubtype = _fromClass(null, subtype, tbForPlaceholders);
275 ResolvedType resolvedSupertype = resolvedSubtype.findSupertype(superclass);
276 if (resolvedSupertype == null) { // sanity check, should never occur
277 throw new IllegalArgumentException("Internal error: unable to locate supertype ("+subtype.getName()+") for type "+supertype.getBriefDescription());
278 }
279 // Ok, then, let's find and verify type assignments; resolve type holders if any
280 // (and yes, even for no-type-parameters case)
281 _resolveTypePlaceholders(supertype, resolvedSupertype);
282 // And then re-construct, if necessary
283 if (paramCount == 0) { // if no type parameters, fine as is
284 return resolvedSubtype;
285 }
286 // but with type parameters, need to reconstruct
287 final ResolvedType[] typeParams = new ResolvedType[paramCount];
288 for (int i = 0; i < paramCount; ++i) {
289 ResolvedType t = placeholders[i].actualType();
290 // Is it ok for it to be left unassigned? For now let's not allow that
291 // 18-Oct-2017, tatu: Highly likely that we'll need to allow this, substitute with "unknown" --
292 // had to do that in Jackson. Occurs when subtype is generic, with "bogus" type declared
293 // but not bound in supertype(s). But leaving checking in for now.
294 if (t == null) {
295 throw new IllegalArgumentException("Failed to find type parameter #"+(i+1)+"/"
296 +paramCount+" for "+subtype.getName());
297 }
298 typeParams[i] = t;
299 }
300 return resolve(subtype, typeParams);
301 }
302
303 /*
304 /**********************************************************************
305 /* Misc other methods
306 /**********************************************************************
307 */
308
309 /**
310 * Convenience method that can be used to checked whether given resolved type
311 * (with erased type of <code>java.lang.Object</code>) is a placeholder
312 * for "self-reference"; these are nasty recursive ("self") types
313 * needed with some interfaces
314 *
315 * @param type Type to check
316 */
317 public static boolean isSelfReference(ResolvedType type)
318 {
319 return (type instanceof ResolvedRecursiveType);
320 }
321
322 /*
323 /**********************************************************************
324 /* Internal methods, second-level factory methods
325 /**********************************************************************
326 */
327
328 private ResolvedType _fromAny(ClassStack context, Type mainType, TypeBindings typeBindings)
329 {
330 if (mainType instanceof Class<?>) {
331 return _fromClass(context, (Class<?>) mainType, typeBindings);
332 }
333 if (mainType instanceof ParameterizedType) {
334 return _fromParamType(context, (ParameterizedType) mainType, typeBindings);
335 }
336 if (mainType instanceof ResolvedType) { // Esp. TypePlaceHolder
337 return (ResolvedType) mainType;
338 }
339 if (mainType instanceof GenericType<?>) {
340 return _fromGenericType(context, (GenericType<?>) mainType, typeBindings);
341 }
342 if (mainType instanceof GenericArrayType) {
343 return _fromArrayType(context, (GenericArrayType) mainType, typeBindings);
344 }
345 if (mainType instanceof TypeVariable<?>) {
346 return _fromVariable(context, (TypeVariable<?>) mainType, typeBindings);
347 }
348 if (mainType instanceof WildcardType) {
349 return _fromWildcard(context, (WildcardType) mainType, typeBindings);
350 }
351 // should never get here...
352 throw new IllegalArgumentException("Unrecognized type class: "+mainType.getClass().getName());
353 }
354
355 private ResolvedType _fromClass(ClassStack context, Class<?> rawType, TypeBindings typeBindings)
356 {
357 // First: a primitive type perhaps?
358 ResolvedType type = _primitiveTypes.get(new ClassKey(rawType));
359 if (type != null) {
360 return type;
361 }
362 // Second: recursive reference?
363 if (context == null) {
364 context = new ClassStack(rawType);
365 } else {
366 ClassStack prev = context.find(rawType);
367 if (prev != null) {
368 // Self-reference: needs special handling, then...
369 ResolvedRecursiveType selfRef = new ResolvedRecursiveType(rawType, typeBindings);
370 prev.addSelfReference(selfRef);
371 return selfRef;
372 }
373 // no, can just add
374 context = context.child(rawType);
375 }
376
377 // If not, already recently resolved?
378 ResolvedType[] typeParameters = typeBindings.typeParameterArray();
379 ResolvedTypeKey key = _resolvedTypes.key(rawType, typeParameters);
380 // 25-Oct-2015, tatu: one twist; if any TypePlaceHolders included, key will NOT be created,
381 // which means that caching should not be used (since type is mutable)
382 if (key == null) {
383 type = _constructType(context, rawType, typeBindings);
384 } else {
385 type = _resolvedTypes.find(key);
386 if (type == null) {
387 type = _constructType(context, rawType, typeBindings);
388 _resolvedTypes.put(key, type);
389 }
390 }
391 context.resolveSelfReferences(type);
392 return type;
393 }
394
395 /**
396 * Factory method for resolving given generic type, defined by using sub-class
397 * instance of {@link GenericType}
398 */
399 private ResolvedType _fromGenericType(ClassStack context, GenericType<?> generic, TypeBindings typeBindings)
400 {
401 /* To allow multiple levels of inheritance (just in case someone
402 * wants to go to town with inheritance of GenericType),
403 * we better resolve the whole thing; then dig out
404 * type parameterization...
405 */
406 ResolvedType type = _fromClass(context, generic.getClass(), typeBindings);
407 ResolvedType genType = type.findSupertype(GenericType.class);
408 if (genType == null) { // sanity check; shouldn't occur
409 throw new IllegalArgumentException("Unparameterized GenericType instance ("+generic.getClass().getName()+")");
410 }
411 TypeBindings b = genType.getTypeBindings();
412 ResolvedType[] params = b.typeParameterArray();
413 if (params.length == 0) {
414 throw new IllegalArgumentException("Unparameterized GenericType instance ("+generic.getClass().getName()+")");
415 }
416 return params[0];
417 }
418
419 private ResolvedType _constructType(ClassStack context, Class<?> rawType, TypeBindings typeBindings)
420 {
421 // Ok: no easy shortcut, let's figure out type of type...
422 if (rawType.isArray()) {
423 ResolvedType elementType = _fromAny(context, rawType.getComponentType(), typeBindings);
424 return new ResolvedArrayType(rawType, typeBindings, elementType);
425 }
426 // Work-around/fix for [#33]: if the type has no type parameters, don't include
427 // typeBindings in the ResolvedType
428 if (!typeBindings.isEmpty() && rawType.getTypeParameters().length == 0) {
429 typeBindings = TypeBindings.emptyBindings();
430 }
431 // For other types super interfaces are needed...
432 if (rawType.isInterface()) {
433 return new ResolvedInterfaceType(rawType, typeBindings,
434 _resolveSuperInterfaces(context, rawType, typeBindings));
435
436 }
437 return new ResolvedObjectType(rawType, typeBindings,
438 _resolveSuperClass(context, rawType, typeBindings),
439 _resolveSuperInterfaces(context, rawType, typeBindings));
440 }
441
442 private ResolvedType[] _resolveSuperInterfaces(ClassStack context, Class<?> rawType, TypeBindings typeBindings)
443 {
444 Type[] types = rawType.getGenericInterfaces();
445 if (types == null || types.length == 0) {
446 return NO_TYPES;
447 }
448 int len = types.length;
449 ResolvedType[] resolved = new ResolvedType[len];
450 for (int i = 0; i < len; ++i) {
451 resolved[i] = _fromAny(context, types[i], typeBindings);
452 }
453 return resolved;
454 }
455
456 /**
457 * NOTE: return type changed in 1.0.1 from {@link ResolvedObjectType} to
458 * {@link ResolvedType}, since it was found that other types may
459 * be returned...
460 *
461 * @return Usually a {@link ResolvedObjectType}, but possibly also
462 * {@link ResolvedRecursiveType}
463 */
464 private ResolvedType _resolveSuperClass(ClassStack context, Class<?> rawType, TypeBindings typeBindings)
465 {
466 Type parent = rawType.getGenericSuperclass();
467 if (parent == null) {
468 return null;
469 }
470 return _fromAny(context, parent, typeBindings);
471 }
472
473 private ResolvedType _fromParamType(ClassStack context, ParameterizedType ptype, TypeBindings parentBindings)
474 {
475 /* First: what is the actual base type? One odd thing is that 'getRawType'
476 * returns Type, not Class<?> as one might expect. But let's assume it is
477 * always of type Class: if not, need to add more code to resolve it...
478 */
479 Class<?> rawType = (Class<?>) ptype.getRawType();
480 Type[] params = ptype.getActualTypeArguments();
481 int len = params.length;
482 ResolvedType[] types = new ResolvedType[len];
483
484 for (int i = 0; i < len; ++i) {
485 types[i] = _fromAny(context, params[i], parentBindings);
486 }
487 // Ok: this gives us current bindings for this type:
488 TypeBindings newBindings = TypeBindings.create(rawType, types);
489 return _fromClass(context, rawType, newBindings);
490 }
491
492 private ResolvedType _fromArrayType(ClassStack context, GenericArrayType arrayType, TypeBindings typeBindings)
493 {
494 ResolvedType elementType = _fromAny(context, arrayType.getGenericComponentType(), typeBindings);
495 // Figuring out raw class for generic array is actually bit tricky...
496 Object emptyArray = Array.newInstance(elementType.getErasedType(), 0);
497 return new ResolvedArrayType(emptyArray.getClass(), typeBindings, elementType);
498 }
499
500 private ResolvedType _fromWildcard(ClassStack context, WildcardType wildType, TypeBindings typeBindings)
501 {
502 /* Similar to challenges with TypeVariable, we may have multiple upper bounds.
503 * But it is also possible that if upper bound defaults to Object, we might want to
504 * consider lower bounds instead?
505 * For now, we won't try anything more advanced; above is just for future reference.
506 */
507 return _fromAny(context, wildType.getUpperBounds()[0], typeBindings);
508 }
509
510 private ResolvedType _fromVariable(ClassStack context, TypeVariable<?> variable, TypeBindings typeBindings)
511 {
512 // ideally should find it via bindings:
513 String name = variable.getName();
514 ResolvedType type = typeBindings.findBoundType(name);
515
516 if (type != null) {
517 return type;
518 }
519
520 /* but if not, use bounds... note that approach here is simplistic; not taking
521 * into account possible multiple bounds, nor consider upper bounds.
522 */
523 /* 02-Mar-2011, tatu: As per issue#4, need to avoid self-reference cycles here;
524 * can be handled by (temporarily) adding binding:
525 */
526 if (typeBindings.hasUnbound(name)) {
527 return sJavaLangObject;
528 }
529 typeBindings = typeBindings.withUnboundVariable(name);
530
531 Type[] bounds = variable.getBounds();
532 return _fromAny(context, bounds[0], typeBindings);
533 }
534
535 /*
536 /**********************************************************************
537 /* Internal methods, replacing and verifying type placeholders
538 /**********************************************************************
539 */
540
541 /**
542 * Method called to verify that types match; and if there are any placeholders,
543 * replace them in <code>actualType</code>.
544 *
545 * @param sourceType Original base type used for specification/refinement
546 * @param actualType Base type instance after re-resolving, possibly containing type placeholders
547 */
548 private void _resolveTypePlaceholders(ResolvedType sourceType, ResolvedType actualType)
549 throws IllegalArgumentException
550 {
551 List<ResolvedType> expectedTypes = sourceType.getTypeParameters();
552 List<ResolvedType> actualTypes = actualType.getTypeParameters();
553 for (int i = 0, len = expectedTypes.size(); i < len; ++i) {
554 ResolvedType exp = expectedTypes.get(i);
555 ResolvedType act = actualTypes.get(i);
556 if (!_verifyAndResolve(exp, act)) {
557 throw new IllegalArgumentException("Type parameter #"+(i+1)+"/"+len+" differs; expected "
558 +exp.getBriefDescription()+", got "+act.getBriefDescription());
559 }
560 }
561 }
562
563 private boolean _verifyAndResolve(ResolvedType exp, ResolvedType act)
564 {
565 // See if we have an actual type placeholder to resolve; if yes, replace
566 if (act instanceof TypePlaceHolder) {
567 ((TypePlaceHolder) act).actualType(exp);
568 return true;
569 }
570 // if not, try to verify compatibility. But note that we can not
571 // use simple equality as we need to resolve recursively
572 if (exp.getErasedType() != act.getErasedType()) {
573 return false;
574 }
575 // But we can check type parameters "blindly"
576 List<ResolvedType> expectedTypes = exp.getTypeParameters();
577 List<ResolvedType> actualTypes = act.getTypeParameters();
578 for (int i = 0, len = expectedTypes.size(); i < len; ++i) {
579 ResolvedType exp2 = expectedTypes.get(i);
580 ResolvedType act2 = actualTypes.get(i);
581 if (!_verifyAndResolve(exp2, act2)) {
582 return false;
583 }
584 }
585 return true;
586 }
587 }
588