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

Quarkus AnnotationsTransformerBuildItem未按预期工作问题求助

问题分析

你遇到的核心问题是:AnnotationsTransformerBuildItem 仅修改了CDI容器处理的元数据,但Quarkus的JAX-RS路由构建基于Jandex索引或原始类字节码,并未同步读取CDI修改后的注解。控制台打印说明Transformer逻辑触发成功,但JAX-RS的端点注册流程早于或独立于CDI的注解转换,导致修改未生效。

解决方案

方案1:调整注解转换执行时机,确保JAX-RS感知到修改

Quarkus构建步骤有严格执行顺序,需让AnnotationsTransformer在JAX-RS扫描端点前运行,同时合并注解修改操作(避免多次transform()调用导致状态覆盖)。

修改后的代码:

package com.tawfeek.greeting.extension.deployment;

import io.quarkus.arc.deployment.AnnotationsTransformerBuildItem;
import io.quarkus.arc.processor.AnnotationsTransformer;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.annotations.Order;
import io.quarkus.deployment.builditem.FeatureBuildItem;
import org.jboss.jandex.AnnotationTarget;
import org.jboss.jandex.DotName;
import org.jboss.jandex.MethodInfo;

class GreetingExtensionProcessor {

    private static final String FEATURE = "greeting-extension";
    // 定义常量避免硬编码字符串错误
    private static final DotName GET = DotName.createSimple("jakarta.ws.rs.GET");
    private static final DotName POST = DotName.createSimple("jakarta.ws.rs.POST");

    @BuildStep
    FeatureBuildItem feature() {
        return new FeatureBuildItem(FEATURE);
    }

    // 设置执行顺序,确保在JAX-RS端点扫描前完成注解转换
    @BuildStep
    @Order(io.quarkus.deployment.annotations.Phase.BEFORE_ANALYSIS)
    AnnotationsTransformerBuildItem transformAnnotations() {
        return new AnnotationsTransformerBuildItem(new AnnotationsTransformer() {
            @Override
            public boolean appliesTo(AnnotationTarget.Kind kind) {
                return kind == AnnotationTarget.Kind.METHOD;
            }

            @Override
            public void transform(TransformationContext context) {
                MethodInfo methodInfo = context.getTarget().asMethod();
                if (methodInfo.hasAnnotation(GET)) {
                    // 合并remove和add操作到同一个transform链
                    context.transform()
                            .remove(annotationInstance -> annotationInstance.name().equals(GET))
                            .add(POST)
                            .done();
                    System.out.println("method " + methodInfo.name() + " is changed from GET to POST");
                }
            }
        });
    }
}

关键调整点:

  • 使用@Order(Phase.BEFORE_ANALYSIS)确保注解转换在JAX-RS端点元数据收集前执行
  • 将remove和add操作合并到同一个transform()链中,避免多次done()导致的状态覆盖
  • 用DotName常量替代硬编码字符串,减少拼写错误

方案2:直接修改类字节码(更可靠的方式)

如果方案1仍不生效,说明JAX-RS完全不依赖CDI的注解转换结果,此时需要直接修改类的字节码,让JAX-RS扫描时读取到修改后的注解。

实现代码:

package com.tawfeek.greeting.extension.deployment;

import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.builditem.FeatureBuildItem;
import io.quarkus.deployment.builditem.transformer.ClassTransformerBuildItem;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;

class GreetingExtensionProcessor {

    private static final String FEATURE = "greeting-extension";
    private static final String GET_DESC = "Ljakarta/ws/rs/GET;";
    private static final String POST_DESC = "Ljakarta/ws/rs/POST;";

    @BuildStep
    FeatureBuildItem feature() {
        return new FeatureBuildItem(FEATURE);
    }

    @BuildStep
    ClassTransformerBuildItem transformClass() {
        return ClassTransformerBuildItem.builder()
                .setClassVisitorTransformer((className, classVisitor) -> new ClassVisitor(classVisitor) {
                    @Override
                    public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
                        // 不修改类级注解,直接传递
                        return super.visitAnnotation(descriptor, visible);
                    }

                    @Override
                    public AnnotationVisitor visitMethodAnnotation(int access, String name, String descriptor, String signature, String[] exceptions) {
                        AnnotationVisitor av = super.visitMethodAnnotation(access, name, descriptor, signature, exceptions);
                        return new AnnotationVisitor(av) {
                            @Override
                            public void visit(String name, Object value) {
                                // 如果是@GET注解,替换为@POST
                                if (GET_DESC.equals(descriptor)) {
                                    // 先移除原@GET注解
                                    av.visitEnd();
                                    // 添加@POST注解
                                    return super.visitMethodAnnotation(access, name, POST_DESC, signature, exceptions);
                                }
                                super.visit(name, value);
                            }
                        };
                    }
                })
                // 仅匹配目标包下的类(可选,优化性能)
                .setTargetClassPredicate(className -> className.startsWith("your.target.package"))
                .build();
    }
}

说明:

  • 直接操作ASM字节码修改方法注解描述符,JAX-RS扫描类时会直接读取修改后的字节码
  • 通过setTargetClassPredicate限定转换范围,提升构建性能
验证方法

修改代码后重新构建启动应用:

  1. 确认控制台仍打印转换成功的日志
  2. 用Postman发送POST请求到原GET接口,确认返回正常;发送GET请求应返回405 Method Not Allowed

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 21:44:51