标准Annotation Processor无法替代Lombok或MapStruct:Lombok依赖javac内部API修改AST,MapStruct需泛型元数据与框架集成,而Processor仅能读取Element、生成新文件,无法修改原类语义或获取运行时类型信息。

Annotation Processor 不能直接替代 MapStruct 或 Lombok 的核心能力——MapStruct 依赖注解驱动的接口实现生成,Lombok 则深度耦合 javac 的 AST 修改机制;你用标准 javax.annotation.processing.Processor 无法安全地重写 @Data 或 @Mapper 的全部行为,尤其涉及字段访问控制、getter/setter 语义、泛型桥接、甚至字节码级增强时,会掉进 javac 插件边界和编译器兼容性坑里。
为什么自研 Processor 很难复刻 Lombok 的 @Data
Lombok 不是普通注解处理器:它通过 javac 的内部 API(如 com.sun.tools.javac.tree.JCTree)直接修改语法树,并在解析/分析阶段注入节点。标准 Processor 只能在 ROUND 中读取已解析的 Element,无法添加新方法、修改修饰符、或生成带泛型擦除逻辑的桥接方法。
- 你无法在
process()里让 javac “认为”某个类已有public String getName()方法——它只生成额外 .java 文件或 .class,不参与当前类的符号解析 -
@SneakyThrows这类异常处理重写,需操作 try/catch AST 节点,标准 Processor 没有入口 - Lombok 的
@Builder支持 builder 类继承、泛型推导、默认值表达式,这些依赖对TreePath和Types的实时求值,标准 API 不暴露
MapStruct 的 @Mapper 为什么也不适合用普通 Processor 模仿
MapStruct 的关键在于:它生成的是完整、可调试、类型安全的 impl 类,且能精确响应 @Mapping、@AfterMapping、@Context 等组合语义;这些需要理解目标类的完整继承链、泛型实参映射、甚至 Spring Bean 名称绑定。
- 标准 Processor 拿不到
TypeMirror的运行时泛型信息(如List<UserDto>中的UserDto),只能靠字符串解析,极易出错 - 它无法感知 Spring 的
@Qualifier或 CDI 的@Named,而 MapStruct 的componentModel = "spring"依赖这些元数据生成@Autowired字段 - MapStruct 会为
@MapperConfig做跨@Mapper的配置继承,这要求 Processor 维护全局处理上下文,但 javac 不保证所有@Mapper在同一 round 被发现
如果你真要动手,唯一可行的轻量路径是“生成辅助类”而非“替换原类”
放弃模拟 @Data 或 @Mapper,转而用 Processor 生成独立工具类,比如为 POJO 自动生成 JSON Schema、DTO-to-Entity 转换器骨架、或字段校验注解的反射检查器——这类代码不侵入原类语义,只读不写,风险可控。
- 用
RoundEnvironment.getElementsAnnotatedWith(MyGenerateSchema.class)扫描目标类 - 用
Filer.createSourceFile()写出MyPojoSchema.java,内容基于Element.getEnclosedElements()提取字段名+类型 - 避免生成方法体逻辑(如深拷贝),只生成结构化数据或空方法存根;复杂逻辑留到运行时用
BeanUtils.copyProperties()或手动调用 - 务必在
@SupportedOptions中声明"debug=true",并用Messager.printMessage()输出生成路径,否则 debug 时根本不知道文件写哪了
真正想控制编译期代码生成,要么用 Lombok(接受它的黑盒性),要么用 MapStruct(接受它的约定优先),要么上 Gradle 编译插件或 Java Agent——标准 Annotation Processor 是个“只读快照”,不是“可编程编译器”。别在 process() 里硬刚 AST,那不是它的设计位置。

















