javaparser_JavaParser生成,分析和修改Java代码

javaparser

作为开发人员,我们经常鄙视手动进行重复工作的人员。

我们认为, 他们应该实现这一目标

尽管如此,我们还是进行与编码有关的所有活动。 当然,我们使用的高级IDE可以为我们执行一些重构,但这基本上就结束了。 我们不品尝我们自己的药。

让我们改变一下。 让我们看看如何将代码编写为:

  • 生成我们必须编写的无聊的重复性Java代码
  • 分析我们的代码以回答有关它的一些问题
  • 做一些代码处理和重构

好消息是,我们将使用一组库来实现所有这些功能:JavaParser和它的弟弟JavaSymbolSolver。

入门

好吧,这很简单:只需将JavaSymbolSolver添加到您的依赖项中即可。

什么是JavaSymbolSolver? 它是JavaParser的补充库,为它提供了一些非常强大的功能,这些功能对于回答关于代码的更复杂的问题是必需的。

JavaSymbolSolver依赖于JavaParser,因此您只需要添加JavaSymbolSolver,Maven或Gradle也会为您提供JavaParser。

我假设您知道如何使用Maven或Gradle。 如果您不喜欢,请停止阅读并开始学习!

使用javaparser生成代码

在几种情况下,您可能需要生成Java代码。 例如,您可能想基于一些外部数据生成代码,例如数据库架构或REST API。

您可能还需要将其他语言翻译成Java。 例如,我设计了用于生活的DSL,而当用户只能看到我为他们构建的DSL时,我经常在后台生成Java并将其编译。

有时候,您只想生成样板代码,就像我以前在使用JavaEE和所有这些层(谁能记住编写EJB的乏味?)时曾经使用过dp一样。

无论出于什么原因生成代码,都可以使用JavaParser。 JavaParser不会提出问题,它只是在帮助您。

让我们看看如何生成一个具有两个字段的类,一个构造函数和两个getter。 没什么特别先进的,但是它应该使您了解使用JavaParser进行代码生成的含义。

CompilationUnit cu = new CompilationUnit();cu.setPackageDeclaration("jpexample.model");ClassOrInterfaceDeclaration book = cu.addClass("Book");
book.addField("String", "title");
book.addField("Person", "author");book.addConstructor(Modifier.PUBLIC).addParameter("String", "title").addParameter("Person", "author").setBody(new BlockStmt().addStatement(new ExpressionStmt(new AssignExpr(new FieldAccessExpr(new ThisExpr(), "title"),new NameExpr("title"),AssignExpr.Operator.ASSIGN))).addStatement(new ExpressionStmt(new AssignExpr(new FieldAccessExpr(new ThisExpr(), "author"),new NameExpr("author"),AssignExpr.Operator.ASSIGN))));book.addMethod("getTitle", Modifier.PUBLIC).setBody(new BlockStmt().addStatement(new ReturnStmt(new NameExpr("title"))));book.addMethod("getAuthor", Modifier.PUBLIC).setBody(new BlockStmt().addStatement(new ReturnStmt(new NameExpr("author"))));System.out.println(cu.toString());

最后一条指令将打印出您的代码,并且可以立即进行编译。 您可能希望将代码保存到文件中而不是打印它,但是您明白了。

使用javaparser分析代码

您可能会询问有关代码的许多不同问题,以及许多不同的分析方式。

首先,让我们解析项目的所有源文件:

// Parse all source files
SourceRoot sourceRoot = new SourceRoot(myProjectSourceDir.toPath());
sourceRoot.setParserConfiguration(parserConfiguration);
List<ParseResult> parseResults = sourceRoot.tryToParse("");// Now get all compilation unitsList 
allCus = parseResults.stream()        .filter(ParseResult::isSuccessful)        .map(r -> r.getResult().get())        .collect(Collectors.toList());

我们还创建一个方法来获取所有编译单元中特定类型的所有节点:

public static  List getNodes(List cus, Class nodeClass) {List res = new LinkedList();cus.forEach(cu -> res.addAll(cu.findAll(nodeClass)));return res;
}

