javaparser_JavaParser入门:以编程方式分析Java代码

javaparser

我最喜欢的事情之一是解析代码并对其执行自动操作。 因此,我开始为JavaParser做出贡献,并创建了两个相关项目: java-symbol-solver和Effectivejava 。 java_jp-1024x648

作为JavaParser的贡献者,我反复阅读了一些有关从Java源代码提取信息的非常相似的问题。 因此,我认为我可以帮助提供一些简单的示例,以帮助您开始解析Java代码。

  • Github上提供了所有源代码: analyzer-java-code-examples

通用代码

使用JavaParser theere时,我们总是希望进行很多操作。 通常,我们希望对整个项目进行操作,因此在给定目录的情况下,我们将浏览所有Java文件。 此类应帮助完成此任务:

package me.tomassetti.support;import java.io.File;public class DirExplorer {public interface FileHandler {void handle(int level, String path, File file);}public interface Filter {boolean interested(int level, String path, File file);}private FileHandler fileHandler;private Filter filter;public DirExplorer(Filter filter, FileHandler fileHandler) {this.filter = filter;this.fileHandler = fileHandler;}public void explore(File root) {explore(0, "", root);}private void explore(int level, String path, File file) {if (file.isDirectory()) {for (File child : file.listFiles()) {explore(level + 1, path + "/" + child.getName(), child);}} else {if (filter.interested(level, path, file)) {fileHandler.handle(level, path, file);}}}}

对于每个Java文件,我们首先要为每个Java文件构建一个抽象语法树(AST),然后对其进行导航。 这样做有两种主要策略:

  1. 使用访客:要在特定类型的AST节点上进行操作时,这是正确的策略
  2. 使用递归迭代器:这允许处理所有类型的节点

可以编写访问者扩展JavaParser中包含的类,但这是一个简单的节点迭代器:

package me.tomassetti.support;import com.github.javaparser.ast.Node;public class NodeIterator {public interface NodeHandler {boolean handle(Node node);}private NodeHandler nodeHandler;public NodeIterator(NodeHandler nodeHandler) {this.nodeHandler = nodeHandler;}public void explore(Node node) {if (nodeHandler.handle(node)) {for (Node child : node.getChildrenNodes()) {explore(child);}}}
}

现在,让我们看看如何使用此代码来解决Stack Overflow上的一些问题。

如何从Java类中提取普通字符串中所有类的名称?

  • 在堆栈溢出时询问

寻找ClassOrInterfaceDeclaration节点可以解决此解决方案。 给定我们想要一种特定类型的节点,我们可以使用访客。 请注意,VoidVisitorAdapter允许传递任意参数。 在这种情况下,我们不需要这样做,因此我们指定对象类型,而在访问方法中将其忽略即可。

