/**
* Copyright (C) 2010 Michael Mosmann <michael@mosmann.de>
*
* 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 de.flapdoodle.mongoom.mapping.converter.generics;
import java.lang.reflect.Array;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.HashMap;
import java.util.Map;
import de.flapdoodle.mongoom.exceptions.MappingException;
public class TypeExtractor {
// http://www.artima.com/weblogs/viewpost.jsp?thread=208860
public static Type getGenericInterface(Class<?> declaringClass, Class<?> interfaze) {
Type[] genericInterfaces = declaringClass.getGenericInterfaces();
for (Type t : genericInterfaces) {
Class<?> typeClass = getClass(t);
if (interfaze.isAssignableFrom(typeClass)) {
return t;
}
}
return null;
}
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;
}
}
public static <T> Map<Type, Type> getTypeArgumentMap(Type childClass) {
Map<Type, Type> resolvedTypes = new HashMap<Type, Type>();
Type type = childClass;
Class<?> baseClass = Object.class;
while (!getClass(type).equals(baseClass)) {
if (type instanceof Class) {
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();
}
}
}
return resolvedTypes;
}
public static Class<?> getTypeclass(Class<?> declaringClass, Type genericType) {
Type result = getParameterizedClass(declaringClass, genericType, 0);
return (Class<?>) (result instanceof Class ? result : null);
}
public static Type getParameterizedClass(Class<?> declaringClass, Type genericType, final int index) {
if (genericType instanceof ParameterizedType) {
ParameterizedType ptype = (ParameterizedType) genericType;
if ((ptype.getActualTypeArguments() == null) || (ptype.getActualTypeArguments().length <= index)) {
return null;
}
Type paramType = ptype.getActualTypeArguments()[index];
if (paramType instanceof GenericArrayType) {
Class arrayType = (Class) ((GenericArrayType) paramType).getGenericComponentType();
return Array.newInstance(arrayType, 0).getClass();
} else {
if (paramType instanceof ParameterizedType) {
ParameterizedType paramPType = (ParameterizedType) paramType;
// return (Class) paramPType.getRawType();
return paramPType;
} else {
if (paramType instanceof TypeVariable) {
Map<Type, Type> typeArgumentMap = getTypeArgumentMap(declaringClass);
TypeVariable typeVar = (TypeVariable) paramType;
Type type = typeArgumentMap.get(typeVar);
if (type != null) {
return type;
} else {
throw new MappingException("Generic Typed Class not supported: <" + ((TypeVariable) paramType).getName()
+ "> = " + ((TypeVariable) paramType).getBounds()[0]);
}
} else {
if (paramType instanceof Class) {
return (Class) paramType;
} else {
throw new MappingException("Unknown type... pretty bad... call for help, wave your hands... yeah!");
}
}
}
}
}
return null;
}
}