然后让我们开始提出问题,例如:

有多少种方法采用3个以上的参数?

long n = getNodes(allCus, MethodDeclaration.class)        .stream()        .filter(m -> m.getParameters().size() > 3).count();System.out.println("N of methods with 3+ params: " + n);

大多数方法中的三个顶级类别是什么?

getNodes(allCus, ClassOrInterfaceDeclaration.class)        .stream()        .filter(c -> !c.isInterface())        .sorted(Comparator.comparingInt(o -> -1 * o.getMethods().size()))        .limit(3)        .forEach(c -> System.out.println(c.getNameAsString() + ": " +             c.getMethods().size() + " methods"));

好的,您知道了。 现在去检查您的代码。 您没有什么可隐藏的,对吗?

使用javaparser转换代码

假设您是某个库的满意用户。 几年前,您已将其添加到依赖项中,并从此以后就愉快地使用它。 时间已经过去,您已经在整个项目中越来越多地使用它。

有一天,该实用库的新版本出现了,您决定要更新依赖项。 现在,他们在新库中删除了您正在使用的方法之一。 确保已弃用它,并将其命名为oldMethod (可能告诉您一些信息……)。

现在oldMethod已被newMethod取代。 newMethod具有3个参数:前两个与oldMethod相同只是将它们取反,第三个是布尔值,应将其设置为true以获得与oldMethod相同的行为。

您有对oldMethod的数百个调用…是否要一个一个地更改它们? 好吧,也许,如果您按小时收费。 或者,您可以只使用JavaParser代替。

首先让我们找到所有在JavaParser类parlanse老方法在某个文件,又名CompilationUnit的电话:

myCompilationUnit.findAll(ethodCallExpr.class).stream().filter(m -> m.resolveInvokedMethod()                .getQualifiedSignature()                .equals("foo.MyClass.oldMethod(java.lang.String, int)"))        .forEach(m -> m.replace(replaceCallsToOldMethod(m)));

然后让我们将旧调用转换为新调用:

public MethodCallExpr replaceCallsToOldMethod(MethodCallExpr methodCall) {    MethodCallExpr newMethodCall = new MethodCallExpr(methodCall.getScope().get(), "newMethod");    newMethodCall.addArgument(methodCall.getArgument(1));    newMethodCall.addArgument(methodCall.getArgument(0));    newMethodCall.addArgument(new BooleanLiteralExpr(true));    return newMethodCall;
}

太酷了,现在我们只需要获取修改后的CompilationUnit的代码并将其保存到Java文件即可。

newMethod使用寿命

在哪里可以找到有关javaparser的更多信息

我们还没有看到JavaParser的众多功能:

  • JavaParser可以处理注释,弄清楚它们所引用的元素
  • JavaParser可以进行词法保留漂亮的打印 :您的选择
  • 它可以找出一个方法调用指向哪个方法声明,某个类具有哪个祖先,以及更多地归功于与JavaSymbolSolver的集成。
  • 它可以将AST导出为JSON,XML,YAML,甚至可以使用Graphviz生成图表!

您在哪里可以了解所有这些东西?

这里有一些资源:

  • 我们写了一本关于JavaParser和JavaSymbolSolver的书,免费提供。 它被命名为JavaParser:Visited
  • Matozoid伟大的博客 :他是JavaParser的光荣维护者,这是不可阻挡的力量,它每隔一个星期就会推出新版本。 谁更了解JavaParser?
  • 我关于语言工程的拙劣博客 。 我是JavaSymbolSolver的维护者,并且尝试作为JavaParser中的第二命令来提供帮助。 遥远的第二个&#55357;&#56898;
  • 该项目的网站 :目前内容还不是很丰富,但是我们正在努力
  • 烦恼频道 :您有问题吗? 在那儿问他们

摘要

几乎没有情况可以学习如何使用一种工具来完成三件不同的事情。 通过学习如何使用JavaParser,您可以分析,生成和修改Java代码。

好吧,感觉就像圣诞节,不是吗?

翻译自: https://www.javacodegeeks.com/2017/12/javaparser-generate-analyze-modify-java-code.html

