RFR: JDK-8044629: (reflect) Constructor.getAnnotatedReceiverType() returns wrong value

Martin Buchholz martinrb at google.com
Thu Jul 21 18:39:57 UTC 2016


Joel, Thanks for responding so quickly!

Here' s a slightly modified version of my repro recipe:
You can see that local classes in instance methods have a receiver type,
just like a member inner class.
local classes in static methods (naturally!) do not.  I expect the two
flavors of local classes to be treated differently.

I've never understood why
"""All local classes are inner classes"""
(even in a static method?)
https://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.3


import java.lang.reflect.Constructor;

public class LocalClassReceiverTypeBug {
    public static void main(String[] args) throws Throwable {
        class StaticLocal {}
        printConstructor(StaticLocal.class);
        new LocalClassReceiverTypeBug().instanceMain();
    }

    public void instanceMain() throws Throwable {
        class InstanceLocal {}
        printConstructor(InstanceLocal.class);
        printConstructor(Inner.class);
        // printConstructor(Nested.class);
    }

    static class Nested {}
    class Inner {}

    static void printConstructor(Class<?> klazz) {
        Constructor<?>[] constructors = klazz.getDeclaredConstructors();
        if (constructors.length != 1) throw new AssertionError();
        Constructor<?> constructor = constructors[0];
        System.out.printf("constructor=%s receivertype=%s%n",
                          constructor,
                          constructor.getAnnotatedReceiverType());
    }
}
==> javac -source 9 -Xlint:all LocalClassReceiverTypeBug.java
==> java -esa -ea LocalClassReceiverTypeBug
constructor=LocalClassReceiverTypeBug$1StaticLocal() receivertype=null
constructor=LocalClassReceiverTypeBug$1InstanceLocal(LocalClassReceiverTypeBug)
receivertype=null
constructor=LocalClassReceiverTypeBug$Inner(LocalClassReceiverTypeBug)
receivertype=sun.reflect.annotation.AnnotatedTypeFactory$AnnotatedTypeBaseImpl at 1810399e


On Thu, Jul 21, 2016 at 11:16 AM, Joel Borggrén-Franck <
joel.borggren.franck at gmail.com> wrote:

> Hi Martin,
>
> I'm away from my workstation at the moment, so this is from memory. IIRC a
> local class is pure scoping and lacks an "outer this" which is what you
> annotate for constructors. There should not be receiver type to annotate.
> Since I can't run your code I can't see what's wrong but I might be able to
> help if you paste the output from a run.
>
> Cheers
> /Joel
>
> On Jul 21, 2016 19:49, "Martin Buchholz" <martinrb at google.com> wrote:
>
>> Hi Joel, Paul,
>>
>> A coworker ran into the change of behavior here in jdk9.  Specifically,
>> we noticed that a local class constructor has a receiver parameter,
>> but getAnnotatedReceiverType returns null.  The changed jdk9 spec is
>> actually very clear about that:
>>
>>
>> http://download.java.net/java/jdk9/docs/api/java/lang/reflect/Constructor.html#getAnnotatedReceiverType--
>> """If this Executable object represents a static method or represents a
>> constructor of a top level, static member, local, or anonymous class, then
>> the return value is null."""
>>
>> BUT we can't think of any reason WHY a local inner class would be treated
>> differently from an inner member class.  Why not the simple and obvious
>> rule: if there is a receiver parameter, return an appropriate non-null
>> AnnotatedType?
>>
>> You already have an excellent jtreg test, but here's what I was playing
>> with:
>>
>> import java.lang.reflect.Constructor;
>>
>> public class LocalClassReceiverTypeBug {
>>     public static void main(String[] args) throws Throwable {
>>         class StaticLocal {}
>>         printConstructor(StaticLocal.class);
>>         new LocalClassReceiverTypeBug().instanceMain();
>>     }
>>
>>     public void instanceMain() throws Throwable {
>>         class InstanceLocal {}
>>         printConstructor(InstanceLocal.class);
>>         printConstructor(Inner.class);
>>         printConstructor(Nested.class);
>>     }
>>
>>     static class Nested {}
>>     class Inner {}
>>
>>     static void printConstructor(Class<?> klazz) {
>>         Constructor<?>[] constructors = klazz.getDeclaredConstructors();
>>         if (constructors.length != 1) throw new AssertionError();
>>         System.out.printf("constructor=%s%n", constructors[0]);
>>         System.out.printf("receiver type=%s%n",
>>                           constructors[0].getAnnotatedReceiverType());
>>     }
>> }
>>
>>
>>
>> On Wed, Aug 13, 2014 at 1:54 AM, Joel Borggren-Franck <
>> joel.franck at oracle.com> wrote:
>>
>>> Hi Paul,
>>>
>>> On 2014-06-24, Paul Sandoz wrote:
>>> >
>>> > On Jun 17, 2014, at 6:52 PM, Joel Borggrén-Franck <
>>> joel.franck at oracle.com> wrote:
>>> > >
>>> > > Can I get a review for this fix and javadoc clarification for
>>> https://bugs.openjdk.java.net/browse/JDK-8044629
>>> > >
>>> >
>>> > +1
>>> >
>>> > I never quite realised just how convoluted it was to determine that a
>>> class is an inner class.
>>>
>>> Neither did I until I had to implement it :)
>>>
>>> cheers
>>> /Joel
>>>
>>
>>


More information about the core-libs-dev mailing list