Initial spec for Repeating Annotations and Method Parameter Reflection
Rémi Forax
forax at univ-mlv.fr
Tue Aug 21 13:45:07 PDT 2012
On 08/21/2012 09:59 PM, Joel Borggrén-Franck wrote:
> Hi Remi,
>
> Thanks for your feedback!
>
> Inline,
>
> On Aug 21, 2012, at 8:53 PM, Rémi Forax <forax at univ-mlv.fr> wrote:
>
>> On 08/21/2012 06:57 PM, Alex Buckley wrote:
>>> Initially we didn't have @ContainerFor, and thought it would be possible
>>> to "infer" that an annotation T is a "container" by checking that its
>>> value() element's return type T' is indeed an annotation type which
>>> expects to be contained by T. A small matter of programming, as some
>>> might say. However, for compatibility reasons, this turned out to be
>>> insufficient. Here's the reasoning:
>>>
>>> A marker annotation is needed because lines (1) and (2) below compile to
>>> the same ClassFile structure, yet the reflective API which operates on
>>> that structure needs to determine whether the repetition was implicit
>>> (1) or explicit (2) in order to give results that satisfy legacy
>>> consumers.
>>>
>>> (1) @Foo(1) @Foo(2) class A {}
>>> (2) @FooContainer({@Foo(1), @Foo(2)}) class A {}
>>>
>>> - If the source was (1), then
>>> A.class.get[Declared]Annotation(Foo.class) should "look through" the
>>> synthesized container and return @Foo(1). In particular, if the source
>>> was initially annotated with just @Foo(1), then adding @Foo(2) should
>>> not change the result from @Foo(1) to null (because the @Foo's were
>>> wrapped in a @FooContainer). The act of repeating an annotation is
>>> source-compatible, and a source-compatible change in code should not
>>> imply a behavior-incompatible change for reflective code.
>>>
>>> - If the source was (2), then
>>> A.class.get[Declared]Annotation(Foo.class) should _not_ look through
>>> @FooContainer (since it was written by hand in legacy code) and should
>>> return null (since there are logically no @Foo's on class A in (2)).
>>>
>>> You can see that it's not always desirable to "look through" an annotation which "appears" to be a container based on its value() element. The explicit @ContainerFor seems like a useful and reasonable piece of documentation.
>> I think the following assumption is broken,
>> [with get[Declared]Annotation(Foo.class)]
>> "In particular, if the source was initially annotated with just @Foo(1), then adding @Foo(2) should not change the result from @Foo(1) to null"
>>
>> It should be true with get[Declared]Annotations (with an 's' at the end) not with get[Declared]Annotation,
>> it's not a good idea to choose between the two Foo, because annotations are like modifiers,
>> @Foo(1) @Foo(2) should be equivalent to @Foo(2) @Foo(1). And here, you clearly break that rule.
>>
> I disagree with you on this point. While implementing this I did a lot of hallway testing, and all the people I asked think that in the example above,
>
> get[Declared]Annotation(Foo.class) => null
>
> is a (much) bigger bad than choosing, say, the leftmost in a left-to-right source order.
We all know that it depends how you ask the question, i.e. I suppose you
don't paint the whole picture, see below.
> Foo-annotations are present in the source, and while reflection ins't a 1-1 mapping to source programmers tend to want that.
You can't say, the user has to be aware that he has to declare a
container annotation, this is not a hidden detail, and at the same time
say that we should provide a 1-1 mapping.
Also Java has a long tradition of ignoring the order of the declaration
element, especially modifiers.
Just ask the the people if they think that
@Foo(1) @Foo(2) class A {}
should be behaviorally different from
@Foo(2) @Foo(1) class A {}
There is no free lunch here, and I do think that the proposed design is
not the right trade off,
users of the reflection API, users that create annotations and container
annotations will be fully aware that in the bytecode an annotation
container will be used, so I think that trying to hide a detail they
will have to know just plain wrong.
so get[Declared]Annotation can return null if the javadoc explains that
users should use get[Declared]Annotation instead.
> We already live with the problem that runtime retention isn't the default, we shouldn't make the source-to-reflection gap bigger.
You also see the hidden parameters of the enum constructor, you can't
access to enclosing private variable and so on.
>
> Also note that on the byte code level, the proposed spec writeup says that @Foo(1) @Foo(2) isn't equivalent to @Foo(2) @Foo(1).
>
> cheers
> /Joel
cheers,
Rémi
More information about the enhanced-metadata-spec-discuss
mailing list