com.jaspersoft.jasperserver.war.helper.GenericParametersHelper.java Source code

Java tutorial

Introduction

Here is the source code for com.jaspersoft.jasperserver.war.helper.GenericParametersHelper.java

Source

/*
 * Copyright (C) 2005 - 2014 TIBCO Software Inc. All rights reserved.
 * http://www.jaspersoft.com.
 *
 * Unless you have purchased  a commercial license agreement from Jaspersoft,
 * the following license terms  apply:
 *
 * This program is free software: you can redistribute it and/or  modify
 * it under the terms of the GNU Affero General Public License  as
 * published by the Free Software Foundation, either version 3 of  the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero  General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public  License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package com.jaspersoft.jasperserver.war.helper;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.HashMap;
import java.util.Map;

/**
 * <p></p>
 *
 * @author yaroslav.kovalchyk
 * @version $Id: GenericParametersHelper.java 47331 2014-07-18 09:13:06Z kklein $
 */
public class GenericParametersHelper {
    protected final static Log log = LogFactory.getLog(GenericParametersHelper.class);

    public static Class<?> getGenericTypeArgument(Class<?> classToParse, Class<?> genericClassToFind,
            Integer argumentIndex) {
        Class<?> result = null;
        ParameterizedType parameterizedType = null;
        Class<?> currentClass = classToParse;
        Map<String, Class<?>> currentParameterValues = new HashMap<String, Class<?>>();
        Type[] previousTypeArguments = null;
        while (parameterizedType == null) {
            final TypeVariable<? extends Class<?>>[] typeParameters = currentClass.getTypeParameters();
            currentParameterValues = getCurrentParameterValues(typeParameters, previousTypeArguments,
                    currentParameterValues);
            parameterizedType = findParametrizedType(currentClass, genericClassToFind, currentParameterValues);
            if (parameterizedType == null) {
                // current class doesn't extend/implement searched class directly. Should parse superclass
                final Type genericSuperclassType = currentClass.getGenericSuperclass();
                if (genericSuperclassType instanceof Class<?>) {
                    log.debug(classToParse.getName() + " is raw subclass of " + genericClassToFind.getName());
                    return null;
                }
                final ParameterizedType genericSuperclass = (ParameterizedType) genericSuperclassType;
                previousTypeArguments = genericSuperclass.getActualTypeArguments();
                currentClass = (Class<?>) genericSuperclass.getRawType();
            }
        }
        final Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
        if (actualTypeArguments[argumentIndex] instanceof Class<?>) {
            result = (Class<?>) actualTypeArguments[argumentIndex];
        } else if (actualTypeArguments[argumentIndex] instanceof TypeVariable) {
            result = currentParameterValues.get(((TypeVariable<?>) actualTypeArguments[argumentIndex]).getName());
        }
        if (result == null) {
            log.debug("Class " + classToParse.getName() + " has unsupported inheritance structure");
        }
        return result;
    }

    private static Map<String, Class<?>> getCurrentParameterValues(
            TypeVariable<? extends Class<?>>[] typeParameters, Type[] previousTypeArguments,
            Map<String, Class<?>> inputParameterValues) {
        Map<String, Class<?>> result = inputParameterValues != null ? inputParameterValues
                : new HashMap<String, Class<?>>();
        if (typeParameters != null && typeParameters.length > 0) {
            Map<String, Class<?>> currentParameterValues = new HashMap<String, Class<?>>();
            for (int i = 0; i < typeParameters.length; i++) {
                TypeVariable<? extends Class<?>> currentVariable = typeParameters[i];
                if (previousTypeArguments != null && previousTypeArguments.length > i) {
                    // fill current type parameters with arguments from subclass declaration
                    Type argumentType = previousTypeArguments[i];
                    if (argumentType instanceof Class<?>) {
                        currentParameterValues.put(currentVariable.getName(), (Class<?>) argumentType);
                        continue;
                    } else if (argumentType instanceof TypeVariable<?>
                            && result.containsKey(((TypeVariable<?>) argumentType).getName())) {
                        currentParameterValues.put(currentVariable.getName(),
                                result.get(((TypeVariable<?>) argumentType).getName()));
                        continue;
                    }
                }
                Class<?> variableClass = null;
                final Type[] bounds = currentVariable.getBounds();
                if (bounds != null && bounds.length > 0) {
                    if (bounds[0] instanceof Class<?>) {
                        variableClass = (Class<?>) bounds[0];
                    } else if (bounds[0] instanceof ParameterizedType) {
                        variableClass = (Class) ((ParameterizedType) bounds[0]).getRawType();
                    }
                }
                currentParameterValues.put(currentVariable.getName(), variableClass);
            }
            result.clear();
            result.putAll(currentParameterValues);
        }
        return result;
    }

    private static ParameterizedType findParametrizedType(Class<?> classToParse, Class<?> genericClassToFind,
            Map<String, Class<?>> inputParameterValues) {
        ParameterizedType type = null;
        if (genericClassToFind.isInterface()) {
            final Type[] genericInterfaces = classToParse.getGenericInterfaces();
            if (genericInterfaces != null && genericInterfaces.length > 0) {
                for (Type genericInterface : genericInterfaces) {
                    if (genericInterface == genericClassToFind) {
                        throw new IllegalArgumentException(classToParse.getName() + " is raw implementation of "
                                + genericClassToFind.getName());
                    }
                    if (genericInterface instanceof ParameterizedType) {
                        ParameterizedType currentParametrizedType = (ParameterizedType) genericInterface;
                        Map<String, Class<?>> currentParameterValues = new HashMap<String, Class<?>>(
                                inputParameterValues);
                        if (currentParametrizedType.getRawType() == genericClassToFind) {
                            type = (ParameterizedType) genericInterface;
                        } else {
                            currentParameterValues = getCurrentParameterValues(
                                    ((Class<?>) currentParametrizedType.getRawType()).getTypeParameters(),
                                    currentParametrizedType.getActualTypeArguments(),
                                    new HashMap<String, Class<?>>(inputParameterValues));
                            type = findParametrizedType((Class<?>) currentParametrizedType.getRawType(),
                                    genericClassToFind, currentParameterValues);
                        }
                        if (type != null) {
                            inputParameterValues.clear();
                            inputParameterValues.putAll(currentParameterValues);
                            break;
                        }
                    }
                }
            }
        } else {
            final Type genericSuperclass = classToParse.getGenericSuperclass();
            if (genericSuperclass == genericClassToFind) {
                log.debug(classToParse.getName() + " is raw subclass of " + genericClassToFind.getName());
            } else if (genericSuperclass instanceof ParameterizedType
                    && ((ParameterizedType) genericSuperclass).getRawType() == genericClassToFind) {
                type = (ParameterizedType) genericSuperclass;
            }
        }
        return type;
    }
}