Skip to content

Instantly share code, notes, and snippets.

@jianyun8023
Created November 16, 2018 06:10
Show Gist options
  • Save jianyun8023/ebffbf7d64513e40039734fa78395843 to your computer and use it in GitHub Desktop.
Save jianyun8023/ebffbf7d64513e40039734fa78395843 to your computer and use it in GitHub Desktop.
Java获取编译时泛型工具
package cc.yihy.util;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.text.MessageFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Stream;
/**
* 分析编译时泛型参数,获取class
*
* @author yihy Create at 2018/11/12
*/
public class GenericToClassUtil {
private static Map<String, Class<?>> classMap = new ConcurrentHashMap<>();
public static <T, A> Class<T> getGeneric(Class<? extends A> thisClass, Class<A> superClass, int genericIndex) {
String key = thisClass.getName() + "_" + superClass.getName() + "_" + genericIndex;
return (Class<T>) classMap.computeIfAbsent(key, k -> getT(thisClass, superClass, genericIndex));
}
private static <T, A> Class<T> getT(Class<? extends A> thisClass, Class<A> superClass, int genericIndex) {
ParameterizedType type = findTypeBySuperClass(thisClass, superClass);
return getClassByIndex(thisClass, genericIndex, type);
}
private static <T, A> Class<T> getClassByIndex(Class<? extends A> thisClass, int genericIndex,
ParameterizedType type) {
Type actualTypeArgument = type.getActualTypeArguments()[genericIndex];
validTypeIsClass(thisClass, actualTypeArgument);
return (Class<T>) actualTypeArgument;
}
private static <A> void validTypeIsClass(Class<? extends A> thisClass, Type actualTypeArgument) {
if (actualTypeArgument instanceof Class) {
return;
}
throw new RuntimeException(MessageFormat.format("不支持自动推断运行时的泛型,请重写 {0} 类的获取泛型类的方法", thisClass.getName()));
}
private static <A> Type[] getGenericType(Class<? extends A> thisClass, Class<A> superClass) {
Type[] generic;
if (superClass.isInterface()) {
generic = thisClass.getGenericInterfaces();
} else {
generic = new Type[1];
generic[0] = thisClass.getGenericSuperclass();
}
return generic;
}
private static <A> ParameterizedType findTypeBySuperClass(Class<? extends A> thisClass, Class<A> superClass) {
Type[] generic = getGenericType(thisClass, superClass);
Optional<ParameterizedType> typeOptional = Stream.of(generic).filter(t -> t instanceof ParameterizedType)
.map(t -> (ParameterizedType) t).filter(type -> Objects.nonNull(type.getRawType()))
.filter(type -> type.getRawType().equals(superClass)).findAny();
if (!typeOptional.isPresent()) {
throw buildException(generic, thisClass, superClass);
}
return typeOptional.get();
}
private static <A> RuntimeException buildException(Type[] generic, Class<? extends A> thisClass,
Class<A> superClass) {
Optional<? extends Class<?>> associationClass = findAssociationClass(generic, thisClass, superClass);
if (!associationClass.isPresent()) {
return new IllegalStateException(
MessageFormat.format("{0} 没有直接继承/实现 {1}\n解决办法: 1, {0} 重写 {1} 中的获取泛型类的方法 2, {0} 直接继承或实现 {1}",
thisClass.getName(), superClass.getName()));
}
String name = associationClass.get().getName();
return new RuntimeException(MessageFormat.format(
"{1} 需要重写 {2} 的分析泛型类方法\n解决办法: 1, 重写 {1} 类的泛型推断方法 2, 重写 {0} 的泛型推断方法 3, 让 {0} 直接继承或实现 {2}",
thisClass.getName(), name, superClass.getName()));
}
/**
* 查找一个类,既实现了superClass,又是thisClass的父类
*
* @param <A> 基类
* @param generic this类的父类信息
* @param thisClass 当前实现类
* @param superClass this类的基类
* @return 实现了superClass,又是thisClass父类的类
*/
private static <A> Optional<? extends Class<?>> findAssociationClass(Type[] generic, Class<? extends A> thisClass,
Class<A> superClass) {
List<Type> list = new ArrayList<>(Arrays.asList(generic));
if (superClass.isInterface()) {
list.add(thisClass.getGenericSuperclass());
}
Optional<? extends Class<?>> any = list.stream().filter(t -> t instanceof ParameterizedType)
.map(t -> (ParameterizedType) t).filter(type -> Objects.nonNull(type.getRawType()))
.map(type -> (Class<?>) type.getRawType()).filter(superClass::isAssignableFrom).findAny();
return any;
}
}
@jianyun8023
Copy link
Author

可以获取编译时泛型的class,父类可以是接口或类,子类需要声明出具体的泛型。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment