001// Licensed under the Apache License, Version 2.0 (the "License");
002// you may not use this file except in compliance with the License.
003// You may obtain a copy of the License at
004//
005// http://www.apache.org/licenses/LICENSE-2.0
006//
007// Unless required by applicable law or agreed to in writing, software
008// distributed under the License is distributed on an "AS IS" BASIS,
009// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
010// See the License for the specific language governing permissions and
011// limitations under the License.
012
013package org.apache.tapestry5.commons.internal.util;
014
015import java.lang.reflect.Field;
016import java.lang.reflect.Method;
017import java.lang.reflect.Type;
018
019import org.apache.tapestry5.commons.services.GenericsResolver;
020
021/**
022 * Static methods related to the use of JDK 1.5 generics. From Tapestry 5.5.0,
023 * this class just delegates to {@link GenericsResolver}.
024 */
025public class GenericsUtils
026{
027    final private static GenericsResolver GENERICS_RESOLVER = GenericsResolver.Provider.getInstance();
028    
029    /**
030     * Analyzes the method in the context of containingClass and returns the Class that is represented by
031     * the method's generic return type. Any parameter information in the generic return type is lost. If you want
032     * to preserve the type parameters of the return type consider using
033     * {@link #extractActualType(java.lang.reflect.Type, java.lang.reflect.Method)}.
034     *
035     * @param containingClass class which either contains or inherited the method
036     * @param method          method from which to extract the return type
037     * @return the class represented by the methods generic return type, resolved based on the context .
038     * @see #extractActualType(java.lang.reflect.Type, java.lang.reflect.Method)
039     * @see #resolve(java.lang.reflect.Type,java.lang.reflect.Type)
040     * @see #asClass(java.lang.reflect.Type)
041     */
042    public static Class<?> extractGenericReturnType(Class<?> containingClass, Method method)
043    {
044        return GENERICS_RESOLVER.extractGenericReturnType(containingClass, method);
045    }
046
047    /**
048     * Analyzes the field in the context of containingClass and returns the Class that is represented by
049     * the field's generic type. Any parameter information in the generic type is lost, if you want
050     * to preserve the type parameters of the return type consider using
051     * #getTypeVariableIndex(java.lang.reflect.TypeVariable).
052     *
053     * @param containingClass class which either contains or inherited the field
054     * @param field           field from which to extract the type
055     * @return the class represented by the field's generic type, resolved based on the containingClass.
056     * @see #extractActualType(java.lang.reflect.Type, java.lang.reflect.Field)
057     * @see #resolve(java.lang.reflect.Type,java.lang.reflect.Type)
058     * @see #asClass(java.lang.reflect.Type)
059     */
060    public static Class extractGenericFieldType(Class containingClass, Field field)
061    {
062        return GENERICS_RESOLVER.extractGenericFieldType(containingClass, field);
063    }
064
065    /**
066     * Analyzes the method in the context of containingClass and returns the Class that is represented by
067     * the method's generic return type. Any parameter information in the generic return type is lost.
068     *
069     * @param containingType Type which is/represents the class that either contains or inherited the method
070     * @param method         method from which to extract the generic return type
071     * @return the generic type represented by the methods generic return type, resolved based on the containingType.
072     * @see #resolve(java.lang.reflect.Type,java.lang.reflect.Type)
073     */
074    public static Type extractActualType(Type containingType, Method method)
075    {
076        return GENERICS_RESOLVER.extractActualType(containingType, method);
077    }
078
079    /**
080     * Analyzes the method in the context of containingClass and returns the Class that is represented by
081     * the method's generic return type. Any parameter information in the generic return type is lost.
082     *
083     * @param containingType Type which is/represents the class that either contains or inherited the field
084     * @param field          field from which to extract the generic return type
085     * @return the generic type represented by the methods generic return type, resolved based on the containingType.
086     * @see #resolve(java.lang.reflect.Type,java.lang.reflect.Type)
087     */
088    public static Type extractActualType(Type containingType, Field field)
089    {
090        return GENERICS_RESOLVER.extractActualType(containingType, field);
091    }
092
093    /**
094     * Resolves the type parameter based on the context of the containingType.
095     *
096     * {@link java.lang.reflect.TypeVariable} will be unwrapped to the type argument resolved form the class
097     * hierarchy. This may be something other than a simple Class if the type argument is a ParameterizedType for
098     * instance (e.g. {@code List<E>; List<Map<Long, String>>}, E would be returned as a ParameterizedType with the raw
099     * type Map and type arguments Long and String.
100     *
101     *
102     * @param type
103     *          the generic type (ParameterizedType, GenericArrayType, WildcardType, TypeVariable) to be resolved
104     * @param containingType
105     *          the type which his
106     * @return
107     *          the type resolved to the best of our ability.
108     * @since 5.2.?
109     */
110    public static Type resolve(final Type type, final Type containingType)
111    {
112        return GENERICS_RESOLVER.resolve(type, containingType);
113    }
114    
115    /**
116     * Get the class represented by the reflected type.
117     * This method is lossy; You cannot recover the type information from the class that is returned.
118     *
119     * {@code TypeVariable} the first bound is returned. If your type variable extends multiple interfaces that information
120     * is lost.
121     *
122     * {@code WildcardType} the first lower bound is returned. If the wildcard is defined with upper bounds
123     * then {@code Object} is returned.
124     *
125     * @param actualType
126     *           a Class, ParameterizedType, GenericArrayType
127     * @return the un-parameterized class associated with the type.
128     */
129    public static Class asClass(Type actualType)
130    {
131        return GENERICS_RESOLVER.asClass(actualType);
132    }
133    
134}