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

Gunnar Morling gunnar at hibernate.org
Mon Jan 20 08:36:24 UTC 2020

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

    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

  public static record Bar (@Deprecated String bar) {
    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



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