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

David Holmes david.holmes at oracle.com
Fri Jul 22 01:20:10 UTC 2016


On 22/07/2016 4:50 AM, Joel Borggrén-Franck wrote:
> This is the first time I noticed the second paragraph of $14.3, strange
> indeed! I'd ping compiler-dev with this, Alex will probably know if this is
> a spec bug in $14.3 or just an irregularity.

It is an irregularity - for want of a better word. See:

https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.1.3

"An instance of an inner class I whose declaration occurs in a static 
context has no lexically enclosing instances. "

David
-----

> Cheers
> /Joel
>
> On Jul 21, 2016 20:39, "Martin Buchholz" <martinrb at google.com> wrote:
>
>> 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