首页 > 基础资料 博客日记

Javaparse包的使用和讲解

2024-07-03 08:00:05基础资料围观14

文章Javaparse包的使用和讲解分享给大家,欢迎收藏Java资料网,专注分享技术知识

JavaParser 是一个开源的 Java 源代码解析器和操作库,它能够解析 Java 源代码并构建对应的抽象语法树(AST)。JavaParser 提供了一组 API,使得开发者可以轻松地分析、修改和生成 Java 源代码。据此,你可以通过这些API来实现Java动态编译,原生的java库有javax.tools,但可惜不能支持对于AST的修改

著名的java效率包lombok的底层实现原理就是基于对java的AST的修改。

如何下载javapraser

(1) Maven下载,下文附上依赖坐标

<dependency>
    <groupId>com.github.javaparser</groupId>
    <artifactId>javaparser-core</artifactId>
    <version>最新版本号</version>
</dependency>

(2)Gradle下载

implementation 'com.github.javaparser:javaparser-core:最新版本号'

(3)源地址下载:github
直接下载jar包

##在最新的3.25.10版的API中,使用了大量的函数式编程。

JavaParser类是源代码的解析器,可以通过使用其实例的parse()方法解析源代码或字符串得到一个解析结果ParseResult

public class Test{
public static void main(String args[]){
 ParserConfiguration parserConfiguration = new ParserConfiguration();
        JavaParser javaParser = new JavaParser(parserConfiguration);
String code = "public class HelloWorld {\n" +
                      "    public static void main(String[] args) {\n" +
                      "        System.out.println(\"Hello, JavaParser!\");\n" +
                      "    }\n" +
                      "}";

        // 解析代码
        ParseResult<CompilationUnit> compilationUnit = javaParser.parse(code);
        
}

Javaparser有两种构造方法
无参构造 JavaParser()
有参构造 Java Parser(ParserConfiguration)
ParserConfiguration用于配置一些选项
ParserConfiguration 类提供了一系列方法用于设置解析器的配置选项。以下是所有可用的设置方法:

  1. setLanguageLevel(LanguageLevel level): 设置解析器使用的语言级别。
  2. setAttributeComments(boolean attributeComments): 设置是否解析属性的注释。
  3. setLexicalPreservationEnabled(boolean lexicalPreservationEnabled): 设置是否启用词法保留。
  4. setTabSize(int tabSize): 设置解析器使用的制表符大小。
  5. setColumnStart(int columnStart): 设置解析器的起始列。
  6. setColumnEnd(int columnEnd): 设置解析器的结束列。
  7. setTabulationSize(int tabulationSize): 设置解析器的制表符大小。
  8. setPreprocessUnicodeEscapes(boolean preprocessUnicodeEscapes): 设置是否预处理 Unicode 转义字符。
  9. setAutoCloseEnabled(boolean autoCloseEnabled): 设置是否启用自动关闭功能。
  10. setAutomaticImports(boolean automaticImports): 设置是否自动导入。
  11. setLexicalPreservationEnabled(boolean lexicalPreservationEnabled): 设置是否启用词法保留。

ParserConfiguration 类中提供了一些获取配置选项的方法,你可以使用这些方法来获取当前配置的信息。以下是所有可用的获取方法:

  1. getLanguageLevel(): 获取解析器使用的语言级别。
  2. isAttributeComments(): 获取是否解析属性的注释。
  3. isLexicalPreservationEnabled(): 获取是否启用词法保留。
  4. getTabSize(): 获取解析器使用的制表符大小。
  5. getColumnStart(): 获取解析器的起始列。
  6. getColumnEnd(): 获取解析器的结束列。
  7. getTabulationSize(): 获取解析器的制表符大小。
  8. isPreprocessUnicodeEscapes(): 获取是否预处理 Unicode 转义字符。
  9. isAutoCloseEnabled(): 获取是否启用自动关闭功能。
  10. isAutomaticImports(): 获取是否自动导入。
  11. isLexicalPreservationEnabled(): 获取是否启用词法保留。

你可以使用这些方法来获取当前配置的信息,并根据需要进行进一步处理。

在此有几个概念的辨析:
语言级别
指的是解析器使用的编程语言的版本或规范。在 JavaParser 中,语言级别可以设置为不同的 Java 版本,例如 Java 8、Java 11 等。这决定了解析器在解析代码时会考虑哪些语言特性和语法规则。

词法保留(Lexical Preservation)
指的是在解析代码时保留代码的原始格式和排版。启用词法保留功能后,解析器将尽可能地保留代码中的空格、缩进、换行符等词法结构,以保持代码的视觉布局和格式不变。这对于需要保留代码原始格式的应用场景非常有用,例如代码转换、代码生成、代码格式化等。

制表符大小(Tab Size)
是指在解析器中使用的制表符的宽度。制表符是一种特殊字符,通常用于在代码中表示缩进。制表符大小表示一个制表符字符在文本中所占的空格数目。例如,如果制表符大小为 4,则一个制表符字符在文本中将会被替换为四个空格字符。这有助于在不同的编辑器和环境中保持代码的一致缩进样式。

标题自动关闭(Auto-closing)和自动导入(Auto-import)是在编程环境中常见的功能。

