GroovyAST 在编译时添加通用字段

GroovyAST add generic field at compile time

我想在编译时向某些 classes 添加一个通用字段。对于这个objective,我按照官方documentation实现了自己的AST注解和转换classes,并用AST注解标注了想要的classes。

但是我在编译时遇到这个错误:

org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed: /home/.../groovy/Sample.groovy: -1: A transform used a generics containing ClassNode java.util.HashSet for the field x directly. You are not supposed to do this. Please create a new ClassNode referring to the old ClassNode and use the new ClassNode instead of the old one. Otherwise the compiler will create wrong descriptors and a potential NullPointerException in TypeResolver in the OpenJDK. If this is not your own doing, please report this bug to the writer of the transform. @ line -1, column -1.

我弄错了吗?

示例代码

例如,假设我想添加一个名为 xHashSet<Long> 字段到由 MyAST 注释注释的每个 class。

我的 AST 注释 class:

@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
@GroovyASTTransformationClass(classes = [MyASTTransformation.class])
public @interface MyAST {
}

我的 AST 转换 class:

@CompileStatic
@GroovyASTTransformation(phase = CompilePhase.SEMANTIC_ANALYSIS)
public class MyASTTransformation implements ASTTransformation {

@Override
public void visit(ASTNode[] nodes, SourceUnit sourceUnit) {
     ClassNode clazz = (ClassNode) nodes[1];
     ClassNode longHashSetClass = new ClassNode(HashSet.class);
     longHashSetClass.setGenericsTypes([new GenericsType(new ClassNode(Long.class))] as GenericsType[]);
     FieldNode field = new FieldNode("x", FieldNode.ACC_PRIVATE, longHashSetClass, clazz, new ConstantExpression(null));
     clazz.addField(field);
 }
}

样本注释 class:

@MyAST
public class Sample {
}

备注

当我删除行 longHashSetClass.setGenericsTypes([new GenericsType(new ClassNode(Long.class))] as GenericsType[]); 时,一切正常,但 x 的类型在运行时是 HashSet 而不是 HashSet<Long>

您应该使用 ClassHelperGenericUtils 来创建一个 ClassNode :

import static org.codehaus.groovy.ast.ClassHelper.make
import static org.codehaus.groovy.ast.tools.GenericsUtils.makeClassSafeWithGenerics

...

ClassNode hashSet = makeClassSafeWithGenerics(HashSet, make(Long))