使用JavaParser 如何获取一个Java类中的某个方法的返回类型呢?
假如有一个如下的简单的Java 类:
/**
* Copyright (C) Oscar Chen(XM):
*
* Date: 2024-11-21
* Author: XM
*/
package com.osxm.ai.sdlc.codeparse.codesample;
public class MyClass {
public String myMethod(String str) {
return str;
}
}
- 该类有一个返回String 类型的方法myMethod()
使用JavaParser 如何获取myMethod的返回类型,也就是String 呢?
获取方法的返回类型类的简化名
这里直接给实现代码:
// @formatter:off
String sourceCode = "public class MyClass {" +
"public String myMethod(String str){" +
"return str;" +
"}" +
"}";
// @formatter:on
@Test
public void methodReturnClassSimpleName() {
CompilationUnit cu = StaticJavaParser.parse(sourceCode);
String methodName = "myMethod";
MethodDeclaration methodDecl = cu.findAll(MethodDeclaration.class).stream()
.filter(md -> md.getName().getIdentifier().equals(methodName))
.findFirst()
.orElseThrow(() -> new RuntimeException("Method not found"));
Type returnType = methodDecl.getType();
String returnSimpleClassName = returnType.asString();
Assertions.assertEquals("String", returnSimpleClassName); // 获取方法返回类型的简化名
}
代码解释如下:
CompilationUnit cu = StaticJavaParser.parse(sourceCode);
- 这行代码使用JavaParser库来解析给定的Java源代码字符串
sourceCode
,并将其转换为一个CompilationUnit
对象。CompilationUnit
是JavaParser中表示整个Java源文件的一个抽象语法树(AST)的根节点。
- 这行代码使用JavaParser库来解析给定的Java源代码字符串
String methodName = "myMethod";
- 这行代码定义了一个字符串变量
methodName
,并将其值设置为"myMethod"
。这是要查找的方法的名称。
- 这行代码定义了一个字符串变量
MethodDeclaration methodDecl = cu.findAll(MethodDeclaration.class).stream()
- 这行代码开始通过
cu
(即CompilationUnit
对象)查找所有的方法声明(MethodDeclaration
)。findAll(MethodDeclaration.class)
返回一个包含所有方法声明的列表。 .stream()
将这个列表转换为一个流(Stream),以便进行后续的流式处理。
- 这行代码开始通过
.filter(md -> md.getName().getIdentifier().equals(methodName))
- 这行代码使用
filter
方法过滤流中的元素。它保留那些其名称(通过md.getName().getIdentifier()
获取)等于methodName
(即"myMethod"
)的方法声明。
- 这行代码使用
.findFirst()
- 这行代码尝试从过滤后的流中找到第一个元素(即第一个匹配的方法声明)。如果找到,它返回一个包含该元素的
Optional<MethodDeclaration>
;如果没有找到,它返回一个空的Optional
。
- 这行代码尝试从过滤后的流中找到第一个元素(即第一个匹配的方法声明)。如果找到,它返回一个包含该元素的
.orElseThrow(() -> new RuntimeException("Method not found"));
- 这行代码处理上一步返回的
Optional
。如果Optional
是空的(即没有找到方法),则执行orElseThrow
,抛出一个RuntimeException
,异常信息为"Method not found"
。如果Optional
非空,即找到了方法,则将其值(MethodDeclaration
对象)赋给methodDecl
变量。
- 这行代码处理上一步返回的
Type returnType = methodDecl.getType();
- 这行代码获取
methodDecl
(即找到的myMethod
方法)的返回类型,并将其存储在returnType
变量中。
- 这行代码获取
String returnSimpleClassName = returnType.asString();
- 这行代码将
returnType
(即方法的返回类型)转换为其字符串表示形式,这里返回的是简化名。
- 这行代码将
Assertions.assertEquals("String", returnSimpleClassName);
- 这行代码使用JUnit的
Assertions
类来断言returnSimpleClassName
(即方法的返回类型的字符串表示)是否等于字符串"String"
。这是为了验证myMethod
方法的返回类型确实是String
。
- 这行代码使用JUnit的
现在问题来了, 如果要返回全限定名, 也就是这里的java.lang.String 要怎么处理呢?
获取方法的返回类型类的全限定名
同样,直接上代码:
@Test
public void methodReturnClassFullName() {
ReflectionTypeSolver reflectionTypeSolver = new ReflectionTypeSolver();
JavaSymbolSolver symbolSolver = new JavaSymbolSolver(reflectionTypeSolver);
// init parser
ParserConfiguration configuration = new ParserConfiguration().setSymbolResolver(symbolSolver);
// Setup parser
StaticJavaParser.setConfiguration(configuration);
CompilationUnit cu = StaticJavaParser.parse(sourceCode);
String methodName = "myMethod";
MethodDeclaration methodDecl = cu.findAll(MethodDeclaration.class).stream()
.filter(md -> md.getName().getIdentifier().equals(methodName))
.findFirst()
.orElseThrow(() -> new RuntimeException("Method not found"));
Type returnType = methodDecl.getType();
String returnSimpleClassName = returnType.asString();
Assertions.assertEquals("String", returnSimpleClassName); // 获取方法返回类型的简化名
String fullClassName = returnType.resolve().describe();
Assertions.assertEquals("java.lang.String", fullClassName); // 获取方法返回类型的全限定名
}
**重点: ** 要便捷的获取全限定名, 需要结合 JavaSymbolSolver ,也就是JavaParser-Symbol-Solver 这个库来使用。
完整的解释:
ReflectionTypeSolver
是JavaSymbolSolver库中的一个组件,它使用Java反射API来解析类路径上的Java类文件,以获取类型信息。JavaSymbolSolver
是一个更高级的组件,它使用TypeSolver
(在这个例子中是ReflectionTypeSolver
)来解决符号(如类型、方法等)的引用。- 这里创建了一个
ParserConfiguration
对象,并通过setSymbolResolver
方法设置了之前创建的JavaSymbolSolver
实例。 - 然后,使用
StaticJavaParser.setConfiguration
方法将这个配置应用到JavaParser上。这样,当JavaParser解析源代码时,它就可以使用JavaSymbolSolver来解决符号引用了。 returnType.resolve().describe()
返回类型的完全描述,这通常包括类型的完全限定名以及任何泛型信息。对于基本类型或String
等常见类型,这将返回它们的完全限定名。
完整代码如下:
/**
* Copyright (C) Oscar Chen(XM):
*
* Date: 2024-11-21
* Author: XM
*/
package com.osxm.ai.sdlc.javaparser;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import com.github.javaparser.ParserConfiguration;
import com.github.javaparser.StaticJavaParser;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.type.Type;
import com.github.javaparser.symbolsolver.JavaSymbolSolver;
import com.github.javaparser.symbolsolver.resolution.typesolvers.ReflectionTypeSolver;
public class MethodInfo {
// @formatter:off
String sourceCode = "public class MyClass {" +
"public String myMethod(String str){" +
"return str;" +
"}" +
"}";
// @formatter:on
@Test
public void methodReturnClassSimpleName() {
CompilationUnit cu = StaticJavaParser.parse(sourceCode);
String methodName = "myMethod";
MethodDeclaration methodDecl = cu.findAll(MethodDeclaration.class).stream()
.filter(md -> md.getName().getIdentifier().equals(methodName))
.findFirst()
.orElseThrow(() -> new RuntimeException("Method not found"));
Type returnType = methodDecl.getType();
String returnSimpleClassName = returnType.asString();
Assertions.assertEquals("String", returnSimpleClassName); // 获取方法返回类型的简化名
}
@Test
public void methodReturnClassFullName() {
ReflectionTypeSolver reflectionTypeSolver = new ReflectionTypeSolver();
JavaSymbolSolver symbolSolver = new JavaSymbolSolver(reflectionTypeSolver);
// init parser
ParserConfiguration configuration = new ParserConfiguration().setSymbolResolver(symbolSolver);
// Setup parser
StaticJavaParser.setConfiguration(configuration);
CompilationUnit cu = StaticJavaParser.parse(sourceCode);
String methodName = "myMethod";
MethodDeclaration methodDecl = cu.findAll(MethodDeclaration.class).stream()
.filter(md -> md.getName().getIdentifier().equals(methodName))
.findFirst()
.orElseThrow(() -> new RuntimeException("Method not found"));
Type returnType = methodDecl.getType();
String returnSimpleClassName = returnType.asString();
Assertions.assertEquals("String", returnSimpleClassName); // 获取方法返回类型的简化名
String fullClassName = returnType.resolve().describe();
Assertions.assertEquals("java.lang.String", fullClassName); // 获取方法返回类型的全限定名
}
}