首页 > 基础资料 博客日记
Javaparse包的使用和讲解
2024-07-03 08:00:05基础资料围观207次
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
类提供了一系列方法用于设置解析器的配置选项。以下是所有可用的设置方法:
setLanguageLevel(LanguageLevel level)
: 设置解析器使用的语言级别。setAttributeComments(boolean attributeComments)
: 设置是否解析属性的注释。setLexicalPreservationEnabled(boolean lexicalPreservationEnabled)
: 设置是否启用词法保留。setTabSize(int tabSize)
: 设置解析器使用的制表符大小。setColumnStart(int columnStart)
: 设置解析器的起始列。setColumnEnd(int columnEnd)
: 设置解析器的结束列。setTabulationSize(int tabulationSize)
: 设置解析器的制表符大小。setPreprocessUnicodeEscapes(boolean preprocessUnicodeEscapes)
: 设置是否预处理 Unicode 转义字符。setAutoCloseEnabled(boolean autoCloseEnabled)
: 设置是否启用自动关闭功能。setAutomaticImports(boolean automaticImports)
: 设置是否自动导入。setLexicalPreservationEnabled(boolean lexicalPreservationEnabled)
: 设置是否启用词法保留。
ParserConfiguration
类中提供了一些获取配置选项的方法,你可以使用这些方法来获取当前配置的信息。以下是所有可用的获取方法:
getLanguageLevel()
: 获取解析器使用的语言级别。isAttributeComments()
: 获取是否解析属性的注释。isLexicalPreservationEnabled()
: 获取是否启用词法保留。getTabSize()
: 获取解析器使用的制表符大小。getColumnStart()
: 获取解析器的起始列。getColumnEnd()
: 获取解析器的结束列。getTabulationSize()
: 获取解析器的制表符大小。isPreprocessUnicodeEscapes()
: 获取是否预处理 Unicode 转义字符。isAutoCloseEnabled()
: 获取是否启用自动关闭功能。isAutomaticImports()
: 获取是否自动导入。isLexicalPreservationEnabled()
: 获取是否启用词法保留。
你可以使用这些方法来获取当前配置的信息,并根据需要进行进一步处理。
在此有几个概念的辨析:
语言级别
指的是解析器使用的编程语言的版本或规范。在 JavaParser 中,语言级别可以设置为不同的 Java 版本,例如 Java 8、Java 11 等。这决定了解析器在解析代码时会考虑哪些语言特性和语法规则。
词法保留(Lexical Preservation)
指的是在解析代码时保留代码的原始格式和排版。启用词法保留功能后,解析器将尽可能地保留代码中的空格、缩进、换行符等词法结构,以保持代码的视觉布局和格式不变。这对于需要保留代码原始格式的应用场景非常有用,例如代码转换、代码生成、代码格式化等。
制表符大小(Tab Size)
是指在解析器中使用的制表符的宽度。制表符是一种特殊字符,通常用于在代码中表示缩进。制表符大小表示一个制表符字符在文本中所占的空格数目。例如,如果制表符大小为 4,则一个制表符字符在文本中将会被替换为四个空格字符。这有助于在不同的编辑器和环境中保持代码的一致缩进样式。
标题自动关闭(Auto-closing)和自动导入(Auto-import)是在编程环境中常见的功能。
-
自动关闭:指的是编辑器或IDE(集成开发环境)在输入代码时自动补全相应的闭合符号,例如括号、引号、标签等。这样可以减少编码过程中的疏忽或错误,提高编码效率和代码质量。例如,当你输入左括号时,编辑器会自动添加右括号,并将光标放置在括号中间,方便你输入括号内的内容。
-
自动导入:指的是编辑器或IDE根据你的代码内容自动引入所需的外部模块、库或类。当你在代码中使用了未导入的模块或类时,编辑器会自动检测并提供导入建议,你可以通过快捷键或点击建议来自动导入所需的内容。这样可以减少手动导入的工作量,并确保代码的正确性和一致性。
parse()方法有多个参数不同的重载,支持文件流,字符串的解析 ,同时也有对单个语句进行解析的方法parse
在 JavaParser 中,解析 Java 代码有多种方法,取决于您想要解析的代码的类型和结构。以下是一些常用的解析方法:
- 解析整个 Java 文件(Compilation Unit):
ParseResult<CompilationUnit> result = StaticJavaParser.parse(file);
- 解析代码块(Block):
ParseResult<BlockStmt> result = StaticJavaParser.parseBlock(code);
- 解析表达式(Expression):
ParseResult<Expression> result = StaticJavaParser.parseExpression(expression);
- 解析语句(Statement):
ParseResult<Statement> result = StaticJavaParser.parseStatement(statement);
- 解析类型(Type):
ParseResult<Type> result = StaticJavaParser.parseType(type);
- 解析注解(Annotation):
ParseResult<AnnotationExpr> result = StaticJavaParser.parseAnnotation(annotation);
- 解析名称(Name):
ParseResult<Name> result = StaticJavaParser.parseName(name);
- 解析 import 语句:
ParseResult<ImportDeclaration> result = StaticJavaParser.parseImport(importDeclaration);
- 解析注释(Comment):
ParseResult<Comment> result = StaticJavaParser.parseComment(comment);
以上代码中的 file
、code
、expression
、statement
、type
、annotation
、name
、importDeclaration
、comment
分别是您要解析的 Java 文件、代码片段、表达式、语句、类型、注解、名称、import 语句、注释。
您可以根据需要选择适合您情况的解析方法。
除此之外 你还可以通过staticJavaParser这个类的静态方法直接调用这些函数
结果类 ParesResult 类
ParseResult<T>
是 JavaParser 中的一个泛型类,用于表示解析操作的结果。它通常包含两个主要部分:
-
解析成功与否的状态信息:通过
isSuccessful()
方法可以获取解析是否成功的布尔值。如果解析成功,则可以通过getResult()
方法获取解析得到的对象;如果解析失败,则可以通过getProblems()
方法获取解析过程中遇到的问题列表。 -
解析得到的对象:泛型类型
T
表示解析得到的对象的类型。根据解析操作的不同,可以得到不同类型的对象,例如CompilationUnit
、BlockStmt
、Expression
等。
通常,您可以按照以下方式使用 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 中常见的节点类:
-
CompilationUnit(编译单元):表示整个 Java 源文件的抽象语法树。它是 AST 的根节点。
-
PackageDeclaration(包声明):表示 Java 源文件中的包声明。
-
ImportDeclaration(导入声明):表示 Java 源文件中的导入声明。
-
ClassOrInterfaceDeclaration(类或接口声明):表示类或接口的声明。
-
FieldDeclaration(字段声明):表示类或接口中的字段声明。
-
MethodDeclaration(方法声明):表示类或接口中的方法声明。
-
ConstructorDeclaration(构造函数声明):表示类的构造函数声明。
-
EnumDeclaration(枚举声明):表示枚举类型的声明。
-
EnumConstantDeclaration(枚举常量声明):表示枚举类型中的常量声明。
-
AnnotationDeclaration(注解声明):表示注解类型的声明。
-
AnnotationMemberDeclaration(注解成员声明):表示注解类型中的成员声明。
-
Parameter(参数):表示方法或构造函数的参数。
-
VariableDeclarator(变量声明符):表示变量的声明符号。
-
Expression(表达式):表示 Java 中的各种表达式,如赋值表达式、方法调用、算术表达式等。
-
Statement(语句):表示 Java 中的各种语句,如 if 语句、for 循环、while 循环等。
-
Type(类型):表示 Java 中的各种类型,如基本类型、类类型、数组类型等。
-
AnnotationExpr(注解表达式):表示 Java 中的注解。
-
Name(名称):表示 Java 中的标识符名称。
-
Comment(注释):表示 Java 源代码中的注释。
这些节点类构成了 JavaParser 中的 AST(抽象语法树),可以通过解析 Java 源代码得到相应的节点对象,并通过这些节点对象进行语法分析、代码生成等操作。
他们都继承了Node这个类,除此之外,你可以通过操纵NodeList这个容器类来实现遍历的操作
这些节点类在 JavaParser 中都有一些常用的方法,用于获取节点的属性、进行节点的遍历和修改等操作。以下是这些节点类常用的方法:
-
获取节点的名称、类型等属性:
getName()
: 获取节点的名称。getType()
: 获取节点的类型。- 其他类似的获取属性的方法,根据节点类型的不同而有所不同。
-
获取节点的子节点:
getChildNodes()
: 获取节点的所有子节点。- 根据节点的类型,可能会有特定的方法来获取特定类型的子节点。
-
遍历节点的属性:
- 根据节点的类型和属性的不同,通常会有一些遍历属性的方法,例如获取方法的参数列表、获取字段的类型等。
-
修改节点的属性:
- 根据节点的类型和属性的不同,通常会有一些设置属性的方法,例如设置方法的参数列表、设置字段的类型等。
-
判断节点类型:
isMethodDeclaration()
: 判断节点是否是方法声明。isFieldDeclaration()
: 判断节点是否是字段声明。isExpressionStmt()
: 判断节点是否是表达式语句。- 其他类似的判断节点类型的方法,根据节点类型的不同而有所不同。
-
节点的位置信息:
getBegin()
和getEnd()
: 获取节点在源代码中的起始位置和结束位置。getRange()
: 获取节点在源代码中的范围。
-
节点的文本表示:
toString()
: 获取节点的文本表示。
-
节点的克隆和复制:
clone()
: 克隆节点,生成一个与原节点相同的新节点。cloneForImport()
等特定的克隆方法,用于在导入节点时进行克隆。
-
其他操作:
- 根据节点类型的不同,可能会有其他特定的方法用于特定操作,如获取方法的异常列表、获取注解的成员列表等。
这些方法可以帮助您对节点进行各种操作,包括遍历、修改、分析等。具体使用哪些方法取决于您的需求和对节点的操作目的。
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());
}
}
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:jacktools123@163.com进行投诉反馈,一经查实,立即删除!
标签: