Anonymous classes are not final according to reflection API
Dan Smith
daniel.smith at oracle.com
Thu Jul 2 22:10:55 UTC 2015
> On Jun 29, 2015, at 7:57 AM, Maurizio Cimadamore <maurizio.cimadamore at oracle.com> wrote:
>
> 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.
If we're making a change to which flags are set, we might as well do it properly and make them all final, no? One way or another, you're going to change some serialization UIDs.
Really, javac is free to implement anonymous classes however it likes (with a few small constraints from JLS, notably in Chapter 13). If it wants to spell all the synthetic field names backwards on Tuesdays, that's it's business. Anybody relying on certain conventions for serialization between recompiled anonymous classes is playing a risky game, and they should not be surprised if things break from time to time.* (Some smaller examples that would also change some UIDs: different bridge generation strategies; different methods produced by lambda/method reference compilation; refining the implementation of asserts; improvements in diamond inference.)
That said, I get the practical constraint of not rocking the boat if there's not a compelling need to do so. And it's notable that this would impact a lot more UIDs than the typical bug fix.
However:
- The JLS assertion "An anonymous class is always implicitly final" is meaningless if it's not interpreted as "the ACC_FINAL flag on the generated class is set", so if we're not going to enforce that, the assertion should be dropped. (The other assertions in 15.9.5 have language-level implications, but not this, since none of the corresponding language restrictions in 8.1.1.2 could ever arise.)
- I don't know why reflection is colluding with javac here. Dynamically changing flags seems to pretty directly violate the Class.getModifiers spec. Does the computation of serialVersionUID rely on reflection? If so, doesn't this flag-modification logic belong there, rather than breaking reflection for everyone? If not, who's relying on the reflection behavior?
—Dan
[* It's "strongly recommended", in italics no less, not to rely on this. From java.lang.Serializable: "it is _strongly recommended_ that all serializable classes explicitly declare serialVersionUID values, since the default serialVersionUID computation is highly sensitive to class details that may vary depending on compiler implementations, and can thus result in unexpected InvalidClassExceptions during deserialization"]
More information about the compiler-dev
mailing list