/* * Copyright 2012 Jason Miller * * 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 jj.util; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; /** * Some methods for dealing with generic parameters, like the * TypeLiteral from Guice, more or less * * @author jason * */ public enum GenericUtils { ; public static Type extractTypeParameter(Class<?> subclass, Class<?> superclass, String typeVariableName) { assert subclass != null : "null subclass"; assert superclass != null : "null superclass"; assert superclass != Object.class : "superclass cannot be Object"; assert !superclass.isInterface() : "superclass must be a class, not an interface. for now anyway"; int index = findTypeVariableIndex(superclass, typeVariableName); assert (index < superclass.getTypeParameters().length) : "couldn't find the type variable"; return extractTypeParameter(subclass, superclass, index); } public static Class<?> extractTypeParameterAsClass(Class<?> subclass, Class<?> superclass, String typeVariableName) { Type result = extractTypeParameter(subclass, superclass, typeVariableName); assert result instanceof Class : "parameter at index is not fully specified " + result; return (Class<?>)result; } private static int findTypeVariableIndex(Class<?> superclass, String typeVariableName) { int index = 0; for (TypeVariable<?> tv : superclass.getTypeParameters()) { if (typeVariableName.equals(tv.getName())) { break; } index++; } return index; } /** * returns the {@link Type} found at a given index of type parameters for a parameterized * superclass of a given subclass. Does not yet handle interfaces. * * @param subclass The leaf class that extends some generic superclass * @param superclass The extended class expecting reified type parameters * @param index The index of the type parameter in the superclass * @return */ private static Type extractTypeParameter(Class<?> subclass, Class<?> superclass, int index) { Class<?> current = subclass; while (current.getSuperclass() != superclass && current.getSuperclass() != Object.class) { current = current.getSuperclass(); } assert current.getSuperclass() == superclass : "couldn't find target in hierarchy"; Type targetType = current.getGenericSuperclass(); assert targetType instanceof ParameterizedType : "doesn't have a generic superclass"; ParameterizedType parameterized = (ParameterizedType)targetType; assert parameterized.getActualTypeArguments().length > index : "not enough type parameters in target for index"; Type result = parameterized.getActualTypeArguments()[index]; return result instanceof Class ? result : extractTypeParameter(subclass, current, result.toString()); } }