[type-annos-observers] annotated type of array-typed varargs parameter

Alex Buckley alex.buckley at oracle.com
Thu Apr 10 21:43:45 UTC 2014


Thanks Markus, I updated JDK-8038881 for 8.4.1 and 10.2.

There's no need for "(possibly annotated)" as generally the JLS doesn't 
flag where annotations are possible - that's centralized in 9.7.4. The 
SE API spec has a similar trick: java.lang.reflect.AnnotatedType speaks 
of a "potentially annotated use of a type" so that we don't have to say 
that in all the places which return AnnotatedType, e.g. 
Class#getAnnotatedSuperclass, Field#getAnnotatedType, etc.

Alex

On 4/6/2014 12:43 PM, Markus Keller wrote:
> Hi Alex
>
> Thanks for the clarification.
>
> 8.4.1 also defines: "a variable arity parameter, indicated by an ellipsis
> following the type." Strictly speaking, it should be "indicated by a
> (possibly annotated) ellipsis following the type".
>
> Using 10.2 to hold the definition of a variable's type sounds good. The
> final text should also tell that annotations belong to the bracket pair or
> ellipsis that follows them, so that it's clear that the annotations are
> reason for the explicit specification of the order of the array
> dimensions.
>
> Markus
>
> "type-annotations-spec-observers"
> <type-annotations-spec-observers-bounces at openjdk.java.net> wrote on
> 2014-04-04 21:04:39:
>
>> From: Alex Buckley <alex.buckley at oracle.com>
>> To: type-annotations-spec-experts
> <type-annotations-spec-experts at openjdk.java.net>
>> Date: 2014-04-04 21:04
>> Subject: Re: [type-annos-observers] annotated type of array-typed
> varargs parameter
>> Sent by: "type-annotations-spec-observers"
> <type-annotations-spec-observers-bounces at openjdk.java.net>
>>
>> Hi Markus,
>>
>> I think it's pretty clear that the "intuitive order" is desirable, for
>> two reasons:
>>
>> 1) It should be possible to refactor pArr's type to match pVar's type by
>
>> replacing the final [] with '...', and not change the array type of
>> pVar. That is, the following method call (in someone else's code, so
>> can't be easily changed) should keep working after the refactoring:
>>
>>     var(new Object @A [] {});
>>
>> 2) I see this more as a spec issue than a true design issue. Formerly,
>> the array type was specified in recursive fashion, building on the
>> component type ("the component type is the UnannType"). That's why, for
>> a variable arity parameter, it looked like the compiler was constructing
>
>> an array of type Object @B [] @A []. But we've generally come to specify
>
>> array types in a linear fashion, which would mean the compiler is deemed
>
>> to construct an array of type Object @A [] @B [] (or Object @A [] if you
>
>> omit later dimensions, as in method call above).
>>
>> With reference to JDK-8038881, I'd propose to have 8.4.1 always point to
>
>> 10.2 for a variable arity parameter, and for 10.2 to build up the
>> parameter's type in basically the same fashion as for other array types
>> [excluding post-identifier [], of course, since they're not legal here].
>>
>> Happily, JLS 15.12.2 which considers variable arity parameters speaks
>> only of the full array type T[] which is the type of the last parameter.
>
>> So that is unaffected by clarifications to 8.4.1 / 10.2, as long as
>> 8.4.1 / 10.2 are deterministic about the outermost dimension.
>>
>> Alex
>>
>> On 4/4/2014 7:14 AM, Markus Keller wrote:
>>> We've found a problem with the definition of the varargs syntax on
> array
>>> types. The methods "var" and "arr" below should intuitively have the
> same
>>> formal parameter type "Object @A [] @B []", but that clashes with the
>>> order of annotations on array dimensions:
>>>
>>> interface Test {
>>>           void var(Object @A [] @B ... pVar);
>>>           void arr(Object @A [] @B [] pArr);
>>> }
>>> @Target(ElementType.TYPE_USE) @interface A { }
>>> @Target(ElementType.TYPE_USE) @interface B { }
>>>
>>> The clarification for 8.4.1 in
>>> https://bugs.openjdk.java.net/browse/JDK-8038881 says: "If the formal
>>> parameter is a variable arity parameter, then the declared type is an
>>> array type whose component type is UnannType."
>>>
>>> In "var", the UnannType is "Object @A []", so the type of the
> parameter is
>>> actually "Object @B [] @A []", according to the annotation order given
> in
>>> 9.7.4.
>>>
>>> In JDK 1.8.0-b132, reflection uses the intuitive order. The snippet
> below
>>> prints:
>>>
>>> var:   class java.lang.Object @A [] @B []
>>> arr:   class java.lang.Object @A [] @B []
>>>
>>> That's incorrect according to JLS8. java-annotation-design.html
> doesn't
>>> address this problem (just says "The varargs syntax “...” is treated
>>> analogously to array brackets").
>>>
>>> I don't see a good solution.
>>> a) Say JLS8 is right. => We lose the simple transformation that turns
> a
>>> vararg into a normal array dimension by changing ... into [].
>>> b) Say the above transformation must be valid. => The annotation in
> front
>>> of the ... no longer applies to the outermost array type, which is
> also
>>> strange, because that's the array that is constructed by the compiler
> for
>>> a variable arity method invocation.
>>>
>>>
>>>
>>> import java.lang.annotation.*;
>>> import java.lang.reflect.*;
>>> import java.util.stream.*;
>>>
>>> @Target(ElementType.TYPE_USE) @Retention(RetentionPolicy.RUNTIME)
>>> @interface A {}
>>> @Target(ElementType.TYPE_USE) @Retention(RetentionPolicy.RUNTIME)
>>> @interface B {}
>>>
>>> public class Snippet {
>>>       void var(Object @A [] @B ... pVar) { }
>>>       void arr(Object @A [] @B [] pArr) { }
>>>
>>>       public static void main(String[] args) throws Exception {
>>>           printParamType(Snippet.class.getDeclaredMethod("var",
>>>                   Object[][].class));
>>>           printParamType(Snippet.class.getDeclaredMethod("arr",
>>>                   Object[][].class));
>>>       }
>>>
>>>       private static void printParamType(Method method) {
>>>           System.out.printf("%-5s %s\n", method.getName() + ":",
>>>                   toString(method.getAnnotatedParameterTypes()[0]));
>>>       }
>>>
>>>       private static String toString(AnnotatedType annotatedType) {
>>>           StringBuilder sb = new StringBuilder();
>>>           while (annotatedType instanceof AnnotatedArrayType) {
>>>               sb.append(" ")
>>>                       .append(toString(annotatedType.getAnnotations()))
>>>                       .append("[]");
>>>               annotatedType = ((AnnotatedArrayType) annotatedType)
>>>                       .getAnnotatedGenericComponentType();
>>>           }
>>>           Type type = annotatedType.getType();
>>>           sb.insert(0, type.toString());
>>>           sb.insert(0, toString(annotatedType.getAnnotations()));
>>>           return sb.toString();
>>>       }
>>>
>>>       private static String toString(Annotation[] annotations) {
>>>           return Stream.of(annotations).map(Snippet::toSimpleString).
>>>                   collect(Collectors.joining(" ", "", " "));
>>>       }
>>>
>>>       public static String toSimpleString(Annotation a) {
>>>           return "@" + a.annotationType().getSimpleName();
>>>       }
>>> }
>>>
>>> Markus
>>>
>>
>


More information about the type-annotations-spec-observers mailing list