001    // Copyright 2008, 2010 The Apache Software Foundation
002    //
003    // Licensed under the Apache License, Version 2.0 (the "License");
004    // you may not use this file except in compliance with the License.
005    // You may obtain a copy of the License at
006    //
007    // http://www.apache.org/licenses/LICENSE-2.0
008    //
009    // Unless required by applicable law or agreed to in writing, software
010    // distributed under the License is distributed on an "AS IS" BASIS,
011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012    // See the License for the specific language governing permissions and
013    // limitations under the License.
014    
015    package org.apache.tapestry5.ioc.internal.util;
016    
017    import java.lang.reflect.*;
018    import java.util.LinkedList;
019    
020    /**
021     * Static methods related to the use of JDK 1.5 generics.
022     */
023    @SuppressWarnings("unchecked")
024    public class GenericsUtils
025    {
026        /**
027         * Analyzes the method in the context of containingClass and returns the Class that is represented by
028         * the method's generic return type. Any parameter information in the generic return type is lost. If you want
029         * to preserve the type parameters of the return type consider using
030         * {@link #extractActualType(java.lang.reflect.Type, java.lang.reflect.Method)}.
031         *
032         * @param containingClass class which either contains or inherited the method
033         * @param method          method from which to extract the return type
034         * @return the class represented by the methods generic return type, resolved based on the context .
035         * @see #extractActualType(java.lang.reflect.Type, java.lang.reflect.Method)
036         * @see #resolve(java.lang.reflect.Type,java.lang.reflect.Type)
037         * @see #asClass(java.lang.reflect.Type)
038         */
039        public static Class<?> extractGenericReturnType(Class<?> containingClass, Method method)
040        {
041            return asClass(resolve(method.getGenericReturnType(), containingClass));
042        }
043    
044    
045        /**
046         * Analyzes the field in the context of containingClass and returns the Class that is represented by
047         * the field's generic type. Any parameter information in the generic type is lost, if you want
048         * to preserve the type parameters of the return type consider using
049         * {@link #getTypeVariableIndex(java.lang.reflect.TypeVariable)}.
050         *
051         * @param containingClass class which either contains or inherited the field
052         * @param field           field from which to extract the type
053         * @return the class represented by the field's generic type, resolved based on the containingClass.
054         * @see #extractActualType(java.lang.reflect.Type, java.lang.reflect.Field)
055         * @see #resolve(java.lang.reflect.Type,java.lang.reflect.Type)
056         * @see #asClass(java.lang.reflect.Type)
057         */
058        public static Class extractGenericFieldType(Class containingClass, Field field)
059        {
060            return asClass(resolve(field.getGenericType(), containingClass));
061        }
062    
063        /**
064         * Analyzes the method in the context of containingClass and returns the Class that is represented by
065         * the method's generic return type. Any parameter information in the generic return type is lost.
066         *
067         * @param containingType Type which is/represents the class that either contains or inherited the method
068         * @param method         method from which to extract the generic return type
069         * @return the generic type represented by the methods generic return type, resolved based on the containingType.
070         * @see #resolve(java.lang.reflect.Type,java.lang.reflect.Type)
071         */
072        public static Type extractActualType(Type containingType, Method method)
073        {
074            return resolve(method.getGenericReturnType(), containingType);
075        }
076    
077        /**
078         * Analyzes the method in the context of containingClass and returns the Class that is represented by
079         * the method's generic return type. Any parameter information in the generic return type is lost.
080         *
081         * @param containingType Type which is/represents the class that either contains or inherited the field
082         * @param field          field from which to extract the generic return type
083         * @return the generic type represented by the methods generic return type, resolved based on the containingType.
084         * @see #resolve(java.lang.reflect.Type,java.lang.reflect.Type)
085         */
086        public static Type extractActualType(Type containingType, Field field)
087        {
088            return resolve(field.getGenericType(), containingType);
089        }
090    
091        /**
092         * Resolves the type parameter based on the context of the containingType.
093         * <p/>
094         * {@link java.lang.reflect.TypeVariable} will be unwrapped to the type argument resolved form the class
095         * hierarchy. This may be something other than a simple Class if the type argument is a ParameterizedType for
096         * instance (e.g. List&lt;E>; List&lt;Map&lt;Long, String>>, E would be returned as a ParameterizedType with the raw
097         * type Map and type arguments Long and String.
098         * <p/>
099         *
100         * @param type
101         *          the generic type (ParameterizedType, GenericArrayType, WildcardType, TypeVariable) to be resolved
102         * @param containingType
103         *          the type which his
104         * @return
105         *          the type resolved to the best of our ability.
106         * @since 5.2.?
107         */
108        public static Type resolve(final Type type, final Type containingType)
109        {
110            // The type isn't generic. (String, Long, etc)
111            if (type instanceof Class)
112                return type;
113    
114            // List<T>, List<String>, List<T extends Number>
115            if (type instanceof ParameterizedType)
116                return resolve((ParameterizedType) type, containingType);
117    
118            // T[], List<String>[], List<T>[]
119            if (type instanceof GenericArrayType)
120                return resolve((GenericArrayType) type, containingType);
121    
122            // List<? extends T>, List<? extends Object & Comparable & Serializable>
123            if (type instanceof WildcardType)
124                return resolve((WildcardType) type, containingType);
125    
126            // T
127            if (type instanceof TypeVariable)
128                return resolve((TypeVariable) type, containingType);
129    
130            // I'm leaning towards an exception here.
131            return type;
132        }
133    
134    
135        /**
136         * Determines if the suspected super type is assignable from the suspected sub type.
137         *
138         * @param suspectedSuperType
139         *          e.g. GenericDAO&lt;Pet, String>
140         * @param suspectedSubType
141         *          e.g. PetDAO extends GenericDAO&lt;Pet,String>
142         * @return
143         *          true if (sourceType)targetClass is a valid cast
144         */
145        public static boolean isAssignableFrom(Type suspectedSuperType, Type suspectedSubType)
146        {
147            final Class suspectedSuperClass = asClass(suspectedSuperType);
148            final Class suspectedSubClass = asClass(suspectedSubType);
149    
150            // The raw types need to be compatible.
151            if (!suspectedSuperClass.isAssignableFrom(suspectedSubClass))
152            {
153                return false;
154            }
155    
156            // From this point we know that the raw types are assignable.
157            // We need to figure out what the generic parameters in the targetClass are
158            // as they pertain to the sourceType.
159    
160            if (suspectedSuperType instanceof WildcardType)
161            {
162                // ? extends Number
163                // needs to match all the bounds (there will only be upper bounds or lower bounds
164                for (Type t : ((WildcardType) suspectedSuperType).getUpperBounds())
165                {
166                    if (!isAssignableFrom(t, suspectedSubType)) return false;
167                }
168                for (Type t : ((WildcardType) suspectedSuperType).getLowerBounds())
169                {
170                    if (!isAssignableFrom(suspectedSubType, t)) return false;
171                }
172                return true;
173            }
174    
175            Type curType = suspectedSubType;
176            Class curClass;
177    
178            while (curType != null && !curType.equals(Object.class))
179            {
180                curClass = asClass(curType);
181    
182                if (curClass.equals(suspectedSuperClass))
183                {
184                    final Type resolved = resolve(curType, suspectedSubType);
185    
186                    if (suspectedSuperType instanceof Class)
187                    {
188                        if ( resolved instanceof Class )
189                            return suspectedSuperType.equals(resolved);
190    
191                        // They may represent the same class, but the suspectedSuperType is not parameterized. The parameter
192                        // types default to Object so they must be a match.
193                        // e.g. Pair p = new StringLongPair();
194                        //      Pair p = new Pair<? extends Number, String>
195    
196                        return true;
197                    }
198    
199                    if (suspectedSuperType instanceof ParameterizedType)
200                    {
201                        if (resolved instanceof ParameterizedType)
202                        {
203                            final Type[] type1Arguments = ((ParameterizedType) suspectedSuperType).getActualTypeArguments();
204                            final Type[] type2Arguments = ((ParameterizedType) resolved).getActualTypeArguments();
205                            if (type1Arguments.length != type2Arguments.length) return false;
206    
207                            for (int i = 0; i < type1Arguments.length; ++i)
208                            {
209                                if (!isAssignableFrom(type1Arguments[i], type2Arguments[i])) return false;
210                            }
211                            return true;
212                        }
213                    }
214                    else if (suspectedSuperType instanceof GenericArrayType)
215                    {
216                        if (resolved instanceof GenericArrayType)
217                        {
218                            return isAssignableFrom(
219                                    ((GenericArrayType) suspectedSuperType).getGenericComponentType(),
220                                    ((GenericArrayType) resolved).getGenericComponentType()
221                            );
222                        }
223                    }
224    
225                    return false;
226                }
227    
228                final Type[] types = curClass.getGenericInterfaces();
229                for (Type t : types)
230                {
231                    final Type resolved = resolve(t, suspectedSubType);
232                    if (isAssignableFrom(suspectedSuperType, resolved))
233                        return true;
234                }
235    
236                curType = curClass.getGenericSuperclass();
237            }
238            return false;
239        }
240    
241        /**
242         * Get the class represented by the reflected type.
243         * This method is lossy; You cannot recover the type information from the class that is returned.
244         * <p/>
245         * {@code TypeVariable} the first bound is returned. If your type variable extends multiple interfaces that information
246         * is lost.
247         * <p/>
248         * {@code WildcardType} the first lower bound is returned. If the wildcard is defined with upper bounds
249         * then {@code Object} is returned.
250         *
251         * @param actualType
252         *           a Class, ParameterizedType, GenericArrayType
253         * @return the un-parameterized class associated with the type.
254         */
255        public static Class asClass(Type actualType)
256        {
257            if (actualType instanceof Class) return (Class) actualType;
258    
259            if (actualType instanceof ParameterizedType)
260            {
261                final Type rawType = ((ParameterizedType) actualType).getRawType();
262                // The sun implementation returns getRawType as Class<?>, but there is room in the interface for it to be
263                // some other Type. We'll assume it's a Class.
264                // TODO: consider logging or throwing our own exception for that day when "something else" causes some confusion
265                return (Class) rawType;
266            }
267    
268            if (actualType instanceof GenericArrayType)
269            {
270                final Type type = ((GenericArrayType) actualType).getGenericComponentType();
271                return Array.newInstance(asClass(type), 0).getClass();
272            }
273    
274            if (actualType instanceof TypeVariable)
275            {
276                // Support for List<T extends Number>
277                // There is always at least one bound. If no bound is specified in the source then it will be Object.class
278                return asClass(((TypeVariable) actualType).getBounds()[0]);
279            }
280    
281            if (actualType instanceof WildcardType)
282            {
283                final WildcardType wildcardType = (WildcardType) actualType;
284                final Type[] bounds = wildcardType.getLowerBounds();
285                if (bounds != null && bounds.length > 0)
286                {
287                    return asClass(bounds[0]);
288                }
289                // If there is no lower bounds then the only thing that makes sense is Object.
290                return Object.class;
291            }
292    
293            throw new RuntimeException(String.format("Unable to convert %s to Class.", actualType));
294        }
295    
296        /**
297         * Convert the type into a string. The string representation approximates the code that would be used to define the
298         * type.
299         *
300         * @param type - the type.
301         * @return a string representation of the type, similar to how it was declared.
302         */
303        public static String toString(Type type)
304        {
305            if ( type instanceof ParameterizedType ) return toString((ParameterizedType)type);
306            if ( type instanceof WildcardType ) return toString((WildcardType)type);
307            if ( type instanceof GenericArrayType) return toString((GenericArrayType)type);
308            if ( type instanceof Class )
309            {
310                final Class theClass = (Class) type;
311                return (theClass.isArray() ? theClass.getName() + "[]" : theClass.getName());
312            }
313            return type.toString();
314        }
315    
316        /**
317         * Method to resolve a TypeVariable to it's most
318         * <a href="http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#112582">reifiable</a> form.
319         * <p/>
320         * <p/>
321         * How to resolve a TypeVariable:<br/>
322         * All of the TypeVariables defined by a generic class will be given a Type by any class that extends it. The Type
323         * given may or may not be reifiable; it may be another TypeVariable for instance.
324         * <p/>
325         * Consider <br/>
326         * <i>class Pair&gt;A,B> { A getA(){...}; ...}</i><br/>
327         * <i>class StringLongPair extends Pair&gt;String, Long> { }</i><br/>
328         * <p/>
329         * To resolve the actual return type of Pair.getA() you must first resolve the TypeVariable "A".
330         * We can do that by first finding the index of "A" in the Pair.class.getTypeParameters() array of TypeVariables.
331         * <p/>
332         * To get to the Type provided by StringLongPair you access the generics information by calling
333         * StringLongPair.class.getGenericSuperclass; this will be a ParameterizedType. ParameterizedType gives you access
334         * to the actual type arguments provided to Pair by StringLongPair. The array is in the same order as the array in
335         * Pair.class.getTypeParameters so you can use the index we discovered earlier to extract the Type; String.class.
336         * <p/>
337         * When extracting Types we only have to consider the superclass hierarchy and not the interfaces implemented by
338         * the class. When a class implements a generic interface it must provide types for the interface and any generic
339         * methods implemented from the interface will be re-defined by the class with it's generic type variables.
340         *
341         * @param typeVariable   - the type variable to resolve.
342         * @param containingType - the shallowest class in the class hierarchy (furthest from Object) where typeVariable is defined.
343         * @return a Type that has had all possible TypeVariables resolved that have been defined between the type variable
344         *         declaration and the containingType.
345         */
346        private static Type resolve(TypeVariable typeVariable, Type containingType)
347        {
348            // The generic declaration is either a Class, Method or Constructor
349            final GenericDeclaration genericDeclaration = typeVariable.getGenericDeclaration();
350    
351            if (!(genericDeclaration instanceof Class))
352            {
353                // It's a method or constructor. The best we can do here is try to resolve the bounds
354                // e.g. <T extends E> T getT(T param){} where E is defined by the class.
355                final Type bounds0 = typeVariable.getBounds()[0];
356                return resolve(bounds0, containingType);
357            }
358    
359            final Class typeVariableOwner = (Class) genericDeclaration;
360    
361            // find the typeOwner in the containingType's hierarchy
362            final LinkedList<Type> stack = new LinkedList<Type>();
363    
364            // If you pass a List<Long> as the containingType then the TypeVariable is going to be resolved by the
365            // containingType and not the super class.
366            if (containingType instanceof ParameterizedType)
367            {
368                stack.add(containingType);
369            }
370    
371            Class theClass = asClass(containingType);
372            Type genericSuperclass = theClass.getGenericSuperclass();
373            while (genericSuperclass != null && // true for interfaces with no superclass
374                    !theClass.equals(Object.class) &&
375                    !theClass.equals(typeVariableOwner))
376            {
377                stack.addFirst(genericSuperclass);
378                theClass = asClass(genericSuperclass);
379                genericSuperclass = theClass.getGenericSuperclass();
380            }
381    
382            int i = getTypeVariableIndex(typeVariable);
383            Type resolved = typeVariable;
384            for (Type t : stack)
385            {
386                if (t instanceof ParameterizedType)
387                {
388                    resolved = ((ParameterizedType) t).getActualTypeArguments()[i];
389                    if (resolved instanceof Class) return resolved;
390                    if (resolved instanceof TypeVariable)
391                    {
392                        // Need to look at the next class in the hierarchy
393                        i = getTypeVariableIndex((TypeVariable) resolved);
394                        continue;
395                    }
396                    return resolve(resolved, containingType);
397                }
398            }
399    
400            // the only way we get here is if resolved is still a TypeVariable, otherwise an
401            // exception is thrown or a value is returned.
402            return ((TypeVariable) resolved).getBounds()[0];
403        }
404    
405        /**
406         * @param type           - something like List&lt;T>[] or List&lt;? extends T>[] or T[]
407         * @param containingType - the shallowest type in the hierarchy where type is defined.
408         * @return either the passed type if no changes required or a copy with a best effort resolve of the component type.
409         */
410        private static GenericArrayType resolve(GenericArrayType type, Type containingType)
411        {
412            final Type componentType = type.getGenericComponentType();
413    
414            if (!(componentType instanceof Class))
415            {
416                final Type resolved = resolve(componentType, containingType);
417                return create(resolved);
418            }
419    
420            return type;
421        }
422    
423        /**
424         * @param type           - something like List&lt;T>, List&lt;T extends Number>
425         * @param containingType - the shallowest type in the hierarchy where type is defined.
426         * @return the passed type if nothing to resolve or a copy of the type with the type arguments resolved.
427         */
428        private static ParameterizedType resolve(ParameterizedType type, Type containingType)
429        {
430            // Use a copy because we're going to modify it.
431            final Type[] types = type.getActualTypeArguments().clone();
432    
433            boolean modified = resolve(types, containingType);
434            return modified ? create(type.getRawType(), type.getOwnerType(), types) : type;
435        }
436    
437        /**
438         * @param type           - something like List&lt;? super T>, List<&lt;? extends T>, List&lt;? extends T & Comparable&lt? super T>>
439         * @param containingType - the shallowest type in the hierarchy where type is defined.
440         * @return the passed type if nothing to resolve or a copy of the type with the upper and lower bounds resolved.
441         */
442        private static WildcardType resolve(WildcardType type, Type containingType)
443        {
444            // Use a copy because we're going to modify them.
445            final Type[] upper = type.getUpperBounds().clone();
446            final Type[] lower = type.getLowerBounds().clone();
447    
448            boolean modified = resolve(upper, containingType);
449            modified = modified || resolve(lower, containingType);
450    
451            return modified ? create(upper, lower) : type;
452        }
453    
454        /**
455         * @param types          - Array of types to resolve. The unresolved type is replaced in the array with the resolved type.
456         * @param containingType - the shallowest type in the hierarchy where type is defined.
457         * @return true if any of the types were resolved.
458         */
459        private static boolean resolve(Type[] types, Type containingType)
460        {
461            boolean modified = false;
462            for (int i = 0; i < types.length; ++i)
463            {
464                Type t = types[i];
465                if (!(t instanceof Class))
466                {
467                    modified = true;
468                    final Type resolved = resolve(t, containingType);
469                    if (!resolved.equals(t))
470                    {
471                        types[i] = resolved;
472                        modified = true;
473                    }
474                }
475            }
476            return modified;
477        }
478    
479        /**
480         * @param rawType       - the un-parameterized type.
481         * @param ownerType     - the outer class or null if the class is not defined within another class.
482         * @param typeArguments - type arguments.
483         * @return a copy of the type with the typeArguments replaced.
484         */
485        static ParameterizedType create(final Type rawType, final Type ownerType, final Type[] typeArguments)
486        {
487            return new ParameterizedType()
488            {
489                public Type[] getActualTypeArguments()
490                {
491                    return typeArguments;
492                }
493    
494                public Type getRawType()
495                {
496                    return rawType;
497                }
498    
499                public Type getOwnerType()
500                {
501                    return ownerType;
502                }
503    
504                @Override
505                public String toString()
506                {
507                    return GenericsUtils.toString(this);
508                }
509            };
510        }
511    
512        static GenericArrayType create(final Type componentType)
513        {
514            return new GenericArrayType()
515            {
516                public Type getGenericComponentType()
517                {
518                    return componentType;
519                }
520    
521                @Override
522                public String toString()
523                {
524                    return GenericsUtils.toString(this);
525                }
526            };
527        }
528    
529        /**
530         * @param upperBounds - e.g. ? extends Number
531         * @param lowerBounds - e.g. ? super Long
532         * @return An new copy of the type with the upper and lower bounds replaced.
533         */
534        static WildcardType create(final Type[] upperBounds, final Type[] lowerBounds)
535        {
536    
537            return new WildcardType()
538            {
539                public Type[] getUpperBounds()
540                {
541                    return upperBounds;
542                }
543    
544                public Type[] getLowerBounds()
545                {
546                    return lowerBounds;
547                }
548    
549                @Override
550                public String toString()
551                {
552                    return GenericsUtils.toString(this);
553                }
554            };
555        }
556    
557        static String toString(ParameterizedType pt)
558        {
559            String s = toString(pt.getActualTypeArguments());
560            return String.format("%s<%s>", toString(pt.getRawType()), s);
561        }
562    
563        static String toString(GenericArrayType gat)
564        {
565            return String.format("%s[]", toString(gat.getGenericComponentType()));
566        }
567    
568        static String toString(WildcardType wt)
569        {
570            final boolean isSuper = wt.getLowerBounds().length > 0;
571            return String.format("? %s %s",
572                    isSuper ? "super" : "extends",
573                    isSuper ? toString(wt.getLowerBounds()) : toString(wt.getLowerBounds()));
574        }
575    
576        static String toString(Type[] types)
577        {
578            StringBuilder sb = new StringBuilder();
579            for ( Type t : types )
580            {
581                sb.append(toString(t)).append(", ");
582            }
583            return sb.substring(0, sb.length() - 2);// drop last ,
584        }
585    
586        /**
587         * Find the index of the TypeVariable in the classes parameters. The offset can be used on a subclass to find
588         * the actual type.
589         *
590         * @param typeVariable - the type variable in question.
591         * @return the index of the type variable in it's declaring class/method/constructor's type parameters.
592         */
593        private static int getTypeVariableIndex(final TypeVariable typeVariable)
594        {
595            // the label from the class (the T in List<T>, the K or V in Map<K,V>, etc)
596            final String typeVarName = typeVariable.getName();
597            final TypeVariable[] typeParameters = typeVariable.getGenericDeclaration().getTypeParameters();
598            for (int typeArgumentIndex = 0; typeArgumentIndex < typeParameters.length; typeArgumentIndex++)
599            {
600                // The .equals for TypeVariable may not be compatible, a name check should be sufficient.
601                if (typeParameters[typeArgumentIndex].getName().equals(typeVarName))
602                    return typeArgumentIndex;
603            }
604    
605            // The only way this could happen is if the TypeVariable is hand built incorrectly, or it's corrupted.
606            throw new RuntimeException(
607                    String.format("%s does not have a TypeVariable matching %s", typeVariable.getGenericDeclaration(), typeVariable));
608        }
609    }