AI编程可视化Java项目拆解第一弹,解析本地Java项目

news2025/2/27 17:02:48

之前分享过一篇使用 AI 可视化 Java 项目的文章,同步在 AI 破局星球、知乎、掘金等地方都分享了。

原文在这里AI 编程:可视化 Java 项目

有很多人感兴趣,我打算写一个系列文章拆解这个项目,大家多多点赞支持~

今天分享的是第一篇:如何使用 Spoon + JavaParser 工具解析一个本地的 Java 项目。

解析这一步骤是整个项目的基础,是为了获得整个 Java 项目的元数据。

这个元数据包含什么呢?1)整个项目的所有的类信息;2)整个项目的所有方法信息

方法信息

序号字段名称字段描述
1method_id方法唯一id标识
2project_name
3method_name方法名
4class_id方法所属类名
5param_type参数类型
6response_type返回类型
7begin_line方法内容开始行
8end_line方法内容结束行
9branch分支
10method_desc方法描述
11chat_descGPT 描述
12invoke_count被调用数量
13mermaid_flow_graph流程图数据
14flow_graph_ignored是否忽略流程图
15annotation_info注解信息
16annotation_type注解类型
17access_modifier修饰符

类信息

序号字段名称字段描述
1class_id类唯一标识
2class_name类名
3project_name项目唯一标识
4package_name包名
5branch分支
6class_type类的类型
7chat_descGPT 类描述
8class_desc类注释
9annotation_info类注解
10method_annotation_info方法注解信息
11annotation_type注解类型

怎么拿到整个项目的类信息和方法信息呢?

首先我们需要一个类解析器、一个方法解析器。使用 Java 的反射,我们就能拿到具体类和方法的详细信息。

类解析器代码:

public void execute(List<CtType<?>> elements) {
        classStructs = Lists.newArrayList();
        for (CtType<?> type : elements) {
            try {
                // 匿名内部类和泛型会跳过解析
                if (type.isAnonymous()) {
                    continue;
                }
                if (Objects.isNull(type.getPackage())) {
                    continue;
                }
                // 获取类的简单类名
                String simpleClassName = type.getSimpleName();
                // GPT 接口获取解释
                String chatDesc = "";
                // 获取类所属包
                String packageName = type.getPackage().getQualifiedName();
                // 获取类注释信息
                String classComment = type.getDocComment();
                // 判断接口还是类
                ClassType classType = getClassType(type);
                // 获取类注解信息
                List<AnnotationInfo> annotationInfos = Lists.newArrayList();
                List<CtAnnotation<?>> annotations = type.getAnnotations();
                for (CtAnnotation<?> annotation : annotations) {
                    AnnotationInfo annotationInfo = new AnnotationInfo();
                    String annotationName = annotation.getAnnotationType().getSimpleName();
                    annotationInfo.setAnnotationName(annotationName);
                    Map<String, CtExpression> annotationValues = annotation.getValues();
                    for (Map.Entry<String, CtExpression> entry : annotationValues.entrySet()) {
                        String attributeName = entry.getKey();
                        Object attributeValue = entry.getValue();
                        annotationInfo.addAttributeName(attributeName, attributeValue.toString());
                    }
                    annotationInfos.add(annotationInfo);
                }
                // 构造类元信息
                ClassStruct classStruct = buildClassStruct(simpleClassName, packageName, classType,
                        classComment, annotationInfos, chatDesc);
                classStructs.add(classStruct);
            } catch (Exception e) {
                log.error("class parse error, className ==>{}, errMsg ==>", type.getSimpleName(), e);
            }
        }
        // 类元信息入库
    }

方法解析器

