在自定义Java Gradle插件中使用Reflections生成注解类/方法报告
实现多模块Gradle项目中基于Reflections的注解报告插件
我来帮你搞定这个在多模块Gradle项目里用自定义Java插件结合Reflections生成注解报告的需求,咱们一步步来:
1. 梳理你已有的基础配置
先把你给出的配置清晰整理出来,确保基础结构没问题:
项目根目录 /build.gradle
apply plugin: com.my.plugins.MyPlugin
/buildSrc/build.gradle 依赖配置
这里引入Reflections和注解API的配置是正确的,不过如果你的Gradle版本在7.0+,推荐把compile换成implementation:
repositories { mavenCentral() } dependencies { implementation 'org.reflections:reflections:0.9.11' implementation 'javax.annotation:javax.annotation-api:1.3.2' }
插件类基础结构 /buildSrc/src/main/java/com/my/plugins/MyPlugin.java
@NonNullApi public class MyPlugin implements Plugin<Project> { @Override public void apply(Project project) { // 核心实现逻辑将在这里补充 } }
2. 核心实现:扫描多模块并生成报告
因为是多模块项目,每个模块都有独立的编译输出,所以我们要给每个子模块单独注册扫描任务,确保能覆盖所有模块的类。
步骤1:给子模块注册自定义任务
在MyPlugin的apply方法中,为每个子模块添加生成报告的任务,并绑定依赖关系:
@Override public void apply(Project project) { // 遍历所有子模块,注册报告生成任务 project.getSubprojects().forEach(subproject -> { TaskProvider<GenerateAnnotationReportTask> reportTask = subproject.getTasks().register( "generateAnnotationReport", GenerateAnnotationReportTask.class, task -> { // 任务依赖子模块的Java编译任务,确保先编译再扫描 task.dependsOn(subproject.getTasks().named("compileJava")); // 指定扫描目录:子模块的编译输出类目录 task.setClassesDir(subproject.getLayout().getBuildDirectory().dir("classes/java/main")); // 指定报告输出路径 task.setOutputFile(subproject.getLayout().getBuildDirectory().file("reports/annotation-report.txt")); } ); // 把报告任务挂到check任务的依赖中,执行check时自动生成报告 subproject.getTasks().named("check").configure(checkTask -> checkTask.dependsOn(reportTask)); }); }
步骤2:实现自定义任务类 GenerateAnnotationReportTask
这个类是核心,负责用Reflections扫描注解并生成报告:
import org.reflections.Reflections; import org.reflections.scanners.Scanners; import org.reflections.util.ClasspathHelper; import org.reflections.util.ConfigurationBuilder; import org.gradle.api.DefaultTask; import org.gradle.api.file.DirectoryProperty; import org.gradle.api.file.RegularFileProperty; import org.gradle.api.tasks.InputDirectory; import org.gradle.api.tasks.OutputFile; import org.gradle.api.tasks.TaskAction; import java.io.FileWriter; import java.io.IOException; import java.util.Set; public class GenerateAnnotationReportTask extends DefaultTask { private final DirectoryProperty classesDir = getProject().getObjects().directoryProperty(); private final RegularFileProperty outputFile = getProject().getObjects().fileProperty(); @InputDirectory public DirectoryProperty getClassesDir() { return classesDir; } @OutputFile public RegularFileProperty getOutputFile() { return outputFile; } @TaskAction public void generateReport() throws IOException { // 构建Reflections配置,指定要扫描的类目录 ConfigurationBuilder config = new ConfigurationBuilder() .setUrls(ClasspathHelper.forDirectory(classesDir.get().getAsFile())) .setScanners(Scanners.TypesAnnotated, Scanners.MethodsAnnotated); Reflections reflections = new Reflections(config); // 替换成你实际要扫描的注解类 Set<Class<?>> annotatedClasses = reflections.getTypesAnnotatedWith(YourClassAnnotation.class); Set<java.lang.reflect.Method> annotatedMethods = reflections.getMethodsAnnotatedWith(YourMethodAnnotation.class); // 拼接报告内容 StringBuilder reportContent = new StringBuilder(); reportContent.append("=== Annotation Report for Module: ").append(getProject().getName()).append(" ===\n\n"); reportContent.append("Classes with @YourClassAnnotation:\n"); annotatedClasses.forEach(clazz -> reportContent.append("- ").append(clazz.getCanonicalName()).append("\n")); reportContent.append("\nMethods with @YourMethodAnnotation:\n"); annotatedMethods.forEach(method -> reportContent.append("- ").append(method.getDeclaringClass().getCanonicalName()) .append("#").append(method.getName()).append("\n")); // 写入报告文件 FileWriter writer = new FileWriter(outputFile.get().getAsFile()); writer.write(reportContent.toString()); writer.close(); getLogger().lifecycle("Generated annotation report at: {}", outputFile.get().getAsFile().getAbsolutePath()); } }
3. 关键注意事项
- 替换注解类:一定要把代码里的
YourClassAnnotation和YourMethodAnnotation替换成你实际需要扫描的注解类。 - 扩展扫描范围:如果需要扫描带注解的字段、构造方法等,可以调整
Scanners的类型,比如添加Scanners.FieldsAnnotated。 - 依赖模块扫描:如果某个模块依赖其他模块的类,需要把依赖模块的编译输出目录也加入扫描路径,可以通过子模块的
sourceSets获取依赖类路径。
4. 执行方式
在项目根目录执行以下命令,即可为所有子模块生成注解报告:
./gradlew generateAnnotationReport
或者执行check任务,会自动触发报告生成:
./gradlew check
内容的提问来源于stack exchange,提问作者G. Miller
相关产品推荐
相关产品推荐

