Proposal to make new-in-Java-SE-8 methods on AnnotatedElement default methods

Alex Buckley alex.buckley at oracle.com
Thu Oct 24 11:37:15 PDT 2013


On 10/24/2013 8:34 AM, Joel Borggrén-Franck wrote:
> On 24 okt 2013, at 15:16, Joe Darcy <joe.darcy at oracle.com> wrote:
>>
>>
>> +     * @implSpec The default implementation first calls {@link
>> +     * #getAnnotation(Class)} on the argument type. If the annotation
>> +     * is directly or indirectly present, it is returned in an
>> +     * one-element array. Otherwise, if the argument annotation type
>> +     * is repeatable and an annotation of the container type is
>> +     * directly or indirectly present, then the returned result is
>> +     * equal to the result of calling the {@code value} method on the
>> +     * container annotation.
...
>> -    <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass);
>> +    default <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass) {
>>
>
> This is the wrong order. The precise lookup of an associated annotation is declared then inherited, quoting the javadoc for AnnotatedElement:

Yes, and the root cause is an inconsistency in the @implSpec. The first 
call to getAnnotation(Class) will tell you if an annotation is 
_present_, which is not the same thing as "directly or indirectly 
present". In fact, as a legacy method, getAnnotation(Class) will never 
reveal an indirectly present annotation. The @implSpec should say "If an 
annotation of type T is present, it is included in the returned array. 
[If multiple annotations of type T are present because someone made a 
Runtime*Annotations attribute with @Foo @Foo by hand, then the first is 
chosen.]"

There's a bigger problem: the word "Otherwise". The intent of 
getAnnotationsByType(Class) is to expose the directly present annotation 
(if any) _and_ indirectly present annotations as may be found in a 
container annotation. This is Example 1.2-3 in 8misc.pdf, where an @Foo 
and an @FooContainer are side by side on an element. Returning a 
one-element array can't be right.

>> +     * @implSpec The default implementation first calls {@link
>> +     * #getDeclaredAnnotation(Class)} on the argument type. If the
>> +     * annotation is directly present, it is returned in an
>> +     * one-element array. Otherwise, if the argument annotation type
>> +     * is repeatable and an annotation of the container type is
>> +     * directly present, then the returned result is equal to the
>> +     * result of calling the {@code value} method on the container
>> +     * annotation.
>> +     *
>>       * @param <T> the type of the annotation to query for and return
>>       * if directly or indirectly present
>>       * @param annotationClass the Class object corresponding to the
>> @@ -277,7 +315,9 @@
>>       * @throws NullPointerException if the given annotation class is null
>>       * @since 1.8
>>       */
>> -    <T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass);
>> +    default <T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass) {
>>
>
> This should work.

In a similar fashion to above, the intent of 
getDeclaredAnnotationsByType(Class) is to reveal all directly and 
indirectly present annotations, not just one directly present annotation.

>> +     * @implSpec The default implementation first performs a null check
>> +     * and then loops over the results of {@link
>> +     * getDeclaredAnnotations} returning the first annotation whose
>> +     * annotation type matches the argument type.
>> +     *
>>       * @param <T> the type of the annotation to query for and return if directly present
>>       * @param annotationClass the Class object corresponding to the
>>       *        annotation type
>> @@ -247,7 +265,18 @@
>>       * @throws NullPointerException if the given annotation class is null
>>       * @since 1.8
>>       */
>> -    <T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass);
>> +    default <T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass) {
>>
>
> Wouldn't this risk the same issues as when we turned isAnnotationPresent() into a default?

The spec is correct though :-)

Alex


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