[
https://issues.apache.org/jira/browse/GROOVY-12413?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Paul King closed GROOVY-12413.
------------------------------
> TYPE_USE annotations on primitive record components and tuple-constructor
> parameters are duplicated or misapplied
> -----------------------------------------------------------------------------------------------------------------
>
> Key: GROOVY-12413
> URL: https://issues.apache.org/jira/browse/GROOVY-12413
> Project: Groovy
> Issue Type: Bug
> Affects Versions: 5.1.2, 6.0.0-RC-2
> Reporter: Paul King
> Assignee: Paul King
> Priority: Major
> Fix For: 5.1.3, 7.0.0-alpha-1, 6.0.0
>
>
> When a record component or a {{@TupleConstructor}} property has a primitive
> type annotated with a {{TYPE_USE}} annotation, the compiler writes the type
> annotation to the wrong places or writes it several times.
> h3. Records
> {code:groovy}
> import java.lang.annotation.*
> @Retention(RetentionPolicy.RUNTIME)
> @Target(ElementType.TYPE_USE)
> @interface NonNeg {}
> record Point(@NonNeg int x, @NonNeg String s) {}
> def rc = Point.recordComponents[0]
> println rc.annotatedType.annotations
> {code}
> Actual:
> {noformat}
> java.lang.annotation.AnnotationFormatError: Duplicate annotation for class:
> interface NonNeg: @NonNeg()
> {noformat}
> The {{int}} component's type annotation is written three times each to the
> Record attribute, the backing field, the accessor return type and the
> canonical constructor parameter. Any reflective read of it fails with the
> error above, including:
> * {{RecordComponent.getAnnotatedType()}}
> * {{Field.getAnnotatedType()}}
> * {{Method.getAnnotatedReturnType()}}
> * {{Constructor.getAnnotatedParameterTypes()}}
> For the constructor this fails for every parameter, including the {{String}}
> one. Reference-type components ({{@NonNeg String s}}) are otherwise written
> correctly.
> Expected: a single {{@NonNeg}} on each of the four places, as javac produces
> for the equivalent Java record.
> h3. @TupleConstructor
> {code:groovy}
> @groovy.transform.TupleConstructor
> class C { @NonNeg int a; @NonNeg String s }
> println C.getDeclaredConstructor(int,
> String).annotatedParameterTypes*.annotations
> {code}
> Actual: {{[[@NonNeg()], []]}}. The {{int}} parameter picks up the field's
> type annotation, but the {{String}} parameter does not.
> Expected: {{[[], []]}}. Tuple constructor parameters do not copy the
> property's annotations, so primitive and reference properties should behave
> the same way.
> h3. Cause
> {{ClassNode.getPlainNodeReference()}} returns the node itself for primitive
> types instead of a new reference. {{RecordTypeASTTransformation}} (record
> component type) and {{TupleConstructorASTTransformation.createParam}}
> (constructor parameter type) both call it. So for a primitive property, the
> component, field, accessor return type and constructor parameter all share
> one {{ClassNode}}. {{ExtendedVerifier}} then adds the {{TYPE_USE}}
> annotations to that shared node once for each place it appears.
> h3. Fix
> Use {{getPlainNodeReference(false)}} at both call sites so primitive types
> also get their own node, as {{ExtendedVerifier.visitConstructor}} already
> does (GROOVY-10937).
> Reproduced on 5.1.2 and on master.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)