文章目录

  • 一、报错信息
  • 二、问题分析
  • 三、解决方案

注解处理器 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 方法多次调用问题 )相关推荐

  1. 【错误记录】Android 编译时技术版本警告 ( 注解处理器与主应用支持的 Java 版本不匹配 )

    文章目录 一.报错信息 二.问题分析 三.解决方案 一.报错信息 在使用 Android 编译时技术 , 涉及 编译时注解 , 注解处理器 ; 开发注解处理器后 , 编译报如下警告 ; 该警告不会影响 ...

  2. 【错误记录】编译 Linux 内核报错 ( fatal error: openssl/opensslv.h: No such file or directory )

    文章目录 一.报错信息 二.解决方案 一.报错信息 编译 Linux 内核 , 执行 sudo make 命令 , 开始正式编译 Linux 内核 , 报如下错误 : root@ubuntu:~/ke ...

  3. 【错误记录】编译 Linux 内核报错 ( /bin/sh: 1: bison: not found )

    文章目录 一.报错信息 二.解决方案 一.报错信息 编译 Linux 内核 , 执行 make menuconfig 配置菜单命令 , 报如下错误 : root@ubuntu:~/kernel/lin ...

  4. 【错误记录】编译 Linux 内核报错 ( /bin/sh: 1: flex: not found )

    文章目录 一.报错信息 二.解决方案 一.报错信息 编译 Linux 内核 , 执行 make menuconfig 配置菜单命令 , 报如下错误 : root@ubuntu:~/kernel/lin ...

  5. 【错误记录】编译安卓项目报错 ( AndroidMavenPlugin 错误 )

    文章目录 一.报错信息 二.解决方案 一.报错信息 编译了一个 2016 年的项目 , 报错如下 : Build file 'D:\002_Project\002_Android_Learn\ffmp ...

  6. 解决vs2013编译时scanf报错的方法

    前言 在使用VS2013时可能会遇到scanf函数报错的问题,这里提供一种解决方法 步骤 1.找到VS2013的安装路径,找到此界面,打开VC文件夹 2.打开下图中的文件夹 3.下载一个Notepad ...

  7. 【错误记录】Manifest 清单文件报错 ( ..required to specify an explicit value for `android:exported` when the .. )

    文章目录 一.报错信息 二.解决方案 一.报错信息 修改 AndroidManifest.xml 清单文件时 , 发现合并清单文件时报错 , 该报错不影响程序运行 ; 报错信息 : Merging E ...

  8. 【错误记录】执行 Python 程序报错 ( NameError: name ‘reload‘ is not defined )

    文章目录 一.报错信息 二.解决方案 一.报错信息 在 Windows 的 cmd 命令行运行 python 脚本时 , 报如下错误 : 执行 python ApkTool.py -analyse - ...

  9. 【错误记录】Google Play 上架报错 ( 此版本不符合 Google Play 关于提供 64 位版本应用的要求 )

    文章目录 一.报错信息 二.解决方案 一.报错信息 在 Google Play 中 , 管理并创建内部测试版本 , 上传完毕后 , 检查版本时 , 出现如下错误 ; 此版本不符合 Google Pla ...

最新文章

  1. php账号密码备忘,WordPress使用备忘
  2. Android SingleTask启动模式与Home键的问题
  3. Android Kotlin 协程async
  4. FPGA(8)--频率计检测控制系统
  5. 【缓存】缓存,这么用才真正达到缓存的效果
  6. [Ext JS6]包-Package
  7. duilib入门简明教程 -- 前言(1) (转)
  8. java mojo是什么_java – 为什么Maven不能找到我的定制Mojo?
  9. x86代表计算机的,X86是32位还是64位 X86和X64含义介绍
  10. 2655 切木头(二分)
  11. 人生这么短,哪有空嫌晚
  12. openwrt之修改Luci界面
  13. 机器学习做二元分类问题(二)
  14. 数据可视化项目(一)
  15. 为陶崇园争取正义懒人包1.0
  16. 模型学习01——评价类模型(1)
  17. 前端常见图片格式整理
  18. 云计算机是什么原理,云电脑的运行原理是什么?
  19. JADE学习笔记2 :Agent的创建和运行
  20. NFT 地板价计算方法

热门文章

  1. 【Unity技巧】制作一个简单的NPC
  2. LVS (DR, NAT)模式应用
  3. COJ 2192: Wells弹键盘 (dp)
  4. 第44节:Java当中的JVM
  5. EOS开发基础之五:使用cleos命令行客户端操作EOS——智能合约之Exchange
  6. react-native 原生組件封裝與原生模塊和js的交互
  7. [LeetCode] 303. Range Sum Query - Immutable
  8. Android点赞音效播放
  9. 【EF Code First】 一对一、一对多的多重关系配置
  10. sqlserver Conversion failed when converting the nvarchar to data type int