package me.tomassetti.examples;import com.github.javaparser.JavaParser;
import com.github.javaparser.ParseException;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;
import com.google.common.base.Strings;
import me.tomassetti.support.DirExplorer;import java.io.File;
import java.io.IOException;public class ListClassesExample {public static void listClasses(File projectDir) {new DirExplorer((level, path, file) -> path.endsWith(".java"), (level, path, file) -> {System.out.println(path);System.out.println(Strings.repeat("=", path.length()));try {new VoidVisitorAdapter<Object>() {@Overridepublic void visit(ClassOrInterfaceDeclaration n, Object arg) {super.visit(n, arg);System.out.println(" * " + n.getName());}}.visit(JavaParser.parse(file), null);System.out.println(); // empty line} catch (ParseException | IOException e) {new RuntimeException(e);}}).explore(projectDir);}public static void main(String[] args) {File projectDir = new File("source_to_parse/junit-master");listClasses(projectDir);}
}

我们在JUnit的源代码上运行示例,并得到以下输出:

/src/test/java/org/junit/internal/MethodSorterTest.java
=======================================================* DummySortWithoutAnnotation* Super* Sub* DummySortWithDefault* DummySortJvm* DummySortWithNameAsc* MethodSorterTest/src/test/java/org/junit/internal/matchers/StacktracePrintingMatcherTest.java
=============================================================================* StacktracePrintingMatcherTest/src/test/java/org/junit/internal/matchers/ThrowableCauseMatcherTest.java
=========================================================================* ThrowableCauseMatcherTest... 
... many other lines follow

是否有Java代码解析器可以返回组成语句的行号?

  • 在堆栈溢出时询问

在这种情况下,我需要查找各种语句。 现在,有几个类扩展了Statement基类,因此我可以使用一个访问者,但我需要在几种访问方法中编写相同的代码,每个Statement方法的子类一个。 另外,我只想获取顶层语句,而不要获取其中的语句。 例如,一个for语句可以包含其他几个语句。 使用我们的自定义NodeIterator,我们可以轻松实现此逻辑。

package me.tomassetti.examples;import com.github.javaparser.JavaParser;
import com.github.javaparser.ParseException;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.stmt.Statement;
import com.google.common.base.Strings;
import me.tomassetti.support.DirExplorer;
import me.tomassetti.support.NodeIterator;import java.io.File;
import java.io.IOException;public class StatementsLinesExample {public static void statementsByLine(File projectDir) {new DirExplorer((level, path, file) -> path.endsWith(".java"), (level, path, file) -> {System.out.println(path);System.out.println(Strings.repeat("=", path.length()));try {new NodeIterator(new NodeIterator.NodeHandler() {@Overridepublic boolean handle(Node node) {if (node instanceof Statement) {System.out.println(" [Lines " + node.getBeginLine() + " - " + node.getEndLine() + " ] " + node);return false;} else {return true;}}}).explore(JavaParser.parse(file));System.out.println(); // empty line} catch (ParseException | IOException e) {new RuntimeException(e);}}).explore(projectDir);}public static void main(String[] args) {File projectDir = new File("source_to_parse/junit-master");statementsByLine(projectDir);}
}

这是在JUnit的源代码上运行程序所获得的输出的一部分。

/src/test/java/org/junit/internal/matchers/ThrowableCauseMatcherTest.java
=========================================================================[Lines 12 - 17 ] {NullPointerException expectedCause = new NullPointerException("expected");Exception actual = new Exception(expectedCause);assertThat(actual, hasCause(is(expectedCause)));
}

您可能会注意到所报告的语句跨5个,而不是所报告的6个(12..17是6行)。 这是因为我们正在打印该语句的纯净版本,删除白线,注释并设置代码格式。

从Java代码中提取方法调用

  • 在堆栈溢出时询问

对于提取方法调用,我们可以再次使用Visitor,因此这非常简单,并且与我们看到的第一个示例非常相似。

package me.tomassetti.examples;import com.github.javaparser.JavaParser;
import com.github.javaparser.ParseException;
import com.github.javaparser.ast.expr.MethodCallExpr;
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;
import com.google.common.base.Strings;
import me.tomassetti.support.DirExplorer;import java.io.File;
import java.io.IOException;public class MethodCallsExample {public static void listMethodCalls(File projectDir) {new DirExplorer((level, path, file) -> path.endsWith(".java"), (level, path, file) -> {System.out.println(path);System.out.println(Strings.repeat("=", path.length()));try {new VoidVisitorAdapter<Object>() {@Overridepublic void visit(MethodCallExpr n, Object arg) {super.visit(n, arg);System.out.println(" [L " + n.getBeginLine() + "] " + n);}}.visit(JavaParser.parse(file), null);System.out.println(); // empty line} catch (ParseException | IOException e) {new RuntimeException(e);}}).explore(projectDir);}public static void main(String[] args) {File projectDir = new File("source_to_parse/junit-master");listMethodCalls(projectDir);}
}

如您所见,该解决方案与用于列出类的解决方案非常相似。

/src/test/java/org/junit/internal/MethodSorterTest.java
=======================================================[L 58] MethodSorter.getDeclaredMethods(clazz)[L 64] m.isSynthetic()[L 65] m.toString()[L 65] clazz.getName()[L 65] m.toString().replace(clazz.getName() + '.', "")[L 65] names.add(m.toString().replace(clazz.getName() + '.', ""))[L 74] Arrays.asList(EPSILON, BETA, ALPHA, DELTA, GAMMA_VOID, GAMMA_BOOLEAN)[L 75] getDeclaredMethodNames(DummySortWithoutAnnotation.class)[L 76] assertEquals(expected, actual)[L 81] Arrays.asList(SUPER_METHOD)[L 82] getDeclaredMethodNames(Super.class)[L 83] assertEquals(expected, actual)[L 88] Arrays.asList(SUB_METHOD)[L 89] getDeclaredMethodNames(Sub.class)[L 90] assertEquals(expected, actual)[L 118] Arrays.asList(EPSILON, BETA, ALPHA, DELTA, GAMMA_VOID, GAMMA_BOOLEAN)[L 119] getDeclaredMethodNames(DummySortWithDefault.class)[L 120] assertEquals(expected, actual)[L 148] DummySortJvm.class.getDeclaredMethods()[L 149] MethodSorter.getDeclaredMethods(DummySortJvm.class)[L 150] assertArrayEquals(fromJvmWithSynthetics, sorted)[L 178] Arrays.asList(ALPHA, BETA, DELTA, EPSILON, GAMMA_VOID, GAMMA_BOOLEAN)[L 179] getDeclaredMethodNames(DummySortWithNameAsc.class)[L 180] assertEquals(expected, actual)

下一步

您可以使用此处介绍的方法回答很多问题:浏览AST,找到您感兴趣的节点,并获取所需的信息。 但是,我们还需要考虑其他几件事:首先,如何转换代码。 虽然提取信息很棒,但是重构更加有用。 然后,对于更高级的问题,我们需要使用java-symbol-solver解析符号。 例如:

  • 查看AST,我们可以找到一个类的名称,但不能找到它间接实现的接口列表
  • 在查看方法调用时,我们无法轻易找到该方法的声明。 它在哪个类或接口中声明? 我们要调用哪些不同的重载变体?

我们将在将来对此进行研究。 希望这些例子可以帮助您入门!

翻译自: https://www.javacodegeeks.com/2016/02/getting-started-javaparser-analyzing-java-code-programmatically.html

javaparser

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

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

相关文章

prepare的用法 php,PHP中的操作mysqli的预处理prepare

这篇文章主要介绍了关于PHP中的操作mysqli的预处理prepare &#xff0c;有着一定的参考价值&#xff0c;现在分享给大家&#xff0c;有需要的朋友可以参考一下PHP中的操作mysqli的预处理prepare1、【PHP错误】Cannot pass parameter 2 by reference这个错误的意思是不能按引用传…

wps xml转换表格_这功能WPS卖近百元?教你免费将PDF转成Word

[PConline 应用]PDF文件如何转换成为Word&#xff1f;很多朋友研究这个问题已经很久了&#xff0c;PDF更利于统一格式传播&#xff0c;Word更便于编辑&#xff0c;因此收到PDF文件后、想要修改时要如何将PDF转换成Word可谓是一个刚需。当然&#xff0c;不少办公软件提供了这样的…

junit 预期错误_谨慎使用JUnit的预期异常

junit 预期错误有时&#xff0c;当我们收到对jOOQ或其他库的拉取请求时&#xff0c;人们会将单元测试中的代码更改为更“惯用的JUnit”。 特别是&#xff0c;这意味着他们倾向于更改此代码&#xff08;公认的不是那么漂亮的代码&#xff09;&#xff1a; Test public void tes…

LeetCode 231. 2的幂

原题链接 class Solution { public:bool isPowerOfTwo(int n) {if(n<0)return false;if((n&n-1) 0) return true;return false;} };

睡眠 应该用 a加权 c加权_在神经网络中提取知识:学习用较小的模型学得更好...

在传统的机器学习中&#xff0c;为了获得最先进的(SOTA)性能&#xff0c;我们经常训练一系列整合模型来克服单个模型的弱点。 但是&#xff0c;要获得SOTA性能&#xff0c;通常需要使用具有数百万个参数的大型模型进行大量计算。 SOTA模型(例如VGG16 / 19&#xff0c;ResNet50)…

matlab读txt文件不完整,求助Matlab批量读取TXT文件出错

我用dlmread函数批量读取txt文件中的一个数据&#xff0c;但运行结果1.txt文件中只有一个数据0&#xff0c;调试时报错&#xff1a;错误使用 dlmread (line 147)文件结尾不支持空的格式字符串&#xff0c;文件有128列&#xff0c;78行&#xff0c;下面没有列全文件格式是&#…

面向对象代码_面向对象的代码生成方法

面向对象代码代码生成是减少无聊任务的不健康负担的一种常用方法&#xff0c;这些任务常常使我们急切地对代码苦恼。 我见过的许多代码生成框架都使用模板替换重复方法&#xff0c;在该模板中&#xff0c;您编写了模板&#xff0c;以了解生成的代码文件的外观&#xff0c;然后替…

LeetCode 20.有效括号

原题链接 方法一&#xff1a;解题思路&#xff0c;使用栈 模拟法&#xff1b;首先遍历将是左括号形式的部分压入栈中。然后对于右括号形式与栈顶元素进行比对&#xff0c;看是否匹配。如果匹配的话删除栈顶元素&#xff0c;不匹配直接返回false。最后栈为空则全部的括号匹配…

gpu编程如何一步步学习_如何学习贴片机编程

学习贴片机编程首选要对贴片机有所熟悉了解&#xff0c;另外对常用的电脑编辑软件要会使用。目前通常学习贴片机编程有专门的培训学校&#xff0c;或者跟着生产线上现有的贴片机编程师傅学习熟练后再进行编程操作。下面深圳智驰科技就来分享一下如何学习贴片机编程。对贴片机编…

plotcylinder matlab,Matlab在任意两点之间绘制三维圆柱

Matlab在任意两点之间绘制三维圆柱Matlab在任意两点之间绘制三维圆柱此函数可能存在一些不足&#xff0c;请多多指教&#xff01;function plotcylinder(u1,u2,color_a,r)Lnorm(u1-u2);RODu2-u1;[X,Y,Z]cylinder(r,100);x1X*0;y1Y*0;z1Z*0;ZL*Z-L/2;ROD_midpoint(u1u2)/2;xROD_…

简单内存池设计

关键词 内存池 链表 class A { public:static void* operator new(size_t size);static void operator delete(void* phead);static int m_iCout;//分配计数统计&#xff0c;每new一次&#xff0c;就统计一次static int m_iMallocCount;//每次malloc一次&#xff0c;统计一次p…

jdk8和hotspot_HotSpot的-XshowSettings标志的简单性和价值

jdk8和hotspot一个方便的HotSpot JVM标志 &#xff08; 选项为Java启动 java &#xff09;是-XshowSettings选项。 Oracle Java启动器描述页面中对此选项进行了如下描述 &#xff1a; -XshowSettings &#xff1a; category显示设置并继续。 该选项的可能类别参数包括&#xf…

怎样自动提取邮件的内容_这些最新的外贸搜索开发工具(图灵搜、谷歌搜索提取工具、易查查),你会使用吗?...

贸业务开展过程中&#xff0c;搜寻买家信息&#xff0c;开发买家客户&#xff0c;是开展外贸的前提。而掌握B2B、谷歌、搜索引擎、社交网站及众多搜索工具的运用技巧&#xff0c;则是外贸业务人员的基本功。本篇文章将结合图灵搜、谷歌搜索提取工具、易查查&#xff0c;三款工具…

LeetCode 面试题55 二叉树的深度

原题链接 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode(int x) : val(x), left(NULL), right(NULL) {}* };*/ class Solution { public:int maxDepth(TreeNode* root) {if(rootNULL)…

matlab信号分割与比对,matlab测量计算信号的相似度

本示例说明如何测量信号相似度。将回答以下问题&#xff1a;如何比较具有不同长度或不同采样率的信号&#xff1f;如何确定测量中是否存在信号或仅有噪声&#xff1f;有两个信号相关吗&#xff1f;如何测量两个信号之间的延迟&#xff1f;比较具有不同采样率的信号考虑一个音频…

Spring Bootstrap中具有配置元数据的高级配置

在简要介绍了配置元数据并涵盖了我之前的文章《 在Spring Boot中使用配置元数据Pimp您的配置》中的基础知识之后&#xff0c;现在该看看如何进一步执行此步骤并进一步自定义配置。 在这篇文章中&#xff0c;我计划提出对配置属性的弃用&#xff0c;并讨论各种值提供程序&#x…

ssh 与 telnet 有何不同?_采用创新面料Nike Infinalon的全新瑜珈系列究竟有何不同?...

采用创新面料Nike Infinalon的全新瑜珈系列究竟有何不同&#xff1f;无拘无束自由运动——这是耐克瑜伽系列新品的核心设计理念。全新系列为你提供垫上瑜伽时毫无束缚的舒适感&#xff0c;采用了耐克创新型面料&#xff1a;Nike Infinalon。Nike Infinalon应用于耐克最新瑜伽系…

matlab中的导函数驻点,Matlab用导数作定性分析

Matlab用导数作定性分析5.1知识要点&#xff1a;函数作图 —用导数定性描述函数【 clf,xlinspace(-8,8,30);f(x-3).^2./(4*(x-1)); plot(x,f) 】【 fplot((x-3)^2/(4*(x-1)),[-8,8])) 】【 clf,xsym(x); f(x-3)^2/(4*(x-1)); ezplot(f,[-8,8]) ,ti…

java lambda循环_使用Java 8 Lambda简化嵌套循环

java lambda循环对于每个经常需要在Java 8&#xff08;或更高版本&#xff09;中使用多维数组的人来说&#xff0c;这只是一个快速技巧。 在这种情况下&#xff0c;您可能经常会以类似于以下代码的结尾&#xff1a; float[][] values ... for (int i 0; i < values.leng…

原生态基于OpenCV图像处理软件开发

部分功能效果图 GitHub:https://github.com/CnYiXiaoNaiHe/OpenCV- 持续更新