JDK-8277679 : annotations in the super class constructor are not propagated to the anonymous class constructor
  • Type: CSR
  • Component: tools
  • Sub-Component: javac
  • Priority: P3
  • Status: Closed
  • Resolution: Withdrawn
  • Fix Versions: 19
  • Submitted: 2021-11-23
  • Updated: 2022-02-04
  • Resolved: 2022-02-04
Related Reports
CSR :  
Description
Summary
-------

Annotations applied to a constructor of a class `C` are not propagated to the corresponding constructor of an anonymous subclass of `C`. There are other cases in which annotations are automatically propagated like annotations in a record component which are propagated to several implicitly declared elements in a record class, in particular to its canonical constructor if it is not explicitly declared.

Problem
-------

Annotations applied to the constructor of a given class are not propagated to the corresponding constructor of an anonymous subclass. For example for code like:

```
    @Target(value = {ElementType.PARAMETER})
    @interface ParamAnnotation {}

    @Target(value = {ElementType.CONSTRUCTOR})
    @interface CtrAnnotation {}

    @Target({ElementType.TYPE_USE})
    @interface TypeAnno {}

    @Target({ElementType.TYPE_PARAMETER})
    @interface TypeAnnoForTypeParams {}

    class Test {
        @CtrAnnotation
        @TypeAnno
        <@TypeAnnoForTypeParams T> Test(String firstParam,
                                        @TypeAnno String secondParam,
                                        @ParamAnnotation String thirdParam) {}

        public void m() {
            // let's create an anonymous class
            new Test("", "", "") {};
        }
    }
```

none of the annotations applied to the constructor of class `Test` is propagated to the constructor of any anonymous subclass of it. Given that it is not possible to explicitly declare the constructor of an anonymous class, not propagating the annotations to the corresponding constructor in the anonymous subclass implies a hard limitation for which there is no possible workaround.

Solution
--------

The proposed solution is to propagate annotations applied to the constructor of a class `C` to the corresponding constructor of any anonymous subclass of `C`. This implies propagating declaration annotations applied to the constructor per se, declaration annotations applied to its parameters and type annotations applied to any type or type parameter.

Specification
-------------

The JLS doesn't mandate annotations applied to a constructor to be propagated to the corresponding constructor of an anonymous subclass but we are already propagating annotations in records in very similar cases. Not propagating annotations to anonymous class constructors seems inconsistent. Consider that we are currently propagating the parameter names to the anonymous class constructor, not propagating the annotations seems inconsistent and forces users to have more than one source of truth when looking for information. Also it should be considered that it impossible to explicitly apply annotations to the constructor of an anonymous class given that these constructors can't be explicitly declared.
Comments
PS Additionally JSR 308 did not define behavior in this area. Users in that domain should be queried about this change if this is to go forward. Defining handling of the receiver parameter would be needed as well.
20-01-2022

I'm moving this request back to Provisional, but also considered pending it. I'm not (yet) convinced the proposed change is either necessary or possible without some kind of spec update. Recording parameter names are not a JLS concern; they are a core reflection / javax.lang.model / compiler quality of implementation issue. It would be allowable by JLS (if unfriendly to users) if the parameters of anonymous subclasses were named "arg0", "arg1", etc. However, it is also fine by JLS, and more helpful to users, to propagate down the name from the superclass ctor in question. In contrast, JLS does say much more about annotations and how and when they do and do not get propagated: 8.9.3. Enum Members: For each enum constant c declared in the body of the declaration of E, E has an implicitly declared public static final field of type E that has the same name as c. The field has a variable initializer which instantiates E and passes any arguments of c to the constructor chosen for E. The field has the same annotations as c (if any). 8.10.1. Record Components Annotations on a record component declaration are available via reflection if their annotation interfaces are applicable in the record component context (§9.6.4.1). Independently, annotations on a record component declaration are propagated to the declarations of members and constructors of the record class if their annotation interfaces are applicable in other contexts (§8.10.3, §8.10.4). If a record class has a record component for which an accessor method is not declared explicitly, then an accessor method for that record component is declared implicitly, with the following properties: ... It is annotated with the annotations, if any, that appear on the corresponding record component and whose annotation interfaces are applicable in the method declaration context, or in type contexts, or both (§9.7.4). ... Annotations that appear on a record component are not propagated to an explicitly declared accessor method for that record component. In some situations, the programmer may need to duplicate a record component's annotations on an explicitly declared accessor method, but this is not generally necessary. If a canonical constructor is not explicitly declared in the declaration of a record class R, then a canonical constructor r is implicitly declared in R with the following properties: ... The derived formal parameter is annotated with the annotations, if any, that appear on the record component and whose annotation interfaces are applicable in the formal parameter context, or in type contexts, or both (§9.7.4). There are no analagous statements regards annotations and anonymous class constructors in JLS 15.9.5.1. Anonymous Constructors . If there were such a statement, I would support this change, but don't anticipate supporting it in the absence of such a statement.
20-01-2022

[~darcy] I have updated the text of the CSR describing in more detail the proposal
08-12-2021

Moving back to Provisional, not Approved. This CSR is extremely terse. Please expand the Solution and/or Specification sections describing the proposed adjustments in more detail.
07-12-2021

right I don't think there is right or wrong here, but IMO a matter of completeness and usability. Completeness in the sense that it is hard to explain that we propagate annotations to bridge methods but not for anonymous class constructors. Usability in the sense that if users are asking for this, there is a use case for using this information which needs then needs to be look for in the constructor of the anonymous class' super class.
06-12-2021

Moving to Provisional, not Approved. It isn't clear to me that the current behavior isn't as reasonable as the proposed new behavior. Bridge methods as separate entities in the class file are present due to limitations in the compilation strategy. For example, one could imagine an alternate scenario where the class file only had the "real" method and any bridge method was created solely in JVM-internal data structures, if at all.
05-12-2021