Initial spec for Repeating Annotations and Method Parameter Reflection

Joel Borggrén-Franck joel.franck at oracle.com
Tue Aug 21 12:59:24 PDT 2012


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. Foo-annotations are present in the source, and while reflection ins't a 1-1 mapping to source programmers tend to want that. We already live with the problem that runtime retention isn't the default, we shouldn't make the source-to-reflection gap bigger.

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


More information about the enhanced-metadata-spec-discuss mailing list