[ 
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)

Reply via email to