如何在OpenRewrite中为注解添加数组参数?
给@Import注解动态添加数组参数的实现方案
我正在编写自定义OpenRewrite Recipe,目标是给@Import注解的数组参数动态添加多个配置类,期望最终生成的代码效果如下:
@Import({ TestConfiguration.class, XyzConfiguration.class, AbcConfiguration.class, ... })
目前我已经能给类添加新注解,但不知道如何为@Import注解添加数组形式的参数,现有代码如下:
private static class ImportVisitor extends JavaIsoVisitor<ExecutionContext> { private static final String IMPORT_ANNOTATION = "Import"; private static final String SPRING_BOOT_APPLICATION_ANNOTATION = "SpringBootApplication"; @Override public @NonNull ClassDeclaration visitClassDeclaration( @NonNull ClassDeclaration classDecl, @NonNull ExecutionContext executionContext ) { boolean isApplication = classDecl.getSimpleName().contains("Application"); boolean isImport = classDecl.getAllAnnotations() .stream() .anyMatch(annotation -> IMPORT_ANNOTATION.equals(annotation.getSimpleName())); if (isApplication && !isImport) { List<Annotation> annotations = classDecl.getAllAnnotations(); Annotation importAnnotation = createAnnotation(IMPORT_ANNOTATION); annotations.add(importAnnotation); annotations.add(createAnnotation(SPRING_BOOT_APPLICATION_ANNOTATION).withPrefix(Space.format("\n"))); classDecl = classDecl.withPrefix(Space.format("\n")) .withLeadingAnnotations(annotations); maybeAddImport("org.springframework.boot.autoconfigure.SpringBootApplication", false); maybeAddImport("org.springframework.context.annotation.Import", false); } return classDecl; } public static J.Annotation createAnnotation(String annotation) { return new J.Annotation(UUID.randomUUID(), Space.EMPTY, Markers.EMPTY, TypeTree.build(annotation), null); } }
解决方案
要实现给@Import添加数组参数,需要改造注解创建逻辑,构建包含数组初始化器的注解参数:
- 改造createAnnotation方法,支持传入注解参数
修改createAnnotation方法,允许接收J.Expression类型的参数,用来构建注解的参数部分:
public static J.Annotation createAnnotation(String annotationName, J.Expression argument) { J.Annotation.Arguments args = null; if (argument != null) { args = new J.Annotation.Arguments( UUID.randomUUID(), Space.EMPTY, List.of(new J.Annotation.Argument( UUID.randomUUID(), Space.EMPTY, null, // @Import的参数默认是value,可省略参数名 argument, Space.EMPTY )) ); } return new J.Annotation( UUID.randomUUID(), Space.EMPTY, Markers.EMPTY, TypeTree.build(annotationName), args ); }
- 构建@Import需要的数组参数并更新业务逻辑
在visitClassDeclaration方法中,定义要添加的配置类列表,用J.ArrayInitializer构建数组元素(每个元素对应配置类的类型字面量),再创建带参数的@Import注解:
if (isApplication && !isImport) { List<Annotation> annotations = classDecl.getAllAnnotations(); // 定义需要添加的配置类全限定名 List<String> configClasses = List.of( "com.example.TestConfiguration", "com.example.XyzConfiguration", "com.example.AbcConfiguration" ); // 构建数组元素:生成XXConfiguration.class格式的类型字面量 List<J.Expression> arrayElements = configClasses.stream() .map(className -> { maybeAddImport(className, false); // 自动添加配置类的import语句 return new J.TypeApply( UUID.randomUUID(), Space.EMPTY, TypeTree.build(className), new J.TypeArgumentList(UUID.randomUUID(), Space.EMPTY, List.of()) ).withSuffix(Space.EMPTY); }) .collect(Collectors.toList()); // 构建带格式的数组初始化器 J.ArrayInitializer arrayInitializer = new J.ArrayInitializer( UUID.randomUUID(), Space.format(" "), new J.LCurly(UUID.randomUUID(), Space.format("\n ")), arrayElements.stream() .map(elem -> elem.withSuffix(Space.format(",\n "))) .collect(Collectors.toList()), new J.RCurly(UUID.randomUUID(), Space.format("\n")) ); // 创建带数组参数的@Import注解 Annotation importAnnotation = createAnnotation(IMPORT_ANNOTATION, arrayInitializer); annotations.add(importAnnotation); annotations.add(createAnnotation(SPRING_BOOT_APPLICATION_ANNOTATION).withPrefix(Space.format("\n"))); classDecl = classDecl.withPrefix(Space.format("\n")) .withLeadingAnnotations(annotations); maybeAddImport("org.springframework.boot.autoconfigure.SpringBootApplication", false); maybeAddImport("org.springframework.context.annotation.Import", false); }
关键说明
J.TypeApply用于生成XXConfiguration.class这种类字面量,对应Java中的类字面量语法。J.ArrayInitializer用来构建数组初始化块,通过设置空格和换行符保证生成的代码格式整洁规范。- 注解参数通过
J.Annotation.Arguments和J.Annotation.Argument构建,@Import的默认参数为value,可以省略参数名。
内容的提问来源于stack exchange,提问作者dk1337
相关产品推荐
相关产品推荐