javaparser

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

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

相关文章

计算机系统组成_网络教育统考计算机应用基础题库(计算机系统的组成2)

点击蓝字关注我哦11在微型计算机的各种设备中&#xff0c;既用于输入又可用于输出的设备是____。A、磁盘驱动器B、键盘C、鼠标D、绘图仪点击空白处查看答案参考答案:A12计算机的硬件系统由五大部分组成&#xff0c;下列各项中不属于这五大部分的是______。A、运算器B、软件C、I…

深度学习基础实战使用MNIST数据集对图片分类

本文代码完全借鉴pytorch中文手册 我们找到数据集&#xff0c;对数据做预处理&#xff0c;定义我们的模型&#xff0c;调整超参数&#xff0c;测试训练&#xff0c;再通过训练结果对超参数进行调整或者对模型进行调整。 import torch import torch.nn as nn import torch.nn.f…

Linux 命令之 curl -- 文件传输工具/下载工具/网络接口调试

文章目录 一、命令介绍二、常用选项三、wget 与 curl 对比四、命令示例(一)以 post 方式提交数据/以 post 方式传递请求参数(二)查看网页的源码内容(三)保存访问的网页源码内容(四)将服务器的回应保存成文件/将输出保存成文件(五)显示 http response 头信息,打印出服…

python cookie使用_Python使用cookielib模块操作cookie的实例教程

cookielib是一个自动处理cookies的模块&#xff0c;如果我们在使用爬虫等技术的时候需要保存cookie&#xff0c;那么cookielib会让你事半功倍&#xff01;他最常见的搭档模块就是python下的urllib和request。核心类1.Cookie该类实现了Netscape and RFC 2965 cookies定义的cooki…

pytorch中unsqueeze()函数理解

unsqueeze()函数起升维的作用,参数表示在哪个地方加一个维度。 在第一个维度(中括号)的每个元素加中括号 0表示在张量最外层加一个中括号变成第一维。 直接看例子: import torch inputtorch.arange(0,6) print(input) print(input.shape) 结果&#xff1a; tensor([0, 1, 2, 3…

Linux 命令之 ifconfig -- 配置和显示网卡的网络参数

文章目录一、命令介绍二、常用选项三、参考示例&#xff08;一&#xff09;显示网络设备信息&#xff08;激活状态的&#xff09;&#xff08;二&#xff09;启动关闭指定网卡&#xff08;三&#xff09;显示所有配置的网络接口&#xff0c;不论其是否激活&#xff08;四&#…

版本交付_连续交付友好的Maven版本

版本交付持续交付管道需要可预测的软件和依赖版本。 Maven软件项目中常见的快照版本与“持续交付”背后的动机背道而驰。 为了将快照版本更新为发行版本&#xff0c;开发人员通常手动或通过诸如maven-release-plugin来编辑pom.xml文件。 但是&#xff0c;Maven还提供了将版本号…

shell开启飞行模式_今天才知道,原来手机的飞行模式用处那么多,看完涨知识了...

想必大家都知道&#xff0c;手机里有个飞行模式&#xff0c;是在乘坐飞机时使用的。其实除了这个功能之外&#xff0c;飞行模式还有很多其他的妙用&#xff0c;下面笔者就为大家一一进行介绍。一、 加快充电速度有些特殊情况你想加快手机的充电速度时&#xff0c;可以试着开启飞…

Anaconda安装库

有时候pip安装库特别慢&#xff0c;就采用conda别的方法装 conda install -c conda-forge 库名#如pydicom,gdcm

Linux 如何安装 SRPM 包(源代码 rpm 软件包,以 .src.rpm 为后缀名)/rpm 格式的源码软件包/源码包

文章目录一、SRPM 介绍二、SRPM 命名格式三、SRPM 的安装&#xff08;一&#xff09;直接使用命令 rpmbuild&#xff08;二&#xff09;利用 *.spec 文件编译&#xff08;三&#xff09;使用命令 make 编译和安装四、写在最后一、SRPM 介绍 SRPM 包&#xff0c;比 RPM 包多了一…

