You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Java Poet生成方法级注解代码:处理器未执行无生成结果求助

问题排查:JavaPoet注解处理器未执行、代码未生成

用户场景与现状

想要实现方法级@Latency注解,通过JavaPoet在编译期生成耗时统计代码(替代AspectJ,方便调试查看具体逻辑),但当前注解处理器LatencyProcessor从未被调用,也看不到任何生成的代码。

注解定义

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Latency {
}

注解处理器代码

package org.example;

import com.google.auto.service.AutoService;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import java.io.IOException;
import java.util.Set;

@AutoService(Processor.class)
public class LatencyProcessor extends AbstractProcessor {

    @Override
    public Set<String> getSupportedAnnotationTypes() {
        return Set.of(Latency.class.getName());
    }

    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        System.out.println("LatencyProcessor is running...");
        for (Element element : roundEnv.getElementsAnnotatedWith(Latency.class)) {
            if (element.getKind().equals(ElementKind.METHOD)) {
                generateLatencyCode((ExecutableElement) element);
            }
        }
        return true;
    }

    private void generateLatencyCode(ExecutableElement methodElement) {
        String methodName = methodElement.getSimpleName().toString();

        CodeBlock codeBlock = CodeBlock.builder()
            .beginControlFlow("try")
            .addStatement("long startTime = System.currentTimeMillis()")
            .addStatement("$N.$N()", "this", methodName)
            .addStatement("long endTime = System.currentTimeMillis()")
            .addStatement("System.out.println(\"Method $N execution time: \" + (endTime - startTime) + \" milliseconds\")", methodName)
            .nextControlFlow("catch (Exception e)")
            .addStatement("e.printStackTrace()")
            .endControlFlow()
            .build();

        MethodSpec latencyMethod = MethodSpec.methodBuilder(methodName)
            .addModifiers(Modifier.PUBLIC)
            .addAnnotation(Override.class)
            .returns(TypeName.VOID)
            .addCode(codeBlock)
            .build();

        TypeSpec latencyClass = TypeSpec.classBuilder("Latency_" + methodName)
            .addModifiers(Modifier.PUBLIC)
            .addSuperinterface(ClassName.get(methodElement.getEnclosingElement().asType()))
            .addMethod(latencyMethod)
            .build();

        JavaFile javaFile = JavaFile.builder("generated", latencyClass)
            .build();

        try {
            javaFile.writeTo(processingEnv.getFiler());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

build.gradle配置

dependencies {
    implementation 'com.squareup:javapoet:1.13.0'
    implementation 'com.google.auto.service:auto-service:1.1.1'

    annotationProcessor 'com.google.auto.service:auto-service:1.1.1'

}

configurations {
    annotationProcessor
}

问题原因与修复步骤

1. 注解处理器依赖配置错误

编译器无法发现你的LatencyProcessor,因为当前gradle配置未将处理器注册到编译流程中:

  • 如果处理器和业务代码在同一模块,修改依赖配置:
    dependencies {
        implementation 'com.squareup:javapoet:1.13.0'
        // auto-service用于生成处理器的META-INF注册文件,必须用annotationProcessor依赖
        annotationProcessor 'com.google.auto.service:auto-service:1.1.1'
        // 确保当前模块的处理器类被纳入注解处理器路径
        annotationProcessor files(sourceSets.main.output.classesDirs)
    }
    
  • 如果处理器是单独模块(推荐解耦),在业务模块的build.gradle中添加:
    dependencies {
        implementation project(':processor-module') // 让业务模块能引用@Latency注解
        annotationProcessor project(':processor-module') // 告诉编译器启用该模块的注解处理器
    }
    

2. 注解RetentionPolicy不规范

当前注解用@Retention(RetentionPolicy.RUNTIME),虽然编译期也能识别,但注解处理器仅在编译期工作,更合理的配置是:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE) // 仅保留到编译期,无需进入运行时
public @interface Latency {
}

3. 处理器代码的逻辑问题

  • 递归调用风险:生成的方法和原方法同名且标注@Override,代码中this.process()会触发递归,应改为持有原对象引用并调用原方法,比如生成包装类:
    // 修改generateLatencyCode中的MethodSpec
    MethodSpec latencyMethod = MethodSpec.methodBuilder(methodName)
        .addModifiers(Modifier.PUBLIC)
        .addAnnotation(Override.class)
        .returns(TypeName.get(methodElement.getReturnType()))
        // 添加原对象作为参数或成员变量
        .addParameter(ClassName.get(methodElement.getEnclosingElement().asType()), "delegate")
        .addCode(CodeBlock.builder()
            .beginControlFlow("try")
            .addStatement("long startTime = System.currentTimeMillis()")
            .addStatement("delegate.$N()", methodName) // 调用原对象方法,避免递归
            .addStatement("long endTime = System.currentTimeMillis()")
            .addStatement("System.out.println(\"Method $N execution time: \" + (endTime - startTime) + \" milliseconds\")", methodName)
            .nextControlFlow("catch (Exception e)")
            .addStatement("e.printStackTrace()")
            .endControlFlow()
            .build())
        .build();
    
  • 类/接口适配问题:如果原方法在普通类而非接口中,addSuperinterface会报错(类不能实现类),需改为继承原类(注意原类不能是final)。

4. 日志输出优化

System.out.println在注解处理器中可能无法正常打印到控制台,改用官方API输出日志:

processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "LatencyProcessor is running...");

5. 生成代码位置检查

编译期生成的代码默认存放在build/generated/sources/annotationProcessor/main/java/目录下,而非项目源码目录,需到该路径下查看结果。


内容的提问来源于stack exchange,提问作者user1692342

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 13:35:57