  1. 自动关闭:指的是编辑器或IDE(集成开发环境)在输入代码时自动补全相应的闭合符号,例如括号、引号、标签等。这样可以减少编码过程中的疏忽或错误,提高编码效率和代码质量。例如,当你输入左括号时,编辑器会自动添加右括号,并将光标放置在括号中间,方便你输入括号内的内容。

  2. 自动导入:指的是编辑器或IDE根据你的代码内容自动引入所需的外部模块、库或类。当你在代码中使用了未导入的模块或类时,编辑器会自动检测并提供导入建议,你可以通过快捷键或点击建议来自动导入所需的内容。这样可以减少手动导入的工作量,并确保代码的正确性和一致性。

parse()方法有多个参数不同的重载,支持文件流,字符串的解析 ,同时也有对单个语句进行解析的方法parse

在 JavaParser 中,解析 Java 代码有多种方法,取决于您想要解析的代码的类型和结构。以下是一些常用的解析方法:

  1. 解析整个 Java 文件(Compilation Unit)
ParseResult<CompilationUnit> result = StaticJavaParser.parse(file);
  1. 解析代码块(Block)
ParseResult<BlockStmt> result = StaticJavaParser.parseBlock(code);
  1. 解析表达式(Expression)
ParseResult<Expression> result = StaticJavaParser.parseExpression(expression);
  1. 解析语句(Statement)
ParseResult<Statement> result = StaticJavaParser.parseStatement(statement);
  1. 解析类型(Type)
ParseResult<Type> result = StaticJavaParser.parseType(type);
  1. 解析注解(Annotation)
ParseResult<AnnotationExpr> result = StaticJavaParser.parseAnnotation(annotation);
  1. 解析名称(Name)
ParseResult<Name> result = StaticJavaParser.parseName(name);
  1. 解析 import 语句
ParseResult<ImportDeclaration> result = StaticJavaParser.parseImport(importDeclaration);
  1. 解析注释(Comment)
ParseResult<Comment> result = StaticJavaParser.parseComment(comment);

以上代码中的 filecodeexpressionstatementtypeannotationnameimportDeclarationcomment 分别是您要解析的 Java 文件、代码片段、表达式、语句、类型、注解、名称、import 语句、注释。

您可以根据需要选择适合您情况的解析方法。

除此之外 你还可以通过staticJavaParser这个类的静态方法直接调用这些函数

结果类 ParesResult 类

ParseResult<T> 是 JavaParser 中的一个泛型类,用于表示解析操作的结果。它通常包含两个主要部分:

  1. 解析成功与否的状态信息:通过 isSuccessful() 方法可以获取解析是否成功的布尔值。如果解析成功,则可以通过 getResult() 方法获取解析得到的对象;如果解析失败,则可以通过 getProblems() 方法获取解析过程中遇到的问题列表。

  2. 解析得到的对象:泛型类型 T 表示解析得到的对象的类型。根据解析操作的不同,可以得到不同类型的对象,例如 CompilationUnitBlockStmtExpression 等。

通常,您可以按照以下方式使用 ParseResult<T>

ParseResult<T> result = // 执行解析操作,获取解析结果

if (result.isSuccessful()) {
    // 解析成功
    T parsedObject = result.getResult();
    // 对解析得到的对象进行操作
} else {
    // 解析失败
    List<Problem> problems = result.getProblems();
    // 处理解析过程中遇到的问题
}

在这个例子中,根据 isSuccessful() 方法的返回值来判断解析操作是否成功,如果成功,则通过 getResult() 方法获取解析得到的对象进行后续操作,如果失败,则通过 getProblems() 方法获取解析过程中遇到的问题列表进行处理。

节点类Node

在 JavaParser 中,节点类用于表示 Java 源代码中的各种结构,如表达式、语句、类型、注解等。这些节点类都位于 com.github.javaparser.ast 包中。以下是 JavaParser 中常见的节点类:

