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

时间:2024-10-13 07:44:23

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进行代码生成的含义。

  1. CompilationUnit cu = new CompilationUnit();
  2. ("");
  3. ClassOrInterfaceDeclaration book = ("Book");
  4. ("String", "title");
  5. ("Person", "author");
  6. ()
  7. .addParameter("String", "title")
  8. .addParameter("Person", "author")
  9. .setBody(new BlockStmt()
  10. .addStatement(new ExpressionStmt(new AssignExpr(
  11. new FieldAccessExpr(new ThisExpr(), "title"),
  12. new NameExpr("title"),
  13. )))
  14. .addStatement(new ExpressionStmt(new AssignExpr(
  15. new FieldAccessExpr(new ThisExpr(), "author"),
  16. new NameExpr("author"),
  17. ))));
  18. ("getTitle", ).setBody(
  19. new BlockStmt().addStatement(new ReturnStmt(new NameExpr("title"))));
  20. ("getAuthor", ).setBody(
  21. new BlockStmt().addStatement(new ReturnStmt(new NameExpr("author"))));
  22. (());

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

使用javaparser分析代码

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

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

  1. // Parse all source files
  2. SourceRoot sourceRoot = new SourceRoot(());
  3. (parserConfiguration);
  4. List<ParseResult> parseResults = ("");
  5. // Now get all compilation unitsList
  6. allCus = ()
  7. .filter(ParseResult::isSuccessful)
  8. .map(r -> ().get())
  9. .collect(());

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

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

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

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

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

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

  1. getNodes(allCus, ClassOrInterfaceDeclaration.class) .stream() .filter(c -> !()) .sorted((o ->
  2. -1 * ().size())) .limit(3) .forEach(c ->
  3. (() + ": " + ().size() + " methods"));

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

使用javaparser转换代码

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

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

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

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

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

  1. myCompilationUnit.findAll()
  2. .stream()
  3. .filter(m -> m.resolveInvokedMethod()
  4. .getQualifiedSignature()
  5. .equals("(, int)"))
  6. .forEach(m -> m.replace(replaceCallsToOldMethod(m)));

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

  1. public MethodCallExpr replaceCallsToOldMethod(MethodCallExpr methodCall) {
  2. MethodCallExpr newMethodCall = new MethodCallExpr(
  3. ().get(), "newMethod");
  4. ((1));
  5. ((0));
  6. (new BooleanLiteralExpr(true));
  7. return newMethodCall;
  8. }

太酷了,现在我们只需要获取修改后的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代码。

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

翻译自: /2017/12/

javaparser