吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 934|回复: 5
收起左侧

[Java 原创] 类泛型工具类 - 【【【只作用于父类(非接口)有泛型的类】】】

[复制链接]
littlerookie 发表于 2023-7-26 22:22
本帖最后由 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[sort].getTypeName();
                // <> 必定是成对出现的
                if (typeName.contains(SymbolConstants.Symbol.En.LEFT_ANGLE_BRACKETS)) {
                    typeName = typeName.split(SymbolConstants.Symbol.En.COMMA)[0];
                }
                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 = ">";
            }
        }
    }

}

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

youxiaxy 发表于 2023-7-27 08:11
感谢分享。学习一下。
pjy612 发表于 2023-7-27 09:10
 楼主| littlerookie 发表于 2023-7-27 09:24
qeadzc 发表于 2023-7-30 23:44
感谢楼主分享
harglo 发表于 2023-8-3 09:49
请问该工具类有什么应用场景,可以简单说一下作用吗
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-24 22:26

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表