  1. CompilationUnit(编译单元):表示整个 Java 源文件的抽象语法树。它是 AST 的根节点。

  2. PackageDeclaration(包声明):表示 Java 源文件中的包声明。

  3. ImportDeclaration(导入声明):表示 Java 源文件中的导入声明。

  4. ClassOrInterfaceDeclaration(类或接口声明):表示类或接口的声明。

  5. FieldDeclaration(字段声明):表示类或接口中的字段声明。

  6. MethodDeclaration(方法声明):表示类或接口中的方法声明。

  7. ConstructorDeclaration(构造函数声明):表示类的构造函数声明。

  8. EnumDeclaration(枚举声明):表示枚举类型的声明。

  9. EnumConstantDeclaration(枚举常量声明):表示枚举类型中的常量声明。

  10. AnnotationDeclaration(注解声明):表示注解类型的声明。

  11. AnnotationMemberDeclaration(注解成员声明):表示注解类型中的成员声明。

  12. Parameter(参数):表示方法或构造函数的参数。

  13. VariableDeclarator(变量声明符):表示变量的声明符号。

  14. Expression(表达式):表示 Java 中的各种表达式,如赋值表达式、方法调用、算术表达式等。

  15. Statement(语句):表示 Java 中的各种语句,如 if 语句、for 循环、while 循环等。

  16. Type(类型):表示 Java 中的各种类型,如基本类型、类类型、数组类型等。

  17. AnnotationExpr(注解表达式):表示 Java 中的注解。

  18. Name(名称):表示 Java 中的标识符名称。

  19. Comment(注释):表示 Java 源代码中的注释。

这些节点类构成了 JavaParser 中的 AST(抽象语法树),可以通过解析 Java 源代码得到相应的节点对象,并通过这些节点对象进行语法分析、代码生成等操作。

他们都继承了Node这个类,除此之外,你可以通过操纵NodeList这个容器类来实现遍历的操作

这些节点类在 JavaParser 中都有一些常用的方法,用于获取节点的属性、进行节点的遍历和修改等操作。以下是这些节点类常用的方法:

  1. 获取节点的名称、类型等属性

    • getName(): 获取节点的名称。
    • getType(): 获取节点的类型。
    • 其他类似的获取属性的方法,根据节点类型的不同而有所不同。
  2. 获取节点的子节点

    • getChildNodes(): 获取节点的所有子节点。
    • 根据节点的类型,可能会有特定的方法来获取特定类型的子节点。
  3. 遍历节点的属性

    • 根据节点的类型和属性的不同,通常会有一些遍历属性的方法,例如获取方法的参数列表、获取字段的类型等。
  4. 修改节点的属性

    • 根据节点的类型和属性的不同,通常会有一些设置属性的方法,例如设置方法的参数列表、设置字段的类型等。
  5. 判断节点类型

    • isMethodDeclaration(): 判断节点是否是方法声明。
    • isFieldDeclaration(): 判断节点是否是字段声明。
    • isExpressionStmt(): 判断节点是否是表达式语句。
    • 其他类似的判断节点类型的方法,根据节点类型的不同而有所不同。
  6. 节点的位置信息

    • getBegin()getEnd(): 获取节点在源代码中的起始位置和结束位置。
    • getRange(): 获取节点在源代码中的范围。
  7. 节点的文本表示

    • toString(): 获取节点的文本表示。
  8. 节点的克隆和复制

    • clone(): 克隆节点,生成一个与原节点相同的新节点。
    • cloneForImport() 等特定的克隆方法,用于在导入节点时进行克隆。
  9. 其他操作

