• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2007 Mockito contributors
3  * This program is made available under the terms of the MIT License.
4  */
5 package org.mockito.internal.util.reflection;
6 
7 
8 import org.mockito.exceptions.base.MockitoException;
9 import org.mockito.internal.util.Checks;
10 
11 import java.lang.reflect.*;
12 import java.util.*;
13 
14 
15 /**
16  * This class can retrieve generic meta-data that the compiler stores on classes
17  * and accessible members.
18  *
19  * <p>
20  *     The main idea of this code is to create a Map that will help to resolve return types.
21  *     In order to actually work with nested generics, this map will have to be passed along new instances
22  *     as a type context.
23  * </p>
24  *
25  * <p>
26  *     Hence :
27  *     <ul>
28  *         <li>A new instance representing the metadata is created using the {@link #inferFrom(Type)} method from a real
29  *         <code>Class</code> or from a <code>ParameterizedType</code>, other types are not yet supported.</li>
30  *
31  *         <li>Then from this metadata, we can extract meta-data for a generic return type of a method, using
32  *         {@link #resolveGenericReturnType(Method)}.</li>
33  *     </ul>
34  * </p>
35  *
36  * <p>
37  * For now this code support the following kind of generic declarations :
38  * <pre class="code"><code class="java">
39  * interface GenericsNest&lt;K extends Comparable&lt;K&gt; & Cloneable&gt; extends Map&lt;K, Set&lt;Number&gt;&gt; {
40  *     Set&lt;Number&gt; remove(Object key); // override with fixed ParameterizedType
41  *     List&lt;? super Integer&gt; returning_wildcard_with_class_lower_bound();
42  *     List&lt;? super K&gt; returning_wildcard_with_typeVar_lower_bound();
43  *     List&lt;? extends K&gt; returning_wildcard_with_typeVar_upper_bound();
44  *     K returningK();
45  *     &lt;O extends K&gt; List&lt;O&gt; paramType_with_type_params();
46  *     &lt;S, T extends S&gt; T two_type_params();
47  *     &lt;O extends K&gt; O typeVar_with_type_params();
48  *     Number returningNonGeneric();
49  * }
50  * </code></pre>
51  *
52  * @see #inferFrom(Type)
53  * @see #resolveGenericReturnType(Method)
54  * @see org.mockito.internal.stubbing.defaultanswers.ReturnsDeepStubs
55  */
56 public abstract class GenericMetadataSupport {
57 
58     // public static MockitoLogger logger = new ConsoleMockitoLogger();
59 
60     /**
61      * Represents actual type variables resolved for current class.
62      */
63     protected Map<TypeVariable<?>, Type> contextualActualTypeParameters = new HashMap<TypeVariable<?>, Type>();
64 
65     /**
66      * Registers the type variables for the given type and all of its superclasses and superinterfaces.
67      */
registerAllTypeVariables(Type classType)68     protected void registerAllTypeVariables(Type classType) {
69         Queue<Type> typesToRegister = new LinkedList<Type>();
70         Set<Type> registeredTypes = new HashSet<Type>();
71         typesToRegister.add(classType);
72 
73         while (!typesToRegister.isEmpty()) {
74             Type typeToRegister = typesToRegister.poll();
75             if (typeToRegister == null || registeredTypes.contains(typeToRegister)) {
76                 continue;
77             }
78 
79             registerTypeVariablesOn(typeToRegister);
80             registeredTypes.add(typeToRegister);
81 
82             Class<?> rawType = extractRawTypeOf(typeToRegister);
83             typesToRegister.add(rawType.getGenericSuperclass());
84             typesToRegister.addAll(Arrays.asList(rawType.getGenericInterfaces()));
85         }
86     }
87 
extractRawTypeOf(Type type)88     protected Class<?> extractRawTypeOf(Type type) {
89         if (type instanceof Class) {
90             return (Class<?>) type;
91         }
92         if (type instanceof ParameterizedType) {
93             return (Class<?>) ((ParameterizedType) type).getRawType();
94         }
95         if (type instanceof BoundedType) {
96             return extractRawTypeOf(((BoundedType) type).firstBound());
97         }
98         if (type instanceof TypeVariable) {
99             /*
100              * If type is a TypeVariable, then it is needed to gather data elsewhere. Usually TypeVariables are declared
101              * on the class definition, such as such as List<E>.
102              */
103             return extractRawTypeOf(contextualActualTypeParameters.get(type));
104         }
105         throw new MockitoException("Raw extraction not supported for : '" + type + "'");
106     }
107 
registerTypeVariablesOn(Type classType)108     protected void registerTypeVariablesOn(Type classType) {
109         if (!(classType instanceof ParameterizedType)) {
110             return;
111         }
112         ParameterizedType parameterizedType = (ParameterizedType) classType;
113         TypeVariable<?>[] typeParameters = ((Class<?>) parameterizedType.getRawType()).getTypeParameters();
114         Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
115         for (int i = 0; i < actualTypeArguments.length; i++) {
116             TypeVariable<?> typeParameter = typeParameters[i];
117             Type actualTypeArgument = actualTypeArguments[i];
118 
119             if (actualTypeArgument instanceof WildcardType) {
120                 contextualActualTypeParameters.put(typeParameter, boundsOf((WildcardType) actualTypeArgument));
121             } else if (typeParameter != actualTypeArgument) {
122                 contextualActualTypeParameters.put(typeParameter, actualTypeArgument);
123             }
124             // logger.log("For '" + parameterizedType + "' found type variable : { '" + typeParameter + "(" + System.identityHashCode(typeParameter) + ")" + "' : '" + actualTypeArgument + "(" + System.identityHashCode(typeParameter) + ")" + "' }");
125         }
126     }
127 
registerTypeParametersOn(TypeVariable<?>[] typeParameters)128     protected void registerTypeParametersOn(TypeVariable<?>[] typeParameters) {
129         for (TypeVariable<?> type : typeParameters) {
130             registerTypeVariableIfNotPresent(type);
131         }
132     }
133 
registerTypeVariableIfNotPresent(TypeVariable<?> typeVariable)134     private void registerTypeVariableIfNotPresent(TypeVariable<?> typeVariable) {
135         if (!contextualActualTypeParameters.containsKey(typeVariable)) {
136             contextualActualTypeParameters.put(typeVariable, boundsOf(typeVariable));
137             // logger.log("For '" + typeVariable.getGenericDeclaration() + "' found type variable : { '" + typeVariable + "(" + System.identityHashCode(typeVariable) + ")" + "' : '" + boundsOf(typeVariable) + "' }");
138         }
139     }
140 
141     /**
142      * @param typeParameter The TypeVariable parameter
143      * @return A {@link BoundedType} for easy bound information, if first bound is a TypeVariable
144      *         then retrieve BoundedType of this TypeVariable
145      */
boundsOf(TypeVariable<?> typeParameter)146     private BoundedType boundsOf(TypeVariable<?> typeParameter) {
147         if (typeParameter.getBounds()[0] instanceof TypeVariable) {
148             return boundsOf((TypeVariable<?>) typeParameter.getBounds()[0]);
149         }
150         return new TypeVarBoundedType(typeParameter);
151     }
152 
153     /**
154      * @param wildCard The WildCard type
155      * @return A {@link BoundedType} for easy bound information, if first bound is a TypeVariable
156      *         then retrieve BoundedType of this TypeVariable
157      */
boundsOf(WildcardType wildCard)158     private BoundedType boundsOf(WildcardType wildCard) {
159         /*
160          *  According to JLS(http://docs.oracle.com/javase/specs/jls/se5.0/html/typesValues.html#4.5.1):
161          *  - Lower and upper can't coexist: (for instance, this is not allowed: <? extends List<String> & super MyInterface>)
162          *  - Multiple bounds are not supported (for instance, this is not allowed: <? extends List<String> & MyInterface>)
163          */
164 
165         WildCardBoundedType wildCardBoundedType = new WildCardBoundedType(wildCard);
166         if (wildCardBoundedType.firstBound() instanceof TypeVariable) {
167             return boundsOf((TypeVariable<?>) wildCardBoundedType.firstBound());
168         }
169 
170         return wildCardBoundedType;
171     }
172 
173     /**
174      * @return Raw type of the current instance.
175      */
rawType()176     public abstract Class<?> rawType();
177 
178     /**
179      * @return Returns extra interfaces <strong>if relevant</strong>, otherwise empty List.
180      */
extraInterfaces()181     public List<Type> extraInterfaces() {
182         return Collections.emptyList();
183     }
184 
185     /**
186      * @return Returns an array with the raw types of {@link #extraInterfaces()} <strong>if relevant</strong>.
187      */
rawExtraInterfaces()188     public Class<?>[] rawExtraInterfaces() {
189         return new Class[0];
190     }
191 
192     /**
193      * @return Returns true if metadata knows about extra-interfaces {@link #extraInterfaces()} <strong>if relevant</strong>.
194      */
hasRawExtraInterfaces()195     public boolean hasRawExtraInterfaces() {
196         return rawExtraInterfaces().length > 0;
197     }
198 
199     /**
200      * @return Actual type arguments matching the type variables of the raw type represented by this {@link GenericMetadataSupport} instance.
201      */
actualTypeArguments()202     public Map<TypeVariable<?>, Type> actualTypeArguments() {
203         TypeVariable<?>[] typeParameters = rawType().getTypeParameters();
204         LinkedHashMap<TypeVariable<?>, Type> actualTypeArguments = new LinkedHashMap<TypeVariable<?>, Type>();
205 
206         for (TypeVariable<?> typeParameter : typeParameters) {
207 
208             Type actualType = getActualTypeArgumentFor(typeParameter);
209 
210             actualTypeArguments.put(typeParameter, actualType);
211             // logger.log("For '" + rawType().getCanonicalName() + "' returning explicit TypeVariable : { '" + typeParameter + "(" + System.identityHashCode(typeParameter) + ")" + "' : '" + actualType +"' }");
212         }
213 
214         return actualTypeArguments;
215     }
216 
getActualTypeArgumentFor(TypeVariable<?> typeParameter)217     protected Type getActualTypeArgumentFor(TypeVariable<?> typeParameter) {
218         Type type = this.contextualActualTypeParameters.get(typeParameter);
219         if (type instanceof TypeVariable) {
220             TypeVariable<?> typeVariable = (TypeVariable<?>) type;
221             return getActualTypeArgumentFor(typeVariable);
222         }
223 
224         return type;
225     }
226 
227     /**
228      * Resolve current method generic return type to a {@link GenericMetadataSupport}.
229      *
230      * @param method Method to resolve the return type.
231      * @return {@link GenericMetadataSupport} representing this generic return type.
232      */
resolveGenericReturnType(Method method)233     public GenericMetadataSupport resolveGenericReturnType(Method method) {
234         Type genericReturnType = method.getGenericReturnType();
235         // logger.log("Method '" + method.toGenericString() + "' has return type : " + genericReturnType.getClass().getInterfaces()[0].getSimpleName() + " : " + genericReturnType);
236 
237         int arity = 0;
238         while(genericReturnType instanceof GenericArrayType) {
239             arity++;
240             genericReturnType = ((GenericArrayType) genericReturnType).getGenericComponentType();
241         }
242 
243         GenericMetadataSupport genericMetadataSupport = resolveGenericType(genericReturnType, method);
244         if (arity == 0) {
245             return genericMetadataSupport;
246         } else {
247             return new GenericArrayReturnType(genericMetadataSupport, arity);
248         }
249     }
250 
resolveGenericType(Type type, Method method)251     private GenericMetadataSupport resolveGenericType(Type type, Method method) {
252 
253         if (type instanceof Class) {
254             return new NotGenericReturnTypeSupport(this, type);
255         }
256         if (type instanceof ParameterizedType) {
257             return new ParameterizedReturnType(this, method.getTypeParameters(), (ParameterizedType) type);
258         }
259         if (type instanceof TypeVariable) {
260             return new TypeVariableReturnType(this, method.getTypeParameters(), (TypeVariable<?>) type);
261         }
262 
263         throw new MockitoException("Ouch, it shouldn't happen, type '" + type.getClass().getCanonicalName() + "' on method : '" + method.toGenericString() + "' is not supported : " + type);
264     }
265 
266     /**
267      * Create an new instance of {@link GenericMetadataSupport} inferred from a {@link Type}.
268      *
269      * <p>
270      *     At the moment <code>type</code> can only be a {@link Class} or a {@link ParameterizedType}, otherwise
271      *     it'll throw a {@link MockitoException}.
272      * </p>
273      *
274      * @param type The class from which the {@link GenericMetadataSupport} should be built.
275      * @return The new {@link GenericMetadataSupport}.
276      * @throws MockitoException Raised if type is not a {@link Class} or a {@link ParameterizedType}.
277      */
inferFrom(Type type)278     public static GenericMetadataSupport inferFrom(Type type) {
279         Checks.checkNotNull(type, "type");
280         if (type instanceof Class) {
281             return new FromClassGenericMetadataSupport((Class<?>) type);
282         }
283         if (type instanceof ParameterizedType) {
284             return new FromParameterizedTypeGenericMetadataSupport((ParameterizedType) type);
285         }
286 
287         throw new MockitoException("Type meta-data for this Type (" + type.getClass().getCanonicalName() + ") is not supported : " + type);
288     }
289 
290 
291     ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
292     //// Below are specializations of GenericMetadataSupport that could handle retrieval of possible Types
293     ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
294 
295     /**
296      * Generic metadata implementation for {@link Class}.
297      *
298      * Offer support to retrieve generic metadata on a {@link Class} by reading type parameters and type variables on
299      * the class and its ancestors and interfaces.
300      */
301     private static class FromClassGenericMetadataSupport extends GenericMetadataSupport {
302         private final Class<?> clazz;
303 
FromClassGenericMetadataSupport(Class<?> clazz)304         public FromClassGenericMetadataSupport(Class<?> clazz) {
305             this.clazz = clazz;
306 
307             registerTypeParametersOn(clazz.getTypeParameters());
308             registerAllTypeVariables(clazz);
309         }
310 
311         @Override
rawType()312         public Class<?> rawType() {
313             return clazz;
314         }
315     }
316 
317     /**
318      * Generic metadata implementation for "standalone" {@link ParameterizedType}.
319      *
320      * Offer support to retrieve generic metadata on a {@link ParameterizedType} by reading type variables of
321      * the related raw type and declared type variable of this parameterized type.
322      *
323      * This class is not designed to work on ParameterizedType returned by {@link Method#getGenericReturnType()}, as
324      * the ParameterizedType instance return in these cases could have Type Variables that refer to type declaration(s).
325      * That's what meant the "standalone" word at the beginning of the Javadoc.
326      * Instead use {@link ParameterizedReturnType}.
327      */
328     private static class FromParameterizedTypeGenericMetadataSupport extends GenericMetadataSupport {
329         private final ParameterizedType parameterizedType;
330 
FromParameterizedTypeGenericMetadataSupport(ParameterizedType parameterizedType)331         public FromParameterizedTypeGenericMetadataSupport(ParameterizedType parameterizedType) {
332             this.parameterizedType = parameterizedType;
333             readActualTypeParameters();
334         }
335 
readActualTypeParameters()336         private void readActualTypeParameters() {
337             registerAllTypeVariables(parameterizedType);
338         }
339 
340         @Override
rawType()341         public Class<?> rawType() {
342             return (Class<?>) parameterizedType.getRawType();
343         }
344     }
345 
346     /**
347      * Generic metadata specific to {@link ParameterizedType} returned via {@link Method#getGenericReturnType()}.
348      */
349     private static class ParameterizedReturnType extends GenericMetadataSupport {
350         private final ParameterizedType parameterizedType;
351         private final TypeVariable<?>[] typeParameters;
352 
ParameterizedReturnType(GenericMetadataSupport source, TypeVariable<?>[] typeParameters, ParameterizedType parameterizedType)353         public ParameterizedReturnType(GenericMetadataSupport source, TypeVariable<?>[] typeParameters, ParameterizedType parameterizedType) {
354             this.parameterizedType = parameterizedType;
355             this.typeParameters = typeParameters;
356             this.contextualActualTypeParameters = source.contextualActualTypeParameters;
357 
358             readTypeParameters();
359             readTypeVariables();
360         }
361 
readTypeParameters()362         private void readTypeParameters() {
363             registerTypeParametersOn(typeParameters);
364         }
365 
readTypeVariables()366         private void readTypeVariables() {
367             registerTypeVariablesOn(parameterizedType);
368         }
369 
370         @Override
rawType()371         public Class<?> rawType() {
372             return (Class<?>) parameterizedType.getRawType();
373         }
374 
375     }
376 
377     /**
378      * Generic metadata for {@link TypeVariable} returned via {@link Method#getGenericReturnType()}.
379      */
380     private static class TypeVariableReturnType extends GenericMetadataSupport {
381         private final TypeVariable<?> typeVariable;
382         private final TypeVariable<?>[] typeParameters;
383         private Class<?> rawType;
384 
TypeVariableReturnType(GenericMetadataSupport source, TypeVariable<?>[] typeParameters, TypeVariable<?> typeVariable)385         public TypeVariableReturnType(GenericMetadataSupport source, TypeVariable<?>[] typeParameters, TypeVariable<?> typeVariable) {
386             this.typeParameters = typeParameters;
387             this.typeVariable = typeVariable;
388             this.contextualActualTypeParameters = source.contextualActualTypeParameters;
389 
390             readTypeParameters();
391             readTypeVariables();
392         }
393 
readTypeParameters()394         private void readTypeParameters() {
395             registerTypeParametersOn(typeParameters);
396         }
397 
readTypeVariables()398         private void readTypeVariables() {
399             for (Type type : typeVariable.getBounds()) {
400                 registerTypeVariablesOn(type);
401             }
402             registerTypeParametersOn(new TypeVariable[] { typeVariable });
403             registerTypeVariablesOn(getActualTypeArgumentFor(typeVariable));
404         }
405 
406         @Override
rawType()407         public Class<?> rawType() {
408             if (rawType == null) {
409                 rawType = extractRawTypeOf(typeVariable);
410             }
411             return rawType;
412         }
413 
414         @Override
extraInterfaces()415         public List<Type> extraInterfaces() {
416             Type type = extractActualBoundedTypeOf(typeVariable);
417             if (type instanceof BoundedType) {
418                 return Arrays.asList(((BoundedType) type).interfaceBounds());
419             }
420             if (type instanceof ParameterizedType) {
421                 return Collections.singletonList(type);
422             }
423             if (type instanceof Class) {
424                 return Collections.emptyList();
425             }
426             throw new MockitoException("Cannot extract extra-interfaces from '" + typeVariable + "' : '" + type + "'");
427         }
428 
429         /**
430          * @return Returns an array with the extracted raw types of {@link #extraInterfaces()}.
431          * @see #extractRawTypeOf(java.lang.reflect.Type)
432          */
rawExtraInterfaces()433         public Class<?>[] rawExtraInterfaces() {
434             List<Type> extraInterfaces = extraInterfaces();
435             List<Class<?>> rawExtraInterfaces = new ArrayList<Class<?>>();
436             for (Type extraInterface : extraInterfaces) {
437                 Class<?> rawInterface = extractRawTypeOf(extraInterface);
438                 // avoid interface collision with actual raw type (with typevariables, resolution ca be quite aggressive)
439                 if(!rawType().equals(rawInterface)) {
440                     rawExtraInterfaces.add(rawInterface);
441                 }
442             }
443             return rawExtraInterfaces.toArray(new Class[rawExtraInterfaces.size()]);
444         }
445 
extractActualBoundedTypeOf(Type type)446         private Type extractActualBoundedTypeOf(Type type) {
447             if (type instanceof TypeVariable) {
448                 /*
449                 If type is a TypeVariable, then it is needed to gather data elsewhere. Usually TypeVariables are declared
450                 on the class definition, such as such as List<E>.
451                 */
452                 return extractActualBoundedTypeOf(contextualActualTypeParameters.get(type));
453             }
454             if (type instanceof BoundedType) {
455                 Type actualFirstBound = extractActualBoundedTypeOf(((BoundedType) type).firstBound());
456                 if (!(actualFirstBound instanceof BoundedType)) {
457                     return type; // avoid going one step further, ie avoid : O(TypeVar) -> K(TypeVar) -> Some ParamType
458                 }
459                 return actualFirstBound;
460             }
461             return type; // irrelevant, we don't manage other types as they are not bounded.
462         }
463     }
464 
465     private static class GenericArrayReturnType extends GenericMetadataSupport {
466 
467         private final GenericMetadataSupport genericArrayType;
468 
469         private final int arity;
470 
GenericArrayReturnType(GenericMetadataSupport genericArrayType, int arity)471         public GenericArrayReturnType(GenericMetadataSupport genericArrayType, int arity) {
472             this.genericArrayType = genericArrayType;
473             this.arity = arity;
474         }
475 
476         @Override
rawType()477         public Class<?> rawType() {
478             Class<?> rawComponentType = genericArrayType.rawType();
479             StringBuilder stringBuilder = new StringBuilder();
480             for (int i = 0; i < arity; i++) {
481                 stringBuilder.append("[");
482             }
483             try {
484                 return Class.forName(stringBuilder.append("L").append(rawComponentType.getName()).append(";").toString(), false, rawComponentType.getClassLoader());
485             } catch (ClassNotFoundException e) {
486                 throw new IllegalStateException("This was not supposed to happend", e);
487             }
488         }
489     }
490 
491     /**
492      * Non-Generic metadata for {@link Class} returned via {@link Method#getGenericReturnType()}.
493      */
494     private static class NotGenericReturnTypeSupport extends GenericMetadataSupport {
495         private final Class<?> returnType;
496 
NotGenericReturnTypeSupport(GenericMetadataSupport source, Type genericReturnType)497         public NotGenericReturnTypeSupport(GenericMetadataSupport source, Type genericReturnType) {
498             returnType = (Class<?>) genericReturnType;
499             this.contextualActualTypeParameters = source.contextualActualTypeParameters;
500 
501             registerAllTypeVariables(returnType);
502         }
503 
504         @Override
rawType()505         public Class<?> rawType() {
506             return returnType;
507         }
508     }
509 
510 
511 
512     /**
513      * Type representing bounds of a type
514      *
515      * @see TypeVarBoundedType
516      * @see <a href="http://docs.oracle.com/javase/specs/jls/se5.0/html/typesValues.html#4.4">http://docs.oracle.com/javase/specs/jls/se5.0/html/typesValues.html#4.4</a>
517      * @see WildCardBoundedType
518      * @see <a href="http://docs.oracle.com/javase/specs/jls/se5.0/html/typesValues.html#4.5.1">http://docs.oracle.com/javase/specs/jls/se5.0/html/typesValues.html#4.5.1</a>
519      */
520     public interface BoundedType extends Type {
firstBound()521         Type firstBound();
522 
interfaceBounds()523         Type[] interfaceBounds();
524     }
525 
526     /**
527      * Type representing bounds of a type variable, allows to keep all bounds information.
528      *
529      * <p>It uses the first bound in the array, as this array is never null and always contains at least
530      * one element (Object is always here if no bounds are declared).</p>
531      *
532      * <p>If upper bounds are declared with SomeClass and additional interfaces, then firstBound will be SomeClass and
533      * interfacesBound will be an array of the additional interfaces.
534      *
535      * i.e. <code>SomeClass</code>.
536      * <pre class="code"><code class="java">
537      *     interface UpperBoundedTypeWithClass<E extends Comparable<E> & Cloneable> {
538      *         E get();
539      *     }
540      *     // will return Comparable type
541      * </code></pre>
542      * </p>
543      *
544      * @see <a href="http://docs.oracle.com/javase/specs/jls/se5.0/html/typesValues.html#4.4">http://docs.oracle.com/javase/specs/jls/se5.0/html/typesValues.html#4.4</a>
545      */
546     public static class TypeVarBoundedType implements BoundedType {
547         private final TypeVariable<?> typeVariable;
548 
TypeVarBoundedType(TypeVariable<?> typeVariable)549         public TypeVarBoundedType(TypeVariable<?> typeVariable) {
550             this.typeVariable = typeVariable;
551         }
552 
553         /**
554          * @return either a class or an interface (parameterized or not), if no bounds declared Object is returned.
555          */
firstBound()556         public Type firstBound() {
557             return typeVariable.getBounds()[0]; //
558         }
559 
560         /**
561          * On a Type Variable (typeVar extends C_0 & I_1 & I_2 & etc), will return an array
562          * containing I_1 and I_2.
563          *
564          * @return other bounds for this type, these bounds can only be only interfaces as the JLS says,
565          * empty array if no other bound declared.
566          */
interfaceBounds()567         public Type[] interfaceBounds() {
568             Type[] interfaceBounds = new Type[typeVariable.getBounds().length - 1];
569             System.arraycopy(typeVariable.getBounds(), 1, interfaceBounds, 0, typeVariable.getBounds().length - 1);
570             return interfaceBounds;
571         }
572 
573         @Override
equals(Object o)574         public boolean equals(Object o) {
575             if (this == o) return true;
576             if (o == null || getClass() != o.getClass()) return false;
577 
578             return typeVariable.equals(((TypeVarBoundedType) o).typeVariable);
579 
580         }
581 
582         @Override
hashCode()583         public int hashCode() {
584             return typeVariable.hashCode();
585         }
586 
587         @Override
toString()588         public String toString() {
589             return "{firstBound=" + firstBound() + ", interfaceBounds=" + Arrays.deepToString(interfaceBounds()) + '}';
590         }
591 
typeVariable()592         public TypeVariable<?> typeVariable() {
593             return typeVariable;
594         }
595     }
596 
597     /**
598      * Type representing bounds of a wildcard, allows to keep all bounds information.
599      *
600      * <p>The JLS says that lower bound and upper bound are mutually exclusive, and that multiple bounds
601      * are not allowed.
602      *
603      * @see <a href="http://docs.oracle.com/javase/specs/jls/se5.0/html/typesValues.html#4.4">http://docs.oracle.com/javase/specs/jls/se5.0/html/typesValues.html#4.4</a>
604      */
605     public static class WildCardBoundedType implements BoundedType {
606         private final WildcardType wildcard;
607 
608 
WildCardBoundedType(WildcardType wildcard)609         public WildCardBoundedType(WildcardType wildcard) {
610             this.wildcard = wildcard;
611         }
612 
613         /**
614          * @return The first bound, either a type or a reference to a TypeVariable
615          */
firstBound()616         public Type firstBound() {
617             Type[] lowerBounds = wildcard.getLowerBounds();
618             Type[] upperBounds = wildcard.getUpperBounds();
619 
620             return lowerBounds.length != 0 ? lowerBounds[0] : upperBounds[0];
621         }
622 
623         /**
624          * @return An empty array as, wildcard don't support multiple bounds.
625          */
interfaceBounds()626         public Type[] interfaceBounds() {
627             return new Type[0];
628         }
629 
630         @Override
equals(Object o)631         public boolean equals(Object o) {
632             if (this == o) return true;
633             if (o == null || getClass() != o.getClass()) return false;
634 
635             return wildcard.equals(((TypeVarBoundedType) o).typeVariable);
636 
637         }
638 
639         @Override
hashCode()640         public int hashCode() {
641             return wildcard.hashCode();
642         }
643 
644         @Override
toString()645         public String toString() {
646             return "{firstBound=" + firstBound() + ", interfaceBounds=[]}";
647         }
648 
wildCard()649         public WildcardType wildCard() {
650             return wildcard;
651         }
652     }
653 
654 }
655 
656 
657