集册 Java实例教程 从给定的Type对象中提取泛型类型。

从给定的Type对象中提取泛型类型。

欢马劈雪     最近更新时间:2020-01-02 10:19:05

593
从给定的Type对象中提取泛型类型。

/*

 * $Id: GenericsUtils.java 20321 2010-11-24 15:21:24Z dfeist $

 * --------------------------------------------------------------------------------------

 * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com

 *

 * The software in this package is published under the terms of the CPAL v1.0

 * license, a copy of which has been included with this distribution in the

 * LICENSE.txt file.

 *///来自 N o w J a v a . c o m - 时  代  Java

import java.lang.reflect.Array;

import java.lang.reflect.Field;

import java.lang.reflect.GenericArrayType;

import java.lang.reflect.Method;

import java.lang.reflect.ParameterizedType;

import java.lang.reflect.Type;

import java.lang.reflect.TypeVariable;

import java.lang.reflect.WildcardType;

import java.util.Collection;

import java.util.Map;


public class Main{

    /**

     * Extract the generic type from the given Type object.

     *

     * @param methodParam  the method parameter specification

     * @param type         the Type to check

     * @param source       the source collection/map Class<?> that we check

     * @param typeIndex    the index of the actual type argument

     * @param nestingLevel the nesting level of the target type

     * @param currentLevel the current nested level

     * @return the generic type as Class, or <code>null</code> if none

     */

    private static Class<?> extractType(MethodParameter methodParam,

            Type type, Class<?> source, int typeIndex, int nestingLevel,

            int currentLevel) {

        Type resolvedType = type;

        if (type instanceof TypeVariable<?> && methodParam != null

                && methodParam.typeVariableMap != null) {

            Type mappedType = methodParam.typeVariableMap.get(type);

            if (mappedType != null) {
            /*
            nowjava.com
            */

                resolvedType = mappedType;

            }

        }

        if (resolvedType instanceof ParameterizedType) {

            return extractTypeFromParameterizedType(methodParam,

                    (ParameterizedType) resolvedType, source, typeIndex,

                    nestingLevel, currentLevel);

        } else if (resolvedType instanceof Class<?>) {

            Class<?> resolvedClass = (Class<?>) resolvedType;

            return extractTypeFromClass(methodParam, resolvedClass, source,

                    typeIndex, nestingLevel, currentLevel);

        } else {

            return null;

        }

    }

    /**

     * Extract the generic type from the given ParameterizedType object.

     *

     * @param methodParam  the method parameter specification

     * @param ptype        the ParameterizedType to check

     * @param source       the expected raw source type (can be <code>null</code>)

     * @param typeIndex    the index of the actual type argument

     * @param nestingLevel the nesting level of the target type

     * @param currentLevel the current nested level

     * @return the generic type as Class, or <code>null</code> if none

     */

    private static Class<?> extractTypeFromParameterizedType(

            MethodParameter methodParam, ParameterizedType ptype,

            Class<?> source, int typeIndex, int nestingLevel,

            int currentLevel) {


        if (!(ptype.getRawType() instanceof Class<?>)) {

            return null;

        }


        Class<?> rawType = (Class<?>) ptype.getRawType();

        Type[] paramTypes = ptype.getActualTypeArguments();

        if (nestingLevel - currentLevel > 0) {

            int nextLevel = currentLevel + 1;

            Integer currentTypeIndex = (methodParam != null ? methodParam

                    .getTypeIndexForLevel(nextLevel) : null);

            // Default is last parameter type: Collection element or Map value.

            int indexToUse = (currentTypeIndex != null ? currentTypeIndex

                    : paramTypes.length - 1);

            Type paramType = paramTypes[indexToUse];

            return extractType(methodParam, paramType, source, typeIndex,

                    nestingLevel, nextLevel);

        }

        if (source != null && !source.isAssignableFrom(rawType)) {

            return null;

        }

        Class<?> fromSuperclassOrInterface = extractTypeFromClass(

                methodParam, rawType, source, typeIndex, nestingLevel,

                currentLevel);

        if (fromSuperclassOrInterface != null) {

            return fromSuperclassOrInterface;

        }

        if (paramTypes == null || typeIndex >= paramTypes.length) {

            return null;

        }

        Type paramType = paramTypes[typeIndex];

        if (paramType instanceof TypeVariable<?> && methodParam != null

                && methodParam.typeVariableMap != null) {

            Type mappedType = methodParam.typeVariableMap.get(paramType);

            if (mappedType != null) {

                paramType = mappedType;

            }

        }

        if (paramType instanceof WildcardType) {

            WildcardType wildcardType = (WildcardType) paramType;

            Type[] upperBounds = wildcardType.getUpperBounds();

            if (upperBounds != null && upperBounds.length > 0

                    && !Object.class.equals(upperBounds[0])) {

                paramType = upperBounds[0];

            } else {

                Type[] lowerBounds = wildcardType.getLowerBounds();

                if (lowerBounds != null && lowerBounds.length > 0

                        && !Object.class.equals(lowerBounds[0])) {

                    paramType = lowerBounds[0];

                }

            }

        }

        if (paramType instanceof ParameterizedType) {

            paramType = ((ParameterizedType) paramType).getRawType();

        }

        if (paramType instanceof GenericArrayType) {

            // A generic array type... Let's turn it into a straight array type if possible.

            Type compType = ((GenericArrayType) paramType)

                    .getGenericComponentType();

            if (compType instanceof Class<?>) {

                Class<?> compClass = (Class<?>) compType;

                return Array.newInstance(compClass, 0).getClass();

            }

        } else if (paramType instanceof Class<?>) {

            // We finally got a straight Class...

            return (Class<?>) paramType;

        }

        return null;

    }

    /**

     * Extract the generic type from the given Class<?> object.

     *

     * @param clazz     the Class<?> to check

     * @param source    the expected raw source type (can be <code>null</code>)

     * @param typeIndex the index of the actual type argument

     * @return the generic type as Class, or <code>null</code> if none

     */

    private static Class<?> extractTypeFromClass(Class<?> clazz,

            Class<?> source, int typeIndex) {

        return extractTypeFromClass(null, clazz, source, typeIndex, 1, 1);

    }

    /**

     * Extract the generic type from the given Class<?> object.

     *

     * @param methodParam  the method parameter specification

     * @param clazz        the Class<?> to check

     * @param source       the expected raw source type (can be <code>null</code>)

     * @param typeIndex    the index of the actual type argument

     * @param nestingLevel the nesting level of the target type

     * @param currentLevel the current nested level

     * @return the generic type as Class, or <code>null</code> if none

     */

    private static Class<?> extractTypeFromClass(

            MethodParameter methodParam, Class<?> clazz, Class<?> source,

            int typeIndex, int nestingLevel, int currentLevel) {


        if (clazz.getName().startsWith("java.util.")) {

            return nu
展开阅读全文