JDK-8162501 : getAnnotatedReceiverType of a local class constructor returns null
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang:reflect
  • Affected Version: 8u40,9,20
  • Priority: P3
  • Status: In Progress
  • Resolution: Unresolved
  • Submitted: 2016-07-25
  • Updated: 2024-07-15
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
tbdUnresolved
Related Reports
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Description
JDK-8044629 changed the behavior so that Constructor.getAnnotatedReceiverType() does not return bogus non-null values.  But it seems it is a little overzealous.  For local classes of non-static methods, there is a receiver type (as demonstrated by the constructors below), and so getAnnotatedReceiverType should not return null.  Or perhaps javac and core reflection disagree?

Try running the demo program below with jdk8 and jdk9:
In jdk8 we get the correct output:
receiver type=sun.reflect.annotation.AnnotatedTypeFactory$AnnotatedTypeBaseImpl@6d06d69c
receiver type=sun.reflect.annotation.AnnotatedTypeFactory$AnnotatedTypeBaseImpl@7852e922
In jdk9 we get:
receiver type=null
receiver type=sun.reflect.annotation.AnnotatedTypeFactory$AnnotatedTypeBaseImpl@5f375618

/*
 * Copyright 2016 Google Inc.  All Rights Reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

import java.lang.reflect.Constructor;

public class ReceiverType {

    public static void main(String[] args) throws Throwable {
        new ReceiverType().instanceMain();
    }

    class Member {
        Member(ReceiverType ReceiverType.this) {}
    }

    public void instanceMain() throws Throwable {
        class Local {
            Local(ReceiverType ReceiverType.this) {}
        }
        printConstructor(Local.class);
        printConstructor(Member.class);
    }

    static void printConstructor(Class<?> klazz) {
        Constructor<?>[] constructors = klazz.getDeclaredConstructors();
        if (constructors.length != 1) throw new AssertionError();
        System.out.printf("receiver type=%s%n",
                          constructors[0].getAnnotatedReceiverType());
    }
}

Comments
JLS doesn't specify how compilers should translate anonymous or local classes; therefore, they don't reliably have receiver "outer this" types. And the exact type that is the "outer this" may change with Flexible constructors JEP with anonymous or local classes in constructor prologue. Thus, it would be the most consistent for core reflections to simply return null for the receiver for any local or anonymous "outer this".
15-07-2024

It is possible to produce the receiver type of a local or anonymous class if it is enclosed within a constructor (always non-static) or a method (we know if it's static or not), but for local or anonymous classes declared in instance or class initializers, there is no way to distinguish them reliably (i.e. regular block or static block) without the MethodParameters attribute. With MethodParameters attribute, it would be possible to check for the mandated enclosing class instance passed to the constructors and thus derive the annotated receiver type.
05-04-2023

1. It's worth more clearly distinguishing between "There is a receiver parameter written in source code; here is an object representing its (potentially annotated) type as written" and "There was no receiver parameter written in source code; I'm going to synthesize an object representing a type that I think is right." 2. "If this Executable object represents ~~a constructor or~~ **an** instance method that does not have a receiver parameter, ~~or has a receiver parameter with no annotations on its type,~~ then the return value is an AnnotatedType object representing ~~an element with no annotations~~ **the type of the declaring class**." -- it's good to specify the implicit receiver type, but don't forget to mandate that the AnnotatedType object embodies no annotations. (What if the declaring class has declaration annotations on it? We don't want them here.)
21-04-2017

Actual behavior should be changed to follow this spec.
21-04-2017

Here's the spec (from javadoc): "Returns an AnnotatedType object that represents the use of a type to specify the receiver type of the method/constructor represented by this Executable object. The receiver type of a method/constructor is available only if the method/constructor has a receiver parameter (JLS 8.4.1). If this Executable object represents a constructor or instance method that does not have a receiver parameter, or has a receiver parameter with no annotations on its type, then the return value is an AnnotatedType object representing an element with no annotations. If this Executable object represents a static method, then the return value is null." This is confusing and incomplete; "available only if the method/constructor has a receiver parameter" is contradicted by the next sentence. Suggested: "Returns an AnnotatedType object that represents the use of a type to specify the receiver **parameter** type of the method/constructor represented by this Executable object **(JLS 8.4.1)**. ~~The receiver type of a method/constructor is available only if the method/constructor has a receiver parameter (JLS 8.4.1).~~ If this Executable object represents ~~a constructor or~~ **an** instance method that does not have a receiver parameter, ~~or has a receiver parameter with no annotations on its type,~~ then the return value is an AnnotatedType object representing ~~an element with no annotations~~ **the type of the declaring class**. **If this Executable object represents a constructor that does not have a receiver parameter, declared by an inner class that does not occur in a static context, then the return value is an AnnotatedType object representing the type of the immediately enclosing type declaration.** If this Executable object represents a static method, **a constructor of a class that is not an inner class, or a constructor of an inner class occurring in a static context,** then the return value is null."
21-04-2017