[
https://issues.apache.org/jira/browse/GROOVY-10758?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17606650#comment-17606650
]
Eric Milles edited comment on GROOVY-10758 at 9/19/22 3:49 PM:
---------------------------------------------------------------
Assuming "fqcn" is "FooResource", your goal is roughly "ClassNode(name:
"FooResource", modifiers: 0x11, superClass: Resource<FooAttributes> ->
Resource<A>)". To achieve this, you can do something like this (dropping
{{tap}} for simplicity):
{code:groovy}
ClassNode resource = ClassHelper.make(Resource)
ClassNode fooResource = ClassHelper.makeWithoutCaching(fqcn)
ClassNode fooAttributes = ClassHelper.makeWithoutCaching(...)
fooResource.modifiers |= PUBLIC | FINAL
fooResource.superClass = GenericsUtils.makeClassSafeWithGenerics(resource,
fooAttributes)
{code}
However, if you already have "FooAttributes" as an instance of
{{GenericsType}}, which you appear to have available through "attr", you can
write:
{code:groovy}
ClassNode resource = ClassHelper.make(Resource)
ClassNode fooResource = ClassHelper.makeWithoutCaching(fqcn)
fooResource.modifiers |= PUBLIC | FINAL
fooResource.superClass = GenericsUtils.makeClassSafe0(resource, attr)
{code}
If you look at the implementation of {{makeClassSafe0}}, it calls
{{ClassNode#getPlainNodeReference}} which produces a raw type reference for a
parameterized type. Then you can freely set the generics (aka type arguments)
of that. Once you get into generics, the APIs get less user-friendly and
working AST examples can make for a good point of reference.
was (Author: emilles):
Assuming "fqcn" is "FooResource", your goal is roughly "ClassNode(name:
"FooResource", modifiers: 0x11, superClass: Resource<FooAttributes> ->
Resource<A>)". To achieve this, you can do something like this (dropping
{{tap}} for simplicity):
{code:groovy}
ClassNode resource = ClassHelper.make(Resource)
ClassNode fooResource = ClassHelper.makeWithoutCaching(fqcn)
ClassNode fooAttributes = ClassHelper.makeWithoutCaching(...)
fooResource.modifiers |= PUBLIC | FINAL
fooResource.superClass = GenericsUtils.makeClassSafeWithGenerics(fooResource,
fooAttributes)
{code}
However, if you already have "FooAttributes" as an instance of
{{GenericsType}}, which you appear to have available through "attr", you can
write:
{code:groovy}
ClassNode resource = ClassHelper.make(Resource)
ClassNode fooResource = ClassHelper.makeWithoutCaching(fqcn)
fooResource.modifiers |= PUBLIC | FINAL
fooResource.superClass = GenericsUtils.makeClassSafe0(fooResource, attr)
{code}
If you look at the implementation of {{makeClassSafe0}}, it calls
{{ClassNode#getPlainNodeReference}} which produces a raw type reference for a
parameterized type. Then you can freely set the generics (aka type arguments)
of that. Once you get into generics, the APIs get less user-friendly and
working AST examples can make for a good point of reference.
> Improve error message when using generic ClassNodes in ASTT
> -----------------------------------------------------------
>
> Key: GROOVY-10758
> URL: https://issues.apache.org/jira/browse/GROOVY-10758
> Project: Groovy
> Issue Type: Improvement
> Components: Compiler
> Affects Versions: 4.0.5
> Reporter: Christopher Smith
> Priority: Minor
>
> When mistakenly using a shared instance of a {{ClassNode}} that has generics
> applied, the compiler (helpfully!) produces this error:
> {code}
> 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.
> {code}
> However, there is no explanation of *how* to create the "new ClassNode", and
> [I couldn't find anything in the API that made the error go
> away|https://stackoverflow.com/questions/73749765/how-do-i-subclass-a-generic-base-class-in-a-groovy-ast-transformation].
> It would be helpful to ASTT neophytes if the error message specified the
> method call(s) suitable for this operation.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)