public void execute(List<CtType<?>> elements) {
        methodStructs = Lists.newArrayList();
        for (CtType<?> element : elements) {
            if (element.isAnonymous()) {
                continue;
            }
            if (Objects.isNull(element.getPackage())) {
                continue;
            }
            // 获取包名
            String packageName = element.getPackage().getQualifiedName();
            // 获取类名
            String className = element.getSimpleName();
            // 获取方法列表
            Set<CtMethod<?>> methods = element.getMethods();
            for (CtMethod<?> method : methods) {
                try {
                    // 获取简单方法名
                    String methodName = method.getSimpleName();
                    // 获取全限定参数
                    String signatureParameters = method.getSignature();
                    int firstIndex = method.getSignature().indexOf("(");
                    int lastIndex = method.getSignature().indexOf(")");
                    String parameters = signatureParameters.substring(firstIndex + 1, lastIndex);
                    List<String> methodParameters = Splitter.on(",").omitEmptyStrings().splitToList(parameters);
                    // 获取响应体类型
                    String responseType = method.getType().getQualifiedName();
                    // 获取方法开始的行
                    int startLine = method.getPosition().getLine();
                    // 获取方法结束的行
                    int endLine = method.getPosition().getEndLine();
                    // 获取方法注释
                    String methodComment = method.getDocComment();
                    // 获取方法包含的注解信息
                    List<AnnotationInfo> annotationInfos = Lists.newArrayList();
                    List<CtAnnotation<?>> annotations = method.getAnnotations();
                    for (CtAnnotation<?> annotation : annotations) {
                        AnnotationInfo annotationInfo = new AnnotationInfo();
                        String annotationName = annotation.getAnnotationType().getSimpleName();
                        annotationInfo.setAnnotationName(annotationName);
                        Map<String, CtExpression> annotationValues = annotation.getValues();
                        for (Map.Entry<String, CtExpression> entry : annotationValues.entrySet()) {
                            String attributeName = entry.getKey();
                            Object attributeValue = entry.getValue();
                            annotationInfo.addAttributeName(attributeName, attributeValue.toString());
                        }
                        annotationInfos.add(annotationInfo);
                    }
                    // 获取方法的访问修饰符
                    String accessModifier = "";
                    if (Objects.isNull(method.getVisibility())) {
                        accessModifier = "default";
                    } else {
                        accessModifier = method.getVisibility().toString();
                    }
                    String methodId = generateIdentityUtil.generateMethodId(MethodSignature.builder()
                            .packagePath(packageName)
                            .className(className)
                            .methodName(methodName)
                            .parameterTypeString(methodParameters)
                            .build(), endLine - startLine + 1);


                    MethodStruct old = null;
                    // 基于规则判断一波是否需要询问chat
                    int lineCount = endLine - startLine;

                    MethodStruct methodStruct = MethodStruct.builder()
                            .appCode(GlobalVariableUtil.getAppCodeName())
                            .methodId(methodId)
                            .methodName(methodName)
                            .classId(generateIdentityUtil.generateClassId(className, packageName, GlobalVariableUtil.getAppCodeName()))
                            .paramTypes(methodParameters)
                            .responseType(responseType)
                            .beginLine(startLine)
                            .endLine(endLine)
                            .branch(GlobalVariableUtil.getBranch())
                            .methodDesc(methodComment)
                            .annotationInfos(annotationInfos)
                            .accessModifier(accessModifier)
                            .invokeCount(old == null ? 0 : old.getInvokeCount())
                            .mermaidFlowGraph(old == null ? "" : old.getMermaidFlowGraph())
                            .build();
                    if (old == null) {
                        methodStructs.add(methodStruct);
                    }
                } catch (Exception e) {
                    log.error("method parse error, className ==>{}, methodName ==>{}, errMsg ==>",
                           className, method.getSimpleName(), e);
                }
            }
        }
//       方法元信息入库
    }

通过这种方式,我们就能拿到整个 Java 项目的方法信息。

需要注意的是,我们这个时候还没有使用 AI 技术,所以这个元信息中部分字段是空的。

我们看到类解析器和方法解析器方法的入参都是 List<CtType<?>> elements

那么,这个信息从哪里来的呢?

我这里使用的是 Spoon 工具。

Spoon 是什么?

Spoon 框架常被用于解析和处理 Java 源代码。Spoon 是一个强大的源码分析与转换工具,它通过构建抽象语法树(Abstract Syntax Tree, AST)来表示 Java 源代码,并提供了一套丰富的 API 供开发者操作 AST。

Spoon 能够完整且准确地捕获源代码的所有细节,所以它非常适合于进行复杂的静态代码分析、重构、自动插入代码逻辑等工作。

Spoon 不会用?没关系,AI 可以帮你写代码。

我们可以看到,GPT 直接帮我们生成完整代码,我们只需要在对应的地方,替换成我们的类解析器和方法解析器即可。

提示词如下:

你是一个Java技术专家。
我需要解析本地的一个 Java 项目,获得这个项目中的类信息和方法信息。我会给你提供这个 Java 项目的绝对路径。
请你使用 Spoon 生成解析代码

写到这里,我要告诉你的是,其实类解析器和方法解析的代码,也可以交给 AI 来完成哟~ 你可以试试看,如果有问题,随时找阿七给你解答。

到这里,我们今天的内容就结束啦。

下一篇,我们分享使用 AI 生成方法的流程图,请期待~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1382722.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C语言之从浅入深一步一步全方位理解指针【附笔试题】

文章目录 前言从浅入深理解指针《第一阶段》一、内存和地址1.1 内存1.2 究竟该如何理解编址 二、指针变量和地址2.1 取地址操作符&#xff08;&&#xff09; 三、指针变量和解引用操作符&#xff08;*&#xff09;3.1 指针变量3.2 如何拆解指针类型3.3 解引用操作符 四、指…

OpenCV-Python的版本介绍及区别

OpenCV-Python版本介绍 OpenCV-Python有多个版本&#xff0c;每个版本都有其特定的功能和改进。以下是一些常见OpenCV-Python版本及其介绍和区别&#xff1a; OpenCV-Python 2.x版本 这是OpenCV-Python的旧版本&#xff0c;支持Python 2.x。它包含了许多传统的计算机视觉功能&…

rpc的正确打开方式|读懂Go原生net/rpc包

前言 大家好&#xff0c;这里是白泽&#xff0c;之前最近在阅读字节跳动开源RPC框架Kitex的源码&#xff0c;分析了如何借助命令行&#xff0c;由一个IDL文件&#xff0c;生成client和server的脚手架代码&#xff0c;也分析了Kitex的日志组件klog。当然Kitex还有许多其他组件&…

sqlilabs第五十三五十四关

Less-51(GET - GET - Error based - ORDER BY CLAUSE-String- Stacked injection) 手工注入 单引号闭合&#xff0c;和上一关一样堆叠注入解决 自动注入 和上一关一样 Less-52(GET - challenge - Union- 10 queries allowed -Variation 1) 手工注入 这一关开始后面的可以看…

Linux 内核如何根据设备树文件来匹配内核

一. 简介 上一篇文章学习了 Linux内核如何确定是否支持此设备&#xff0c;如果支持&#xff0c;设备就会启动 Linux 内核。 文章地址如下&#xff1a; 设备树根节点下的compatile属性的作用-CSDN博客 本文继上面文章的学习。这里简单看一下&#xff0c; Linux 内核是如何根…

学习资料: uni-app HBuilderX

编译器&#xff1a;HBuilderX HBuilderX-高效极客技巧 uni-app介绍&#xff1a;uni-app官网 uni-app 是一个使用 Vue.js 开发所有前端应用的框架&#xff0c;开发者编写一套代码&#xff0c;可发布到iOS、Android、Web&#xff08;响应式&#xff09;、以及各种小程序&#…

2023.1.13 关于在 Spring 中操作 Redis 服务器

目录 引言 前置工作 前置知识 实例演示 String 类型 List 类型 Set 类型 Hash 类型 ZSet 类型 引言 进行下述操作的前提是 你的云服务器已经配置好了 ssh 端口转发即已经将云服务器的 Redis 端口映射到本地主机 注意&#xff1a; 此处我们配置的端口号为 8888 可点击下…

C++力扣题目617--合并二叉树

给你两棵二叉树&#xff1a; root1 和 root2 。 想象一下&#xff0c;当你将其中一棵覆盖到另一棵之上时&#xff0c;两棵树上的一些节点将会重叠&#xff08;而另一些不会&#xff09;。你需要将这两棵树合并成一棵新二叉树。合并的规则是&#xff1a;如果两个节点重叠&#…

【STM32】FLASH闪存