payara 创建 集群_在Payara Server和GlassFish中配置密码

payara 创建 集群回答Stackoverflow问题可以为我发现我最喜欢的开源工具的正式文档中的空白提供很好的反馈。 我在这里回答的问题之一是如何在docker容器中更改Payara Server主密码 。 显然&#xff0c;在标准服务器安装中&#xff0c;这很简单–只需使用asadmin change-master…

axure怎么做5秒倒计时_五个月宝宝早教,5个月婴儿早教怎么做

五个月宝宝早教&#xff0c;5个月婴儿早教怎么做&#xff0c;5个月宝宝是需要开始有意识的进行精细动作的家庭训练了5个月宝宝的一般特点&#xff1a;到了5个月时&#xff0c;能用眼睛观察周围的物体了&#xff0c;而且对什么都感到新奇好玩&#xff0c;能在眼睛的支配下抓住东…

python中enumerate()的理解

enumerate()函数的作用是通过迭代来遍历一个字符串、列表或字典等&#xff0c;并且为其增加索引&#xff0c;返回值为enumerate类。 代码举例如下&#xff1a; list[1,2,3,4,5,6] for i,j in enumerate(list):print(i,j) #结果&#xff1a; 0 1 1 2 2 3 3 4 4 5 5 6namesaber…

jpa执行sql脚本_JPA persistence.xml SQL脚本定义

jpa执行sql脚本您可以在将在运行时执行的JPA持久性上下文定义中定义并链接到SQL脚本。 有标准化的属性来定义脚本&#xff0c;以分别说明如何创建模式&#xff0c;批量加载数据和删除模式&#xff1a; <persistence version"2.1" xmlns"http://xmlns.jcp.or…

RPM 软件包默认的安装路径

通常情况下&#xff0c;RPM 包采用系统默认的安装路径&#xff0c;所有安装文件会按照类别分散安装到表 1 所示的目录中。 表 1 RPM 包默认安装路径安装路径含义/etc/配置文件安装目录/usr/bin/可执行的命令文件安装目录/usr/lib/程序所使用的函数库保存位置/usr/share/doc/基本…

图像融合亮度一致_重磅干货低光图像处理方案

点击上方“AIWalker”&#xff0c;选择加“星标”或“置顶” 重磅干货&#xff0c;第一时间送达Tips&#xff1a;一点点提示&#xff0c;因内容较多建议先关注&#xff0c;再置顶&#xff0c;最后端杯茶来精心浏览。背景低光图像是夜晚拍照时极为常见的一种现象。不充分的光…

修改本地文件的名字

将名字叫做megumi的文本文件改成名字叫做asuna的文本文件。主要用到os库的rename方法。 代码如下: import os folder"C:/Users/13451/Desktop" oldos.path.join(folder,megumi.txt) #或者oldfolder/megumi.txt newos.path.join(folder,asuna.txt) os.rename(old,n…

Adobe PhotoShop(PS) for Mac 如何隐藏切片框?

如何取消显示如下图所示的切片框&#xff1a; 打开『视图』➟ 『显示』&#xff0c;把『切片』前面的勾去掉&#xff0c;如下图所示&#xff1a;

groovy grails_在Grails战争中添加一个“精简”的Groovy Web控制台

groovy grails假设您已将Grails应用程序部署到服务器上–如何查找应用程序的配置方式&#xff1f; 如果您有来源&#xff0c;则可以查看Config.groovy &#xff0c; BuildConfig.groovy等&#xff08;在这种情况下&#xff0c;我正在谈论Grails 2应用程序&#xff0c;但是这些想…

邮宝打印面单尺寸调整_如何打印身份证的实际尺寸?怎样用照片打印身份证复印件...

点击上面 蓝色 文字关注我们&#xff0c;了解选购百科知识&#xff0c;快乐健康不停&#xff01;怎样打印身份证复印件&#xff1f;可以把身份证的照片导入电脑或者扫描件打印黑白的即可。如何打印身份证的实际尺寸&#xff1f;二代身份证的实际尺寸是&#xff1a;85.6MM X 54M…