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

如何使用OpenRewrite将嵌套注解替换为其属性值?

实现思路与建议

要解决这个嵌套注解替换的问题,核心是绕过visitAnnotation()只能返回注解实例的限制,直接操作注解的属性值结构。以下是两种可行方案:

方案1:源码级修改(用JavaParser)

如果是在源码迁移阶段处理,JavaParser是最直观的选择:

  • 遍历源码找到@Foo注解节点
  • 定位其values属性对应的数组初始化表达式
  • 遍历数组内的每个@Bar注解,提取value(兼容示例中的大写Value)属性的字符串值
  • 将数组内的@Bar注解节点替换为对应的字符串字面量节点
  • 输出修改后的源码

伪代码示例:

// 定位@Foo注解
AnnotationExpr fooAnnotation = ...;
// 获取values属性的数组节点
ArrayInitializerExpr valuesArray = (ArrayInitializerExpr) fooAnnotation.findAttribute("values").get();

List<Expression> newElements = new ArrayList<>();
for (Expression elem : valuesArray.getElements()) {
    if (elem instanceof AnnotationExpr barAnnotation) {
        // 兼容value/Value两种属性名
        Optional<Expression> valueExpr = barAnnotation.findAttribute("value")
                .or(() -> barAnnotation.findAttribute("Value"));
        valueExpr.ifPresent(newElements::add);
    }
}
// 替换数组元素
valuesArray.setElements(newElements);

方案2:字节码级修改(用ASM)

如果需要处理编译后的class文件,使用ASM的AnnotationVisitor拦截处理:

  • 重写visitArray(String name)方法,当遇到values数组时,自定义一个子AnnotationVisitor
  • 当访问到@Bar注解时,不返回注解实例,而是提取其value属性值,直接调用数组的visit方法写入字符串
  • 注意ASM的访问顺序:先触发visitArray,再逐个处理数组元素,遇到注解时触发visitAnnotation

伪代码示例:

@Override
public AnnotationVisitor visitArray(String name) {
    if ("values".equals(name)) {
        AnnotationVisitor arrayVisitor = super.visitArray(name);
        return new AnnotationVisitor(Opcodes.ASM9, arrayVisitor) {
            @Override
            public AnnotationVisitor visitAnnotation(String desc, String value) {
                // 判断是否是目标@Bar注解(替换成实际的全类名描述符)
                if ("Lyour/package/Bar;".equals(desc)) {
                    return new AnnotationVisitor(Opcodes.ASM9) {
                        @Override
                        public void visit(String attrName, Object attrValue) {
                            if ("value".equals(attrName) || "Value".equals(attrName)) {
                                // 将提取到的字符串值写入数组
                                arrayVisitor.visit(null, attrValue);
                            }
                        }
                    };
                }
                return super.visitAnnotation(desc, value);
            }
        };
    }
    return super.visitArray(name);
}

关键注意事项

  • 属性名兼容:必须处理value和Value两种大小写的属性名,避免遗漏
  • 类型匹配:确保@Foo的values属性本身就是String[]类型,否则替换后会出现类型不兼容的编译/运行错误
  • 批量处理:如果需要修改大量类,建议封装成批量处理工具,比如基于JavaParser的源码扫描器,或者ASM的字节码转换工具

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 13:25:15