1 FLASH闪存简介 本节所指STM32内部闪存&#xff0c;即下载程序的时候&#xff0c;程序存储的地方。&#xff08;非易失性&#xff09; STM32F1系列的FLASH包含程序存储器、系统存储器&#xff08;bootloader&#xff0c;不允许修改&#xff09;和选项字节三个部分&#xff0…

JavaScript学习笔记——变量、作用域、var、const和let

JavaScript学习笔记——变量、作用域、var、const和let 学习链接&#xff08;原链接&#xff09;变量变量声明的三种方式 作用域作用域介绍作用域分类全局作用域局部作用域&#xff08;函数作用域&#xff09;块级作用域块级作用域和局部(函数)作用域区别 varvar的作用域(全局函…

【elastic search】详解elastic search集群

目录 1.与集群有关的一些概念 2.集群搭建 3.集群搭建 4.kibana链接集群 5.选举流程 6.请求流程 7.master的作用 1.与集群有关的一些概念 数据分片&#xff1a; 数据分片&#xff08;shard&#xff09;&#xff0c;单台服务器的存储容量是有限的&#xff0c;把一份数据…

LINUX基础培训七之进程管理

前言、本章学习目标 了解LINUX中进程和程序掌握进程管理的作用和方法熟悉进程调度优先级了解LINUX信号 一、了解LINUX进程和程序 进程是正在执行的一个程序或命令&#xff0c;每个进程都是一个运行的实体&#xff0c;都有自己的地址空间&#xff0c;并占用一定的系统资源。 …

【Python学习】Python学习15-模块

目录 【Python学习】Python学习15-模块 前言创建语法引入模块from…import 语句from…import* 语句搜索路径PYTHONPATH 变量-*- coding: UTF-8 -*-导入模块现在可以调用模块里包含的函数了PYTHONPATH 变量命名空间和作用域dir()函数globals() 和 locals() 函数reload() 函数Py…

pytest -- 基本使用详解

1. pytest基本介绍 pytest 是一个功能强大且易于使用的 Python 测试框架&#xff0c;用于编写单元测试、集成测试和功能测试。 它提供了丰富的功能和灵活的用法&#xff0c;使得编写和运行测试变得简单而高效。 --------------->>>>> pytest框架优点&#xff1a…

C语言之字符串和指针

目录 用数组实现的字符串和用指针实现的字符串 █用数组实现的字符串str █用指针实现的字符串ptr 注意 用数组和指针实现字符串的不同点 字符串数组 用数组实现的字符串的数组——二维数组 用指针实现的字符串数组——指针数组 注意 字符串和指针有着紧密的联系&#…

C#中对浮点数NaN,PositiveInfinity,NegativeInfinity的特殊处理

NAN NAN 整体意思为Not a Number 不是一个数&#xff0c; NaN&#xff08;Not a Number&#xff0c;非数&#xff09;是计算机科学中数值数据类型的一类值&#xff0c;表示未定义或不可表示的值。常在浮点数运算中使用。首次引入NaN的是1985年的IEEE 754浮点数标准。 EEE 75…

AI-图片转换绚丽动漫人物-UGATIT

​​​​​​ &#x1f3e1; 个人主页&#xff1a;IT贫道-CSDN博客 &#x1f6a9; 私聊博主&#xff1a;私聊博主加WX好友&#xff0c;获取更多资料哦~ &#x1f514; 博主个人B栈地址&#xff1a;豹哥教你学编程的个人空间-豹哥教你学编程个人主页-哔哩哔哩视频 目录 ​​​​…

代码随想录算法训练营第五天天| 总结数组专题

数组&#xff1a;二分查找、双指针&#xff08;包括快慢指针&#xff09;、滑动窗口、模拟 链表&#xff1a;双指针、三指针、虚拟头指针、复杂指针操作画图明确每一步&#xff08;标好次序&#xff09; 数组 代码随想录总结的很好&#xff0c;如下图。我再结合自己的一些理解…

当使用WSL下载运行Docker可视化界面的镜像,使用报错

Traceback (most recent call last): File “app.py”, line 345, in root tk.Tk() File “/usr/lib/python3.8/tkinter/init.py”, line 2270, in init self.tk _tkinter.create(screenName, baseName, className, interactive, wantobjects, useTk, sync, use) _tkinter.T…