All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jetbrick.bean.TypeResolverUtils Maven / Gradle / Ivy

There is a newer version: 2.2.0
Show newest version
/**
 * Copyright 2013-2016 Guoqiang Chen, Shanghai, China. All rights reserved.
 *
 *   Author: Guoqiang Chen
 *    Email: [email protected]
 *   WebURL: https://github.com/subchen
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package jetbrick.bean;

import java.lang.reflect.Array;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;

import jetbrick.util.ArrayUtils;

/**
 * 根据类型定义,获取泛型信息.
 *
 * @author Guoqiang Chen
 */
public final class TypeResolverUtils {

    /**
     * Returns raw class for given type. Use this method with both
     * regular and generic types.
     *
     * @param type - the type to convert
     * @return the closest class representing the given type
     * @see #getRawType(java.lang.reflect.Type, Class)
     */
    public static Class getRawType(Type type) {
        return getRawType(type, null);
    }

    /**
     * Returns raw class for given type when implementation class is known
     * and it makes difference.
     *
     * @param type - given type
     * @param implClass - implementation clas
     * @return raw class
     * @see #resolveVariable(java.lang.reflect.TypeVariable, Class)
     */
    public static Class getRawType(Type type, Class implClass) {
        if (type instanceof Class) {
            return (Class) type;
        }
        if (type instanceof ParameterizedType) {
            ParameterizedType pType = (ParameterizedType) type;
            return getRawType(pType.getRawType(), implClass);
        }
        if (type instanceof WildcardType) {
            WildcardType wType = (WildcardType) type;

            Type[] lowerTypes = wType.getLowerBounds();
            if (lowerTypes.length > 0) {
                return getRawType(lowerTypes[0], implClass);
            }

            Type[] upperTypes = wType.getUpperBounds();
            if (upperTypes.length != 0) {
                return getRawType(upperTypes[0], implClass);
            }

            return Object.class;
        }
        if (type instanceof GenericArrayType) {
            Type genericComponentType = ((GenericArrayType) type).getGenericComponentType();
            Class rawType = getRawType(genericComponentType, implClass);

            return Array.newInstance(rawType, 0).getClass();
        }
        if (type instanceof TypeVariable) {
            TypeVariable varType = (TypeVariable) type;
            if (implClass != null) {
                Type resolvedType = resolveVariable(varType, implClass);
                if (resolvedType != null) {
                    return getRawType(resolvedType, null);
                }
            }
            Type[] boundsTypes = varType.getBounds();
            if (boundsTypes.length == 0) {
                return Object.class;
            }
            return getRawType(boundsTypes[0], implClass);
        }
        return null;
    }

    /**
     * Resolves TypeVariable with given implementation class.
     *
     * @param variable - variable
     * @param implClass - implementation class
     * @return resolved type
     */
    public static Type resolveVariable(TypeVariable variable, Class implClass) {
        Class rawType = getRawType(implClass, null);

        int index = ArrayUtils.indexOf(rawType.getTypeParameters(), variable);
        if (index >= 0) {
            return variable;
        }

        Class[] interfaces = rawType.getInterfaces();
        Type[] genericInterfaces = rawType.getGenericInterfaces();

        for (int i = 0; i <= interfaces.length; i++) {
            Class rawInterface;
            if (i < interfaces.length) {
                rawInterface = interfaces[i];
            } else {
                rawInterface = rawType.getSuperclass();
                if (rawInterface == null) {
                    continue;
                }
            }
            Type resolved = resolveVariable(variable, rawInterface);
            if (resolved instanceof Class || resolved instanceof ParameterizedType) {
                return resolved;
            }

            if (resolved instanceof TypeVariable) {
                TypeVariable typeVariable = (TypeVariable) resolved;
                index = ArrayUtils.indexOf(rawInterface.getTypeParameters(), typeVariable);
                if (index < 0) {
                    throw new IllegalArgumentException("Can't resolve type variable:" + typeVariable);
                }
                Type type = i < genericInterfaces.length ? genericInterfaces[i] : rawType.getGenericSuperclass();
                if (type instanceof Class) {
                    return Object.class;
                }
                if (type instanceof ParameterizedType) {
                    return ((ParameterizedType) type).getActualTypeArguments()[index];
                }
                throw new IllegalArgumentException("Unsupported type: " + type);
            }
        }
        return null;
    }

    public static Class getComponentType(Type type) {
        return getComponentType(type, null, -1);
    }

    public static Class getComponentType(Type type, Class implClass) {
        return getComponentType(type, implClass, -1);
    }

    public static Class getComponentType(Type type, int index) {
        return getComponentType(type, null, index);
    }

    /**
     * Returns the component type of the given type.
     * Returns null if given type does not have a single
     * component type. For example the following types all have the
     * component-type MyClass:
     * 
    *
  • MyClass[]
  • *
  • List<MyClass>
  • *
  • Foo<? extends MyClass>
  • *
  • Bar<? super MyClass>
  • *
  • <T extends MyClass> T[]
  • *
* * Index represents the index of component type, when class supports more then one. * For example, Map<A, B> has 2 component types. If index is 0 or positive, * than it represents order of component type. If the value is negative, then it represents * component type counted from the end! Therefore, the default value of -1 * always returns the last component type. * * @param type - type * @param implClass - implementation class * @param index - index of component type * @return component type */ public static Class getComponentType(Type type, Class implClass, int index) { if (type instanceof Class) { Class clazz = (Class) type; if (clazz.isArray()) { return clazz.getComponentType(); } } else if (type instanceof ParameterizedType) { ParameterizedType pt = (ParameterizedType) type; Type[] generics = pt.getActualTypeArguments(); if (index < 0) { index = generics.length + index; } if (index < generics.length) { return getRawType(generics[index], implClass); } } else if (type instanceof GenericArrayType) { GenericArrayType gat = (GenericArrayType) type; return getRawType(gat.getGenericComponentType(), implClass); } return null; } /** * @see #getComponentType(java.lang.reflect.Type) */ public static Class getGenericSupertype(Class type) { return getComponentType(type.getGenericSuperclass()); } /** * Returns generic supertype for given class and 0-based index. * @see #getComponentType(java.lang.reflect.Type, int) */ public static Class getGenericSupertype(Class type, int index) { return getComponentType(type.getGenericSuperclass(), null, index); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy