Anonymous classes are not final according to reflection API

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Mon Jun 29 13:57:43 UTC 2015


Ouch. It seems like this problem existed for a very long time; the logic 
used to strip away the ACC_FINAL flag from anon classes is more or less 
like this:

if (c.isInner() && c.name.isEmpty()) {
    flags &= ~FINAL;
}

Now, isInner() will only return true _if the class has an enclosing 
instance_ which is clearly not the case if an anon class appears in a 
static context.

In other words:

class Test{
    void finalNo() {
       new Object() { }; //ACC_FINAL not set
    }

     static void finalYesy() {
        new Object() { }; //ACC_FINAL set here
     }
}

javap Test\$1.class
Compiled from "Main.java"
class Test$1 {
   final Test this$0;
   Test$1(Test);
}

javap Test\$2.class
Compiled from "Main.java"
*final* class Test$2 {
   Test$2();
}

I think this should be fixed so that anon classes (regardless of their 
context) always have their ACC_FINAL bit unset; this is probably not 
very hot from a compatibility perspective (given that it's been like 
that for a long time) - but, given the consistency issue and the fact 
that reflection cannot handle this anyway, I'd say we should just make 
this consistent.

Thoughts?

Maurizio


On 29/06/15 14:49, Maurizio Cimadamore wrote:
> More specifically, I was talking about this related issue:
>
> https://bugs.openjdk.java.net/browse/JDK-8130032
>
> Popping back one level, I think the issue you are seeing there, is 
> that ACC_FINAL is erroneosuly set by javac for diamond anon classes. 
> This seems to be against all the documentation that can be found on 
> JBS = example:
>
> https://bugs.openjdk.java.net/browse/JDK-8023945
>
> I seem to be able to get javac spit out ACC_FINAL reliably on JDK 
> 7/8/9 - so the question is - when did it come back? Was it deliberate? 
> If so, was reflection ever updated to handle this?
>
> Maurizio
>
> On 29/06/15 14:36, Remi Forax wrote:
>> yes, right,
>> it seems to be a backward compatibility land of mines.
>>
>> Rémi
>>
>> On 06/29/2015 03:29 PM, Maurizio Cimadamore wrote:
>>> I've closed it as 'not an issue' - this seems to be an outstanding 
>>> issue that was fixed for some time and then reverted because of 
>>> compatibility problems:
>>>
>>> https://bugs.openjdk.java.net/browse/JDK-6520152
>>>
>>> Maurizio
>>>
>>> On 23/06/15 14:42, Georgiy Rakov wrote:
>>>> I've filed the issue JDK-8129576. 
>>>> <https://bugs.openjdk.java.net/browse/JDK-8129576>
>>>>
>>>> There is following issue in JBS: JDK-4777101 
>>>> <https://bugs.openjdk.java.net/browse/JDK-4777101> which seems to 
>>>> relate to this one.
>>>>
>>>> Thank you,
>>>> Georgiy.
>>>>
>>>> On 22.06.2015 18:56, Victor Rudometov wrote:
>>>>> This seems to be a reflection bug, since ACC_FINAL is present in 
>>>>> Test12$1.class file:
>>>>>
>>>>> final class test.Test12$1 extends test.Test12$Foo<java.lang.Integer>
>>>>>   minor version: 0
>>>>>   major version: 52
>>>>>   flags: ACC_FINAL, ACC_SUPER
>>>>>
>>>>> Thanks.
>>>>> Victor.
>>>>>
>>>>> On 22-Jun-15 18:35, Remi Forax wrote:
>>>>>> I wonder if it's not a reflection bug,
>>>>>> did you check with 'javap -c -verbose' the modifiers of the 
>>>>>> generated class (something like Test12$1.class) ?
>>>>>>
>>>>>> cheers,
>>>>>> Rémi
>>>>>>
>>>>>> On 06/22/2015 05:17 PM, Georgiy Rakov wrote:
>>>>>>> Hello,
>>>>>>>
>>>>>>> if I understand correctly according to following assertion from 
>>>>>>> JLS 15.9.5 anonymous classes are always final:
>>>>>>>
>>>>>>>     An anonymous class is always implicitly final (§8.1.1.2).
>>>>>>>
>>>>>>> But reflection API reports that the class is not final. Namely 
>>>>>>> let's consider following code:
>>>>>>>
>>>>>>>     import java.lang.reflect.Modifier;
>>>>>>>
>>>>>>>     public class Test12 {
>>>>>>>         static class Foo<T> {}
>>>>>>>
>>>>>>>         public static void main(String argv[]) {
>>>>>>>             Foo<Integer> foo = new Foo<>() {};
>>>>>>>             if ( (foo.getClass().getModifiers() &
>>>>>>>     Modifier.FINAL) != 0 ) {
>>>>>>>                 System.out.println("final, modifiers: " +
>>>>>>>     foo.getClass().getModifiers());
>>>>>>>             } else {
>>>>>>>                 System.out.println("not final, modifiers: " +
>>>>>>>     foo.getClass().getModifiers());
>>>>>>>             }
>>>>>>>         }
>>>>>>>     }
>>>>>>>
>>>>>>> On JDK9b69 it reports:
>>>>>>>
>>>>>>>     not final, modifiers: 0
>>>>>>>
>>>>>>> Could you please tell if you consider this as a discrepancy 
>>>>>>> between spec and javac (VM?) which should be fixed.
>>>>>>>
>>>>>>> Thank you,
>>>>>>> Georgiy.
>>>>>>
>>>>>
>>>>
>>>
>>
>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openjdk.java.net/pipermail/compiler-dev/attachments/20150629/55f1a95c/attachment-0001.html>


More information about the compiler-dev mailing list