[Records] Component annotations not propagated when explicit canonical constructor is given

Vicente Romero vicente.romero at oracle.com
Tue Jan 21 17:53:05 UTC 2020


thanks for testing it,

Vicente

On 1/21/20 11:44 AM, Gunnar Morling wrote:
> Vincente,
>
> Just tried with build 15-ea+6-123 and can confirm the issue is fixed
> there. Thanks!
>
> --Gunnar
>
> Am Di., 21. Jan. 2020 um 00:08 Uhr schrieb Vicente Romero
> <vicente.romero at oracle.com>:
>> Hi Gunnar
>>
>> On 1/20/20 12:18 PM, Gunnar Morling wrote:
>>> Ah, yes, indeed! I'll track this issue then, thanks! Perhaps it would
>>> even make sense to have it fixed for JDK 14?
>> the issue has already being fixed in 15. Could you please try with 15 to
>> see double check that you can't reproduce the issue with jdk15?
>>
>>> --Gunnar
>> Vicente
>>
>>> Am Mo., 20. Jan. 2020 um 17:35 Uhr schrieb Jorn Vernee <jorn.vernee at oracle.com>:
>>>> Hi,
>>>>
>>>> I remember this issue coming up before. Looks like there was a fix
>>>> targeted at JDK 15: https://bugs.openjdk.java.net/browse/JDK-8236597
>>>>
>>>> Jorn
>>>>
>>>> On 20/01/2020 09:36, Gunnar Morling wrote:
>>>>> Thanks for your reply!
>>>>>
>>>>>> If a canonical ctor / accessor is explicitly specified, the annos on the declaration are used instead.
>>>>> That's where things are still unclear for me, it seems contradictory
>>>>> to "sounds like incorrect behavior to me" above. To make things more
>>>>> concrete, here's an example:
>>>>>
>>>>>      public class RecordAnnos {
>>>>>        public static void main(String... args) {
>>>>>          System.out.println(Arrays.toString(Foo.class.getConstructors()[0].getParameters()[0].getAnnotations()));
>>>>>          System.out.println(Arrays.toString(Bar.class.getConstructors()[0].getParameters()[0].getAnnotations()));
>>>>>        }
>>>>>
>>>>>        public static record Foo (@Deprecated String foo) {}
>>>>>
>>>>>        public static record Bar (@Deprecated String bar) {
>>>>>          public Bar {}
>>>>>        }
>>>>>      }
>>>>>
>>>>> Running this prints:
>>>>>
>>>>>      java --enable-preview --source 14 RecordAnnos.java
>>>>>      [@java.lang.Deprecated(forRemoval=false, since="")]
>>>>>      []
>>>>>
>>>>> Whereas I hoped it'd print this:
>>>>>
>>>>>      [@java.lang.Deprecated(forRemoval=false, since="")]
>>>>>      [@java.lang.Deprecated(forRemoval=false, since="")]
>>>>>
>>>>> In case an explicit canonical constructor is declared without the
>>>>> formal parameter list, there's no way to specify any annotations on
>>>>> the parameters. So shouldn't those from the components be applied?
>>>>> With the current behaviour, if I want to declare any annotation for
>>>>> the constructor itself, I need to repeat all annotations from the
>>>>> components on the annotations of a fully manually implemented
>>>>> constructor:
>>>>>
>>>>>      public static record Bar (@Deprecated String bar) {
>>>>>        @Deprecated
>>>>>        public Bar(@Deprecated String bar) {
>>>>>          this.bar = bar;
>>>>>        }
>>>>>     }
>>>>>
>>>>> Note that @Deprecated is just used here to make the example
>>>>> self-contained; my actual use case is about Bean Validation constraint
>>>>> annotations.
>>>>>
>>>>> Thanks,
>>>>>
>>>>> --Gunnar
>>>>>
>>>>> Am Mo., 20. Jan. 2020 um 01:32 Uhr schrieb Brian Goetz <brian.goetz at oracle.com>:
>>>>>> This sounds like incorrect behavior to me.  The way it should work is:
>>>>>>
>>>>>>     - A declaration annotation is applicable to a record component if it has no @Target meta-anno, or its target includes one or more of PARAMETER, FIELD, METHOD, RECORD_COMPONENT.
>>>>>>     - For _each_ of the applicable types present, the anno is pushed down to the corresponding _implicit_ { ctor parameter, field, accessor method, record component }.
>>>>>>     - If multiple applicable types are present, it is pushed down to all of them.
>>>>>>     - If a canonical ctor / accessor is explicitly specified, the annos on the declaration are used instead.
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>> On 1/19/2020 4:14 PM, Gunnar Morling wrote:
>>>>>>
>>>>>> Hi,
>>>>>>
>>>>>> I'm observing the following behaviour around annotations on record
>>>>>> components, using JDK 14 b32. I'm putting an annotation to a record
>>>>>> component:
>>>>>>
>>>>>>        public record Person(@NotNull String name) {}
>>>>>>
>>>>>> In this case the @NotNull annotation is propagated to the
>>>>>> corresponding parameter of the generated constructor, from where I can
>>>>>> obtain it using reflection. This is not the case though when I
>>>>>> explicitly declare the canonical constructor:
>>>>>>
>>>>>>        public record Person(@NotNull String name) {
>>>>>>            public Person {
>>>>>>                // ...
>>>>>>            }
>>>>>>        }
>>>>>>
>>>>>> In this case the annotation isn't propagated, and it won't be
>>>>>> retrievable from that constructor's parameter via reflection.
>>>>>>
>>>>>> Is this behaviour intended or is it a bug actually? I lean towards the
>>>>>> latter, as I don't explicitly define the parameter in the constructor,
>>>>>> so I'd expect the annotations given on the component to still be
>>>>>> propagated.
>>>>>>
>>>>>> If it *is* intended, it'd make my use case a bit more complex, as I'd
>>>>>> want to be able to put other annotations to the canonical constructor
>>>>>> *itself*, while still getting all the component annotations propagated
>>>>>> to its parameters.
>>>>>>
>>>>>> Thanks a lot,
>>>>>>
>>>>>> --Gunnar
>>>>>>
>>>>>>



More information about the amber-dev mailing list