com.google.code.guice.repository.spi.TypeUtil.java Source code

Java tutorial

Introduction

Here is the source code for com.google.code.guice.repository.spi.TypeUtil.java

Source

/*
 * Copyright (C) 2012 the original author or authors.
 * See the notice.md file distributed with this work for additional
 * information regarding copyright ownership.
 *
 * 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 com.google.code.guice.repository.spi;

import net.jcip.annotations.ThreadSafe;
import org.springframework.util.Assert;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

/**
 * Utility for resolving actual classes of type parameters.
 *
 * @author Alexey Krylov
 * @see #getFirstTypeParameterClass(Class)
 * @see #getTypeParameterClass(Class, int)
 * @see #getTypeParameterClass(Class, Class)
 * @since 22.11.12
 */
@ThreadSafe
public class TypeUtil {

    /*===========================================[ CONSTRUCTORS ]=================*/

    private TypeUtil() {
    }

    /*===========================================[ CLASS METHODS ]================*/

    /**
     * Finds and returns class of first parametrization parameter.
     *
     * @param aClass generic class
     *
     * @return parameter class or {@code null} if parameter can't be found
     *
     * @throws IllegalArgumentException if specified {@code aClass} is null
     */
    public static Class getFirstTypeParameterClass(Class aClass) {
        Assert.notNull(aClass);
        return getTypeParameterClass(aClass, 0);
    }

    /**
     * Finds and returns class of N parametrization parameter.
     *
     * @param aClass         generic class
     * @param parameterIndex parameter index
     *
     * @return parameter class or {@code null} if parameter can't be found
     *
     * @throws IllegalArgumentException if specified {@code aClass} is null or {@code parameterIndex} < 0
     */
    public static Class getTypeParameterClass(Class aClass, int parameterIndex) {
        Assert.notNull(aClass);
        Assert.isTrue(parameterIndex >= 0);

        List<Type> types = new ArrayList<Type>();

        // check interfaces
        getGenericInterfacesActualTypes(types, aClass);

        Class result = findAppropriateType(types, parameterIndex);
        if (result == null) {
            types.clear();
            // check superclasses
            getGenericSuperclassActualTypes(types, aClass);
        }
        return findAppropriateType(types, parameterIndex);
    }

    public static void getGenericInterfacesActualTypes(Collection<Type> types, Class aClass) {
        if (aClass != null && types != null) {
            Type[] interfaces = aClass.getGenericInterfaces();
            for (Type anInterface : interfaces) {
                if (anInterface instanceof ParameterizedType) {
                    ParameterizedType parameterizedType = (ParameterizedType) anInterface;
                    Type[] actualTypes = parameterizedType.getActualTypeArguments();
                    types.addAll(Arrays.asList(actualTypes));
                } else if (anInterface instanceof Class) {
                    Class typeClass = (Class) anInterface;
                    getGenericInterfacesActualTypes(types, typeClass);
                }
            }
        }
    }

    public static void getGenericSuperclassActualTypes(Collection<Type> types, Class aClass) {
        if (aClass != null && types != null) {
            Type superclass = aClass.getGenericSuperclass();
            if (superclass instanceof ParameterizedType) {
                ParameterizedType parameterizedType = (ParameterizedType) superclass;
                Type[] interfaces = parameterizedType.getActualTypeArguments();
                types.addAll(Arrays.asList(interfaces));
            } else if (superclass instanceof Class) {
                Class sClass = (Class) superclass;
                getGenericInterfacesActualTypes(types, sClass);
                getGenericSuperclassActualTypes(types, aClass.getSuperclass());
            }
        }
    }

    private static Class findAppropriateType(List<Type> types, int parameterIndex) {
        for (int i = 0; i < types.size(); i++) {
            if (i == parameterIndex) {
                Type type = types.get(i);
                if (type instanceof Class) {
                    return (Class) type;
                }
            }
        }
        return null;
    }

    /**
     * Finds and returns class of specified generic parametrization class.
     *
     * @param aClass                generic class
     * @param genericParameterClass generic parametrization class
     *
     * @return parameter class or {@code null} if parameter can't be found
     *
     * @throws IllegalArgumentException if specified {@code aClass}  or {@code genericParameterClass} is null
     */
    public static <T> Class<T> getTypeParameterClass(Class aClass, Class<T> genericParameterClass) {
        Assert.noNullElements(new Object[] { aClass, genericParameterClass });

        Collection<Type> types = new ArrayList<Type>();

        // check interfaces
        getGenericInterfacesActualTypes(types, aClass);

        Class result = findAppropriateType(types, genericParameterClass);
        if (result == null) {
            types.clear();
            // check superclasses
            getGenericSuperclassActualTypes(types, aClass);
        }
        return findAppropriateType(types, genericParameterClass);
    }

    private static <T> Class<T> findAppropriateType(Iterable<Type> types, Class<T> genericParameterClass) {
        for (Type type : types) {
            if (type instanceof Class && genericParameterClass.isAssignableFrom((Class<?>) type)) {
                return (Class) type;
            }
        }
        return null;
    }
}