annotated type of array-typed varargs parameter
Alex Buckley
alex.buckley at oracle.com
Fri Apr 4 19:04:39 UTC 2014
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-experts
mailing list