类泛型工具类 - 【【【只作用于父类(非接口)有泛型的类】】】
本帖最后由 littlerookie 于 2023-7-27 09:23 编辑```
package xxx.xxx.xxx;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import lombok.Data;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Set;
/**
* @Description: 类泛型工具类 - 【【【只作用于父类(非接口)有泛型的类】】】
*/
@Slf4j
public enum ClassGenericTypeUtil {
;
/**
* @param sort 泛型序号值 从0开始
* @Param clazz 获取类的class
* @description 获取指定顺序泛型类型 - 不可以获取嵌套层级的泛型
*/
public static Class getGenericType(Class<?> clazz, int sort) {
try {
if (Objects.isNull(clazz)) {
return null;
}
Type superclass = clazz.getGenericSuperclass();
if (superclass instanceof Class) {
throw new IllegalArgumentException("内部错误:在没有实际类型信息的情况下构造getGenericType");
} else {
ParameterizedType parameterizedType = (ParameterizedType) superclass;
Type[] typeList = parameterizedType.getActualTypeArguments();
String typeName = typeList.getTypeName();
// <> 必定是成对出现的
if (typeName.contains(SymbolConstants.Symbol.En.LEFT_ANGLE_BRACKETS)) {
typeName = typeName.split(SymbolConstants.Symbol.En.COMMA);
}
return Class.forName(typeName);
}
} catch (Exception e) {
log.error("【获取泛型出现异常】:", e);
}
return null;
}
/**
* @param type 泛型类型实例
* @description 泛型类型实例 获取 泛型树形结构
*/
public static List<GenericNode> getGenericNodeTree(Type type) {
return ClassGenericTypeUtil.genericNodeList(type.getTypeName(), Boolean.FALSE);
}
/**
* @param genericTypeName 泛型类型字符串
* @description 泛型类型字符串 获取 泛型树形结构
* genericTypeName可能的复杂示例:
* List<Map<Map<String, Function<String, Object>>, Map<String, String>>>
* java.util.List<java.util.Map<java.util.Map<java.lang.String, java.util.function.Function<java.lang.String, java.lang.Object>>, java.util.Map<java.lang.String, java.lang.String>>>
*/
public static List<GenericNode> getGenericNodeTree(String genericTypeName) {
return ClassGenericTypeUtil.genericNodeList(genericTypeName, Boolean.FALSE);
}
/**
* @param genericTypeName 泛型类型字符串
* @description 校验泛型类型字符串是否符合要求,【目前暂无有效规则判断】,所以默认返回true
* genericTypeName可能的复杂示例:
* List<Map<Map<String, Function<String, Object>>, Map<String, String>>>
* java.util.List<java.util.Map<java.util.Map<java.lang.String, java.util.function.Function<java.lang.String, java.lang.Object>>, java.util.Map<java.lang.String, java.lang.String>>>
*/
private static Boolean validGenericTypeName(String genericTypeName) {
return Boolean.TRUE;
}
/**
* @param genericTypeName 泛型类型字符串
* @param innerInvoke 是否内部调用 true 内部调用 false 非内部调用
* @description 泛型类型字符串 获取 泛型树形结构
* genericTypeName可能的复杂示例:
* List<Map<Map<String, Function<String, Object>>, Map<String, String>>>
* java.util.List<java.util.Map<java.util.Map<java.lang.String, java.util.function.Function<java.lang.String, java.lang.Object>>, java.util.Map<java.lang.String, java.lang.String>>>
*/
private static List<GenericNode> genericNodeList(String genericTypeName, Boolean innerInvoke) {
if (innerInvoke == null || Boolean.FALSE.equals(innerInvoke)) {
//只会在首次调用的时候校验,之后就不会校验了
innerInvoke = ClassGenericTypeUtil.validGenericTypeName(genericTypeName);
}
return ClassGenericTypeUtil.genericNodeList(genericTypeName, Boolean.FALSE, innerInvoke);
}
/**
* @param genericTypeName 泛型类型字符串
* @param parseParallelNode 是否解析平行节点 true 解析平行节点 false 不解析平行节点 (genericTypeName 有可能为【java.lang.String, java.lang.Object】)
* @param innerInvoke 是否内部调用 true 内部调用 false 非内部调用
* @description 泛型类型字符串 获取 泛型树形结构
* genericTypeName可能的复杂示例:
* List<Map<Map<String, Function<String, Object>>, Map<String, String>>>
* java.util.List<java.util.Map<java.util.Map<java.lang.String, java.util.function.Function<java.lang.String, java.lang.Object>>, java.util.Map<java.lang.String, java.lang.String>>>
*/
private static List<GenericNode> genericNodeList(String genericTypeName, Boolean parseParallelNode, Boolean innerInvoke) {
if (StrUtil.isBlank(genericTypeName)) {
return Collections.emptyList();
}
if (ObjectUtil.isNull(innerInvoke) || Boolean.FALSE.equals(innerInvoke)) {
//只会在首次调用的时候校验,之后就不会校验了
innerInvoke = ClassGenericTypeUtil.validGenericTypeName(genericTypeName);
}
if (ObjectUtil.isNull(parseParallelNode)) {
parseParallelNode = false;
}
//genericTypeName 可能场景如下
//java.util.List<java.util.Map<java.util.Map<java.lang.String, java.util.function.Function<java.lang.String, java.lang.Object>>, java.util.Map<java.lang.String, java.lang.String>>>
List<GenericNode> resultList = CollUtil.newArrayList();
try {
//基于 <> 必会成对出现前提
//含 < 即表示至少有一个子节点
if (genericTypeName.contains(SymbolConstants.Symbol.En.LEFT_ANGLE_BRACKETS) && genericTypeName.contains(SymbolConstants.Symbol.En.RIGHT_ANGLE_BRACKETS)) {
//parseParallelNode = false 表示 是否解析平行节点 即 java.lang.String, java.lang.Object 场景
if (!genericTypeName.contains(SymbolConstants.Symbol.En.COMMA) || !parseParallelNode) {
GenericNode currentNode = new GenericNode();
//先去除最外层的 <>
String currentClassName = genericTypeName.substring(0, genericTypeName.indexOf(SymbolConstants.Symbol.En.LEFT_ANGLE_BRACKETS));
//获取当前节点的 Class 实例
currentNode.setClazz(Class.forName(currentClassName));
//获取子节点的 Class 实例集
//replace 为 <....> 中的内容
String childNode = genericTypeName.substring(genericTypeName.indexOf(SymbolConstants.Symbol.En.LEFT_ANGLE_BRACKETS) + 1, genericTypeName.lastIndexOf(SymbolConstants.Symbol.En.RIGHT_ANGLE_BRACKETS));
//子节点必须要校验是否有平行节点
currentNode.setNodeList(ClassGenericTypeUtil.genericNodeList(childNode, innerInvoke, Boolean.TRUE));
resultList.add(currentNode);
} else {
//解析 genericTypeName 中的泛型类型
String[] genericTypeNameSplit = genericTypeName.split(SymbolConstants.Symbol.En.COMMA);
List<String> nodeStringList = CollUtil.newArrayList();
StringBuilder stringBuilder = new StringBuilder();
boolean first = true;
for (String childGenericTypeName : genericTypeNameSplit) {
if (!first) {
stringBuilder.append(SymbolConstants.Symbol.En.COMMA);
} else {
first = false;
}
stringBuilder.append(childGenericTypeName);
if (!stringBuilder.toString().contains(SymbolConstants.Symbol.En.LEFT_ANGLE_BRACKETS) ||
StrUtil.count(stringBuilder.toString(), SymbolConstants.Symbol.En.LEFT_ANGLE_BRACKETS) == StrUtil.count(stringBuilder.toString(), SymbolConstants.Symbol.En.RIGHT_ANGLE_BRACKETS)) {
String trimString = stringBuilder.toString().trim();
if (StrUtil.isNotBlank(trimString)) {
nodeStringList.add(trimString);
}
//清空 stringBuilder 内容
stringBuilder.delete(0, stringBuilder.length());
first = true;
}
}
//将 genericTypeName 拆分成多个 genericTypeName 然后递归调用 此方法
if (CollUtil.isEmpty(nodeStringList)) {
return resultList;
}
final Boolean innerInvokeFinal = innerInvoke;
nodeStringList.forEach(nodeString -> {
//nodeString 由上述赋值可知 必定是有效值, 是一个具体确定的类型 但是可能也含泛型 返回的数据 不为空的话必定有有且仅有一条数据
//示例:java.util.Map<java.util.Map<java.lang.String, java.util.function.Function<java.lang.String, java.lang.Object>>>
List<GenericNode> nodeList = ClassGenericTypeUtil.genericNodeList(nodeString, innerInvokeFinal);
if (CollUtil.isEmpty(nodeList)) {
return;
}
resultList.add(nodeList.get(0));
});
}
} else if (genericTypeName.contains(SymbolConstants.Symbol.En.COMMA)) {
//有可能 genericTypeName = java.lang.String, java.lang.String类型的字符串
String[] genericTypeNameSplit = genericTypeName.split(SymbolConstants.Symbol.En.COMMA);
for (String genericTypeNameParallel : genericTypeNameSplit) {
List<GenericNode> nodeList = ClassGenericTypeUtil.genericNodeList(genericTypeNameParallel.trim(), innerInvoke);
if (CollUtil.isEmpty(nodeList)) {
continue;
}
resultList.add(nodeList.get(0));
}
} else {
resultList.add(new GenericNode().setClazz(Class.forName(genericTypeName)));
}
} catch (Exception e) {
log.error("出现异常:", e);
}
return resultList;
}
@Data
@Accessors(chain = true)
public static class GenericNode implements Serializable {
/**
* 当前节点的泛型的class类型
*/
private Class<?> clazz;
/**
* 子泛型的泛型类型集
*/
private List<GenericNode> nodeList;
/**
* @description 将此节点及其子节点的树形结构转换成一个节点Set集合 - 去重
*/
public Set<GenericNode> treeToSet() {
Set<GenericNode> resultList = CollUtil.newHashSet();
if (CollUtil.isEmpty(this.nodeList)) {
resultList.add(this);
} else {
this.nodeList.forEach(node -> resultList.addAll(node.treeToSet()));
}
return resultList;
}
/**
* @description 将此节点及其子节点的树形结构转换成一个节点List集合 - 去重
*/
public List<GenericNode> treeToList() {
return CollUtil.newArrayList(this.treeToSet());
}
}
public interface SymbolConstants {
interface Symbol {
public interface Cn {
String COMMA = ",";
String COLON = ":";
}
interface En {
String COMMA = ",";
String COLON = ":";
String HYPHEN = "-";
String UNDERLINE = "_";
String LEFT_ANGLE_BRACKETS = "<";
String RIGHT_ANGLE_BRACKETS = ">";
}
}
}
}
```
感谢分享。学习一下。 拿代码段 套一下比较好 pjy612 发表于 2023-7-27 09:10
拿代码段 套一下比较好
弄好了,之前一直没找到在哪{:1_907:} 感谢楼主分享 请问该工具类有什么应用场景,可以简单说一下作用吗
页:
[1]