JavaParser生成,分析和修改Java代码_最佳 Java 编程-CSDN博客

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

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

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

原网址: 访问
创建于: 2021-12-28 20:24:57
目录: default
标签: 无

请先后发表评论
  • 最新评论
  • 总共0条评论