    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}