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

org.mockito.internal.util.reflection.GenericTypeExtractor Maven / Gradle / Ivy

/*
 * Copyright (c) 2016 Mockito contributors
 * This program is made available under the terms of the MIT License.
 */
package org.mockito.internal.util.reflection;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

/**
 * Attempts to extract generic type of given target base class or target interface
 */
public class GenericTypeExtractor {

    /**
     * Extract generic type of root class either from the target base class or from target base interface.
     * Examples:
     *  

* 1. Foo implements IFoo[Integer]: * genericTypeOf(Foo.class, Object.class, IFoo.class) returns Integer *

* 2. Foo extends BaseFoo[String]: * genericTypeOf(Foo.class, BaseFoo.class, IFoo.class) returns String *

* 3. Foo extends BaseFoo; BaseFoo implements IFoo[String]: * genericTypeOf(Foo.class, BaseFoo.class, Object.class) returns String *

* Does not support nested generics, only supports single type parameter. * * @param rootClass - the root class that the search begins from * @param targetBaseClass - if one of the classes in the root class' hierarchy extends this base class * it will be used for generic type extraction * @param targetBaseInterface - if one of the interfaces in the root class' hierarchy implements this interface * it will be used for generic type extraction * @return generic interface if found, Object.class if not found. */ public static Class genericTypeOf(Class rootClass, Class targetBaseClass, Class targetBaseInterface) { //looking for candidates in the hierarchy of rootClass Class match = rootClass; while(match != Object.class) { //check the super class first if (match.getSuperclass() == targetBaseClass) { return extractGeneric(match.getGenericSuperclass()); } //check the interfaces (recursively) Type genericInterface = findGenericInteface(match, targetBaseInterface); if (genericInterface != null) { return extractGeneric(genericInterface); } //recurse the hierarchy match = match.getSuperclass(); } return Object.class; } /** * Finds generic interface implementation based on the source class and the target interface. * Returns null if not found. Recurses the interface hierarchy. */ private static Type findGenericInteface(Class sourceClass, Class targetBaseInterface) { for (int i = 0; i < sourceClass.getInterfaces().length; i++) { Class inter = sourceClass.getInterfaces()[i]; if (inter == targetBaseInterface) { return sourceClass.getGenericInterfaces()[0]; } else { Type deeper = findGenericInteface(inter, targetBaseInterface); if (deeper != null) { return deeper; } } } return null; } /** * Attempts to extract generic parameter type of given type. * If there is no generic parameter it returns Object.class */ private static Class extractGeneric(Type type) { if (type instanceof ParameterizedType) { Type[] genericTypes = ((ParameterizedType) type).getActualTypeArguments(); if (genericTypes.length > 0 && genericTypes[0] instanceof Class) { return (Class) genericTypes[0]; } } return Object.class; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy