【错误记录】Android 编译时技术报错 ( 注解处理器 process 方法多次调用问题 )
文章目錄
- 一、報錯信息
- 二、問題分析
- 三、解決方案
注解處理器 AbstractProcessor 中的 process 方法可能會調用多次 , 在生成代碼時 , 一定要注意 , 檢測到 注解節點 后再生成代碼 ;
一、報錯信息
Android 編譯時技術 , 使用注解處理器生成代碼 , 編譯時報如下錯誤 :
( 該錯誤不會中斷編譯 )
javax.annotation.processing.FilerException: Attempt to recreate a file for type com.example.helloworld.HelloWorldat com.sun.tools.javac.processing.JavacFiler.checkNameAndExistence(JavacFiler.java:522)at com.sun.tools.javac.processing.JavacFiler.createSourceOrClassFile(JavacFiler.java:396)at com.sun.tools.javac.processing.JavacFiler.createSourceFile(JavacFiler.java:378)at com.squareup.javapoet.JavaFile.writeTo(JavaFile.java:169)at kim.hsl.router_compiler.RouterProcessor.process(RouterProcessor.java:91)at org.gradle.api.internal.tasks.compile.processing.DelegatingProcessor.process(DelegatingProcessor.java:62)at org.gradle.api.internal.tasks.compile.processing.NonIncrementalProcessor.process(NonIncrementalProcessor.java:45)at org.gradle.api.internal.tasks.compile.processing.DelegatingProcessor.process(DelegatingProcessor.java:62)at org.gradle.api.internal.tasks.compile.processing.TimeTrackingProcessor.access$401(TimeTrackingProcessor.java:37)at org.gradle.api.internal.tasks.compile.processing.TimeTrackingProcessor$5.create(TimeTrackingProcessor.java:99)at org.gradle.api.internal.tasks.compile.processing.TimeTrackingProcessor$5.create(TimeTrackingProcessor.java:96)at org.gradle.api.internal.tasks.compile.processing.TimeTrackingProcessor.track(TimeTrackingProcessor.java:117)at org.gradle.api.internal.tasks.compile.processing.TimeTrackingProcessor.process(TimeTrackingProcessor.java:96)at com.sun.tools.javac.processing.JavacProcessingEnvironment.callProcessor(JavacProcessingEnvironment.java:794)at com.sun.tools.javac.processing.JavacProcessingEnvironment.discoverAndRunProcs(JavacProcessingEnvironment.java:705)at com.sun.tools.javac.processing.JavacProcessingEnvironment.access$1800(JavacProcessingEnvironment.java:91)at com.sun.tools.javac.processing.JavacProcessingEnvironment$Round.run(JavacProcessingEnvironment.java:1035)at com.sun.tools.javac.processing.JavacProcessingEnvironment.doProcessing(JavacProcessingEnvironment.java:1176)at com.sun.tools.javac.main.JavaCompiler.processAnnotations(JavaCompiler.java:1170)at com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:856)at com.sun.tools.javac.main.Main.compile(Main.java:523)at com.sun.tools.javac.api.JavacTaskImpl.doCall(JavacTaskImpl.java:129)at com.sun.tools.javac.api.JavacTaskImpl.call(JavacTaskImpl.java:138)at org.gradle.internal.compiler.java.IncrementalCompileTask.call(IncrementalCompileTask.java:74)二、問題分析
根據上述報錯信息提示 " Attempt to recreate a file " , 嘗試重新創建一個文件 , 也就是說之前已經創建了一次文件 ;
注解處理器代碼如下 :
package kim.hsl.router_compiler;import com.google.auto.service.AutoService; import com.squareup.javapoet.JavaFile; import com.squareup.javapoet.MethodSpec; import com.squareup.javapoet.TypeSpec;import java.io.IOException; import java.util.Set;import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.Filer; import javax.annotation.processing.Messager; import javax.annotation.processing.ProcessingEnvironment; import javax.annotation.processing.Processor; import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.SupportedAnnotationTypes; import javax.annotation.processing.SupportedSourceVersion; import javax.lang.model.SourceVersion; import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; import javax.tools.Diagnostic;// 自動注冊注解處理器 @AutoService(Processor.class) // 支持的注解類型 @SupportedAnnotationTypes({"kim.hsl.router_annotation.Route"}) // 支持的 Java 版本 @SupportedSourceVersion(SourceVersion.RELEASE_8) public class RouterProcessor extends AbstractProcessor {/*** 注解處理器中使用 Messager 對象打印日志*/private Messager mMessager;/*** 用于寫出生成的 Java 代碼*/private Filer mFiler;/*** 該函數在初始化時調用 , 相當于構造函數* @param processingEnvironment*/@Overridepublic synchronized void init(ProcessingEnvironment processingEnvironment) {super.init(processingEnvironment);// 獲取打印日志接口this.mMessager = processingEnvironment.getMessager();mMessager.printMessage(Diagnostic.Kind.NOTE, "Messager Print Log");this.mFiler = processingEnvironment.getFiler();}/*** 該函數在注解處理器注冊時自動執行, 是處理注解的核心函數** Set<? extends TypeElement> set 參數 : 該集合表示使用了相關注解的節點的集合** @param set* @param roundEnvironment* @return*/@Overridepublic boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {for (TypeElement typeElement: set){mMessager.printMessage(Diagnostic.Kind.NOTE, "SupportedAnnotationTypes : " + typeElement.getQualifiedName());}// 生成 public static void main(String[] args) 函數MethodSpec main = MethodSpec.methodBuilder("main").addModifiers(Modifier.PUBLIC, Modifier.STATIC).returns(void.class).addParameter(String[].class, "args").addStatement("$T.out.println($S)", System.class, "Hello, JavaPoet!").build();// 指定 public final class HelloWorld 類TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld").addModifiers(Modifier.PUBLIC, Modifier.FINAL).addMethod(main).build();// 正式在 "com.example.helloworld" 包名下創建 HelloWorld 類JavaFile javaFile = JavaFile.builder("com.example.helloworld", helloWorld).build();try {javaFile.writeTo(mFiler);} catch (IOException e) {e.printStackTrace();}return false;} }在 process 方法中 , 使用 JavaPoet 生成 Java 代碼 ;
上述 process 方法應該是調用 333 次 , 調用第一次時生成了 com.example.helloworld.HelloWorld 源碼 , 但是后面又調用了 222 次 , 后面調用的 222 次直接報上述 " javax.annotation.processing.FilerException: Attempt to recreate a file for type com.example.helloworld.HelloWorld " 錯誤 ;
三、解決方案
AbstractProcessor 中的 process 方法調用了 333 次 , 但是只有 111 次 Set<? extends TypeElement> set 注解參數不為空 , 這里檢測到注解后 , 再生成 Java 代碼即可 ;
修改后的源代碼如下 :
package kim.hsl.router_compiler;import com.google.auto.service.AutoService; import com.squareup.javapoet.JavaFile; import com.squareup.javapoet.MethodSpec; import com.squareup.javapoet.TypeSpec;import java.io.IOException; import java.util.Set;import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.Filer; import javax.annotation.processing.Messager; import javax.annotation.processing.ProcessingEnvironment; import javax.annotation.processing.Processor; import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.SupportedAnnotationTypes; import javax.annotation.processing.SupportedSourceVersion; import javax.lang.model.SourceVersion; import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; import javax.tools.Diagnostic;// 自動注冊注解處理器 @AutoService(Processor.class) // 支持的注解類型 @SupportedAnnotationTypes({"kim.hsl.router_annotation.Route"}) // 支持的 Java 版本 @SupportedSourceVersion(SourceVersion.RELEASE_8) public class RouterProcessor extends AbstractProcessor {/*** 注解處理器中使用 Messager 對象打印日志*/private Messager mMessager;/*** 用于寫出生成的 Java 代碼*/private Filer mFiler;/*** 該函數在初始化時調用 , 相當于構造函數* @param processingEnvironment*/@Overridepublic synchronized void init(ProcessingEnvironment processingEnvironment) {super.init(processingEnvironment);// 獲取打印日志接口this.mMessager = processingEnvironment.getMessager();mMessager.printMessage(Diagnostic.Kind.NOTE, "Messager Print Log");this.mFiler = processingEnvironment.getFiler();}/*** 該函數在注解處理器注冊時自動執行, 是處理注解的核心函數** Set<? extends TypeElement> set 參數 : 該集合表示使用了相關注解的節點的集合** @param set* @param roundEnvironment* @return*/@Overridepublic boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {for (TypeElement typeElement: set){mMessager.printMessage(Diagnostic.Kind.NOTE, "SupportedAnnotationTypes : " + typeElement.getQualifiedName());// 生成 public static void main(String[] args) 函數MethodSpec main = MethodSpec.methodBuilder("main").addModifiers(Modifier.PUBLIC, Modifier.STATIC).returns(void.class).addParameter(String[].class, "args").addStatement("$T.out.println($S)", System.class, "Hello, JavaPoet!").build();// 指定 public final class HelloWorld 類TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld").addModifiers(Modifier.PUBLIC, Modifier.FINAL).addMethod(main).build();// 正式在 "com.example.helloworld" 包名下創建 HelloWorld 類JavaFile javaFile = JavaFile.builder("com.example.helloworld", helloWorld).build();try {javaFile.writeTo(mFiler);} catch (IOException e) {e.printStackTrace();}}return false;} }修改后 , 編譯時不再報上述錯誤 ;
總結
以上是生活随笔為你收集整理的【错误记录】Android 编译时技术报错 ( 注解处理器 process 方法多次调用问题 )的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Android 组件化】路由组件 (
- 下一篇: 【字符串】最长回文子串 ( 蛮力算法 )