blob: 8652b62a78b8832447a5d1f2c50bed293a250941 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.giraph.utils;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Helper methods to get type arguments to generic classes. Courtesy of
* Ian Robertson (overstock.com). Make sure to use with abstract
* generic classes, not interfaces.
*/
public class ReflectionUtils {
/**
* Get the underlying class for a type, or null if the type is
* a variable type.
*
* @param type the type
* @return the underlying class
*/
public static Class<?> getClass(Type type) {
if (type instanceof Class) {
return (Class<?>) type;
}
else if (type instanceof ParameterizedType) {
return getClass(((ParameterizedType) type).getRawType());
}
else if (type instanceof GenericArrayType) {
Type componentType =
((GenericArrayType) type).getGenericComponentType();
Class<?> componentClass = getClass(componentType);
if (componentClass != null ) {
return Array.newInstance(componentClass, 0).getClass();
}
else {
return null;
}
}
else {
return null;
}
}
/**
* Get the actual type arguments a child class has used to extend a
* generic base class.
*
* @param baseClass the base class
* @param childClass the child class
* @return a list of the raw classes for the actual type arguments.
*/
public static <T> List<Class<?>> getTypeArguments(
Class<T> baseClass, Class<? extends T> childClass) {
Map<Type, Type> resolvedTypes = new HashMap<Type, Type>();
Type type = childClass;
// start walking up the inheritance hierarchy until we hit baseClass
while (! getClass(type).equals(baseClass)) {
if (type instanceof Class) {
// there is no useful information for us in raw types,
// so just keep going.
type = ((Class<?>) type).getGenericSuperclass();
}
else {
ParameterizedType parameterizedType = (ParameterizedType) type;
Class<?> rawType = (Class<?>) parameterizedType.getRawType();
Type[] actualTypeArguments =
parameterizedType.getActualTypeArguments();
TypeVariable<?>[] typeParameters = rawType.getTypeParameters();
for (int i = 0; i < actualTypeArguments.length; i++) {
resolvedTypes.put(typeParameters[i],
actualTypeArguments[i]);
}
if (!rawType.equals(baseClass)) {
type = rawType.getGenericSuperclass();
}
}
}
// finally, for each actual type argument provided to baseClass,
// determine (if possible)
// the raw class for that type argument.
Type[] actualTypeArguments;
if (type instanceof Class) {
actualTypeArguments = ((Class<?>) type).getTypeParameters();
}
else {
actualTypeArguments =
((ParameterizedType) type).getActualTypeArguments();
}
List<Class<?>> typeArgumentsAsClasses = new ArrayList<Class<?>>();
// resolve types by chasing down type variables.
for (Type baseType: actualTypeArguments) {
while (resolvedTypes.containsKey(baseType)) {
baseType = resolvedTypes.get(baseType);
}
typeArgumentsAsClasses.add(getClass(baseType));
}
return typeArgumentsAsClasses;
}
/** try to directly set a (possibly private) field on an Object */
public static void setField(Object target, String fieldname, Object value)
throws NoSuchFieldException, IllegalAccessException {
Field field = findDeclaredField(target.getClass(), fieldname);
field.setAccessible(true);
field.set(target, value);
}
/** find a declared field in a class or one of its super classes */
private static Field findDeclaredField(Class<?> inClass, String fieldname)
throws NoSuchFieldException {
while (!Object.class.equals(inClass)) {
for (Field field : inClass.getDeclaredFields()) {
if (field.getName().equalsIgnoreCase(fieldname)) {
return field;
}
}
inClass = inClass.getSuperclass();
}
throw new NoSuchFieldException();
}
}