    • 根据节点类型的不同,可能会有其他特定的方法用于特定操作,如获取方法的异常列表、获取注解的成员列表等。

这些方法可以帮助您对节点进行各种操作,包括遍历、修改、分析等。具体使用哪些方法取决于您的需求和对节点的操作目的。

import com.github.javaparser.StaticJavaParser;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.FieldDeclaration;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.body.Parameter;

public class Main {
    public static void main(String[] args) throws Exception {
        // 解析Java源代码
        CompilationUnit cu = StaticJavaParser.parse("public class MyClass {\n" +
                "    private int myField;\n" +
                "\n" +
                "    public void myMethod(int parameter) {\n" +
                "        System.out.println(\"Hello, world!\");\n" +
                "    }\n" +
                "}");

        // 获取类声明
        ClassOrInterfaceDeclaration classDeclaration = cu.getClassByName("MyClass").orElseThrow();
        String className = classDeclaration.getNameAsString();
        System.out.println("Class Name: " + className);

        // 获取字段声明
        FieldDeclaration fieldDeclaration = classDeclaration.getFieldByName("myField").orElseThrow();
        String fieldName = fieldDeclaration.getVariable(0).getNameAsString();
        System.out.println("Field Name: " + fieldName);

        // 获取方法声明
        MethodDeclaration methodDeclaration = classDeclaration.getMethodsByName("myMethod").get(0);
        String methodName = methodDeclaration.getNameAsString();
        System.out.println("Method Name: " + methodName);

        // 获取方法参数
        Parameter parameter = methodDeclaration.getParameter(0);
        String parameterName = parameter.getNameAsString();
        System.out.println("Parameter Name: " + parameterName);
    }
}

Type和TypeSolver类

TypeSolver 是 JavaParser 中用于解析和解决类型的重要类。它在 JavaParser 的类型处理过程中起着关键作用,特别是对于类类型的解析和解决。

以下是关于 TypeSolver 类的主要信息:

  • 作用TypeSolver 主要用于帮助 JavaParser 解析代码中的类引用,找到类的定义并建立类之间的关系,以便在语法树中正确表示类的继承、实现等关系。

  • 类型解析:通过配置适当的 TypeSolver,你可以确保 JavaParser 在解析代码时能够正确地处理类型信息,从而更准确地分析和理解代码。

  • 类引用解析TypeSolver 可以解析代码中对类的引用,例如在方法参数、变量声明等处使用的类名,通过解析这些引用,JavaParser 可以找到对应的类定义。

  • 类关系建立:除了解析类引用外,TypeSolver 还能够建立类之间的关系,包括类的继承关系、实现接口关系等。这些关系对于理解代码的结构和行为非常重要。

总的来说,TypeSolver 在 JavaParser 中扮演着重要的角色,通过解析和解决类型信息,帮助 JavaParser 更准确地理解和分析代码的结构和含义。

实例:

编译一个源文件,增加一个public void your(String str){System.out.println(str);}方法和删除源代码原本就有的一个字段,最后输出更改后的代码

 import java.util.function.Consumer;

import com.github.javaparser.StaticJavaParser;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.Modifier;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.FieldDeclaration;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.nodeTypes.NodeWithSimpleName;
import com.github.javaparser.ast.stmt.BlockStmt;
import com.github.javaparser.ast.stmt.ExpressionStmt;
import com.github.javaparser.ast.body.Parameter;

public class Main {
    public static void main(String[] args) {
        // 解析现有的源代码
        String code = "public class MyClass { " +
        				"public String myfield;"+
                      "    public void existingMethod() { " +
                      "        System.out.println(\"Existing method\"); " +
                      "    } " +
                      "}";
        
        CompilationUnit cu = StaticJavaParser.parse(code);
        
        // 创建一个新的方法声明
        final MethodDeclaration newMethod = new MethodDeclaration();
        
        // 设置新方法的修饰符为 public
        newMethod.addModifier(Modifier.Keyword.PUBLIC,Modifier.Keyword.STATIC);
        
        // 设置新方法的名称
        newMethod.setName("newMethod");
        
        // 添加参数
        Parameter parameter = new Parameter();
        parameter.setType("String");
        parameter.setName("arg");
        newMethod.addParameter(parameter);
      
   
        
        // 将新方法添加到类中
        cu.getClassByName("MyClass").ifPresent(new Consumer<ClassOrInterfaceDeclaration>() {
            public void accept(ClassOrInterfaceDeclaration classDeclaration) {
                classDeclaration.addMember(newMethod);
            }
        });
        
        // 移除字段
        // 获取类声明
        ClassOrInterfaceDeclaration classDeclaration = cu.getClassByName("MyClass").orElseThrow();
        
        // 通过字段名称获取 FieldDeclaration
        FieldDeclaration fieldDeclaration = classDeclaration.getFieldByName("myfield").orElseThrow();
        
        fieldDeclaration.remove();
        // 输出修改后的代码
        System.out.println(cu.toString());
    }
}

文章来源:https://blog.csdn.net/xwhxwhxhwwjx/article/details/137527874
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:jacktools123@163.com进行投诉反馈,一经查实,立即删除!

标签:

相关文章

本站推荐

标签云