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

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

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

尽管如此,我们还是进行与编码有关的所有活动。 当然,我们使用的高级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

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

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

相关文章

C语言去括号编程题,去括号 - C语言网

题目描述当老师不容易&#xff0c;尤其是当小学的老师更难:现在的小朋友做作业喜欢滥用括号。虽然不影响计算结果&#xff0c;但不够美观&#xff0c;容易出错&#xff0c;而且可读性差。但又不能一棒子打死&#xff0c;也许他们就是将来的“陈景润”呢&#xff01;为了减轻老师…

c语言中删除有序数组中重复元素,去除有序列表中的重复元素

2014-10-27 09:13:00更新你仔细研究一下我写的 testAsignPoint 和 testAsignPointAgain 函数就会明白为什么你的二级指针无效了。还是那句话&#xff0c;你要记住&#xff0c;指针就是一个变量&#xff0c;存的是32位数据&#xff0c;记住这个才能真正的理解指针。另外 pezy 说…

阿卡接口_阿卡vs风暴

阿卡接口我最近在Twitter的Storm上工作了一段时间&#xff0c;这让我想知道&#xff0c;它与另一个高性能的并发数据处理框架Akka相比如何 。 什么是Akka和Storm&#xff1f; 让我们从两个系统的简短描述开始。 Storm是一种分布式实时计算系统。 在Storm集群上&#xff0c;您执…

c 语言已知两点求第三点,已知3点座标,求第一点到第二点和第三点构成的直线的距离。...

已知3点座标&#xff0c;求第一点到第二点和第三点构成的直线的距离。以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;已知3点座标&#xff0c;求第一点到第二点和第三点构成的直线的距离。解…

连续交付友好的Maven版本

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

android u盘检测工具,android USBU盘 接入检测

如果是在注册的静态广播一般必须含有以上的权限&#xff0c;这里必须注意添加如果在代码中注册广播则必须iFilter.addDataScheme("file")这样接受广播判断U盘public class RemovableDiskManagerReceiver extends BroadcastReceiver {public RemovableDiskManagerRece…

android 组合属性动画,Android属性动画组合(sequence串行、together并行)

在android中用原生api实现一系列复杂动画会很麻烦&#xff0c;所以对属性动画进行了一定封装&#xff0c;让使用起来更简单&#xff0c;能够按照人的思维依次编写动画。简单效果&#xff1a;使用方法&#xff1a;添加依赖&#xff1a;dependencies { compile"com.steven:A…

jta atomikos_带有Atomikos示例的Tomcat中的Spring JTA多个资源事务

jta atomikos在本教程中&#xff0c;我们将向您展示如何使用Atomikos Transaction Manager在Tomcat服务器中实现JTA多个资源事务。 Atomicos事务管理器为分布式事务提供支持。 这些是多阶段事务&#xff0c;通常使用多个数据库&#xff0c;必须以协调的方式提交。 分布式事务由…

android 音量键 广播,【Android 7.0 Audio】: 按键调节音量的调用过程

转载自http://blog..net/xiashaohua/article/details/53842337只简单描述调用过程&#xff0c;需对照代码看&#xff0c;不画图了&#xff0c;也不贴代码)1.在key Event处理部分&#xff0c;Phonewindow会捕获到音量按键事件&#xff0c;Phonewindow.onkeydown--MediaSessionLe…

台电+android+电话,通话系统_台电 G17s_平板电脑评测-中关村在线

通话系统将两张联通3G的SIM卡插入台电G17s之后&#xff0c;我们来感受一下它通话系统的使用是否令人满意。和一般的双卡Android手机平板一样&#xff0c;该机也不支持热插拔&#xff0c;需要将机器彻底关闭后插入SIM卡再开机。并且在开机后屏幕会弹出SIM卡信息&#xff0c;并询…

在Payara Server和GlassFish中配置密码

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

功能Java示例 第2部分–讲故事

这是称为“ Functional Java by Example”的系列文章的第2部分。 我在本系列的每个部分中发展的示例是某种“提要处理程序”&#xff0c;用于处理文档。 在上一部分中&#xff0c;我从一些原始代码开始&#xff0c;并应用了一些重构来描述“什么”而不是“如何”。 为了帮助代…

OpenHub框架–下一个有趣的功能

这是有关OpenHub框架的系列文章中的第三篇&#xff0c;第一篇介绍OpenHub框架 &#xff0c;第二篇介绍异步消息传递模型 。 该系列的最后一篇文章将更详细地介绍其他一些有趣的功能&#xff0c;并说明为什么OpenHub可以成为您的集成项目的理想选择的原因。 节流 节流是一种功…

tcga癌症亚型获取_将亚型多态性与通用多态性相关联的危险

tcga癌症亚型获取Java 5已将通用多态性引入Java生态系统。 即使我们都知道由于泛型类型擦除及其后果而引起的无数警告&#xff0c;这还是对Java语言的重要补充。 通用多态性&#xff08;也称为参数多态性 &#xff09;通常与可能预先存在的亚型多态性正交。 一个简单的例子是co…

在生产中运行Java:SRE的观点

作为站点可靠性工程师 &#xff08;SRE&#xff09;&#xff0c;我确保我们的生产服务高效&#xff0c;可扩展且可靠。 典型的SRE是生产大师&#xff0c;必须对更广泛的体系结构有很好的了解&#xff0c;并精通许多更精细的细节。 SRE是会说多种语言的程序员&#xff0c;这是很…

android 退出多个activity,Android 中 退出多个activity的经典方法

1.使用list集合方式用list保存activity实例&#xff0c;然后逐一干掉import java.util.linkedlist;import java.util.list;import android.app.activity;import android.app.alertdialog;import android.app.application;import android.content.dialoginterface;import androi…

声明jpa批注处理器_如何使用反射基于JPA批注记录您的数据模型

声明jpa批注处理器因此&#xff0c;当您仅可以注释Java类时&#xff0c;使用JPA&#xff0c;Hibernate或EBeans很酷&#xff0c;但是您不是一直希望可以从代码“生成”数据模型的文档吗&#xff1f; 提取JPA / Hibernate和其他验证注释的信息&#xff1f; 假设您的bean中具有所…

在Grails战争中添加“精简” Groovy Web控制台

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

ubuntu生成密钥和证书_基于浏览器的密钥生成以及与浏览器的密钥/证书存储的交互...

ubuntu生成密钥和证书想象以下情况&#xff1a; 您需要从访问您的网站的用户那里获取一个密钥&#xff08;在非对称情况下为用户的公共密钥 &#xff09;&#xff0c;并希望浏览器记住私有部分&#xff0c;而不会因冗长的导入过程而困扰用户。 老实说&#xff0c;实际上&#…

JPA persistence.xml SQL脚本定义

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