如何在Groovy AST转换中继承泛型基类Resource<A>?
问题:生成泛型父类的ClassNode时遇到编译器错误
我有一个Java抽象基类Resource<A>,包含A类型的attributes属性。现在要编写一个针对FooAttributes的AST转换,生成继承Resource<FooAttributes>的包装类FooResource,但处理ClassNode时遇到错误。
尝试的代码
make(rc.fqcn).tap { superClass = makeWithoutCaching(Resource).tap { genericsTypes = [attr] as GenericsType[] } }
编译器错误信息
transform used a generics containing ClassNode com.example.Resource<com.example.FooAttributes> for the super class com.example.FooResource 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.
(注:推测错误信息中“super class”应为“super class for”)
我查阅了ClassNode和ClassHelper的API,但未找到“创建引用旧节点的新节点”的方法。尝试调用new ClassNode(String, int, ClassNode)仍出现相同错误。请问应使用哪些API调用来为泛型类Resource<A>创建新的ClassNode?
解决方案
核心思路是创建独立的、带泛型参数的ClassNode引用,而非直接修改原Resource的ClassNode,避免污染复用的节点。可以通过以下两种方式实现:
方式一:通过TypeReference生成泛型类型再创建ClassNode
// 生成带泛型参数的Resource类型引用 def resourceType = new TypeReference(Resource) {}.getType() def genericResourceType = new GenericType(resourceType, attr) // 基于泛型类型创建父类ClassNode make(rc.fqcn).tap { superClass = ClassHelper.makeClassNode(genericResourceType) }
方式二:直接使用ClassHelper的makeWithGenerics工具方法
// 直接创建带指定泛型参数的Resource ClassNode def superClassNode = ClassHelper.makeWithGenerics(Resource, [attr] as GenericsType[]) // 为生成的FooResource设置父类 make(rc.fqcn).tap { superClass = superClassNode }
这两种方法都会生成一个全新的ClassNode,它仅引用原Resource类的元信息,不会修改原节点,符合编译器对AST转换的要求,能解决错误提示中的问题。
内容的提问来源于stack exchange,提问作者chrylis -cautiouslyoptimistic-
相关产品推荐
相关产品推荐

