8007961: javax.lang.model tests for repeating annotations fail in getAnnotationsByType
Reviewed-by: jjg
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java Wed Jul 24 17:35:42 2013 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java Thu Jul 25 11:02:27 2013 +0200
@@ -596,7 +596,7 @@
// This method is part of the javax.lang.model API, do not use this in javac code.
public <A extends java.lang.annotation.Annotation> A[] getAnnotationsByType(Class<A> annoType) {
- return JavacAnnoConstructs.getAnnotations(this, annoType);
+ return JavacAnnoConstructs.getAnnotationsByType(this, annoType);
}
// TODO: getEnclosedElements should return a javac List, fix in FilteredMemberList
--- a/langtools/src/share/classes/com/sun/tools/javac/model/JavacAnnoConstructs.java Wed Jul 24 17:35:42 2013 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/model/JavacAnnoConstructs.java Thu Jul 25 11:02:27 2013 +0200
@@ -108,20 +108,38 @@
}
// Helper to getAnnotation[s]
- private static <A extends Annotation> Attribute.Compound getAttributeOnClass(ClassSymbol annotated,
- Class<A> annoType) {
+ private static <A extends Annotation> Attribute.Compound getAttributeOnClass(
+ ClassSymbol annotated,
+ final Class<A> annoType)
+ {
boolean inherited = annoType.isAnnotationPresent(Inherited.class);
Attribute.Compound result = null;
- while (annotated.name != annotated.name.table.names.java_lang_Object) {
+
+ result = getAttribute(annotated, annoType);
+ if (result != null || !inherited)
+ return result;
+
+ while ((annotated = nextSupertypeToSearch(annotated)) != null) {
result = getAttribute(annotated, annoType);
- if (result != null || !inherited)
- break;
- Type sup = annotated.getSuperclass();
- if (!sup.hasTag(CLASS) || sup.isErroneous())
- break;
- annotated = (ClassSymbol) sup.tsym;
+ if (result != null)
+ return result;
}
- return result;
+ return null; // no more supertypes to search
+ }
+
+ /**
+ * Returns the next type to search for inherited annotations or {@code null}
+ * if the next type can't be found.
+ */
+ private static ClassSymbol nextSupertypeToSearch(ClassSymbol annotated) {
+ if (annotated.name == annotated.name.table.names.java_lang_Object)
+ return null;
+
+ Type sup = annotated.getSuperclass();
+ if (!sup.hasTag(CLASS) || sup.isErroneous())
+ return null;
+
+ return (ClassSymbol) sup.tsym;
}
/**
@@ -129,8 +147,9 @@
* annotations. This is the implementation of
* Element.getAnnotations(Class).
*/
- public static <A extends Annotation> A[] getAnnotations(Symbol annotated,
- Class<A> annoType) {
+ public static <A extends Annotation> A[] getAnnotationsByType(Symbol annotated,
+ Class<A> annoType)
+ {
if (!annoType.isAnnotation())
throw new IllegalArgumentException("Not an annotation type: "
+ annoType);
@@ -153,62 +172,48 @@
}
// So we have a containing type
- String name = annoType.getName();
String annoTypeName = annoType.getSimpleName();
String containerTypeName = containerType.getSimpleName();
int directIndex = -1, containerIndex = -1;
Attribute.Compound direct = null, container = null;
- Attribute.Compound[] rawAttributes = annotated.getRawAttributes().toArray(new Attribute.Compound[0]);
-
- // Find directly present annotations
- for (int i = 0; i < rawAttributes.length; i++) {
- if (annoTypeName.equals(rawAttributes[i].type.tsym.flatName().toString())) {
- directIndex = i;
- direct = rawAttributes[i];
+ // Find directly (explicit or implicit) present annotations
+ int index = -1;
+ for (List<Attribute.Compound> list = annotated.getAnnotationMirrors();
+ !list.isEmpty();
+ list = list.tail) {
+ Attribute.Compound attribute = list.head;
+ index++;
+ if (attribute.type.tsym.flatName().contentEquals(annoTypeName)) {
+ directIndex = index;
+ direct = attribute;
} else if(containerTypeName != null &&
- containerTypeName.equals(rawAttributes[i].type.tsym.flatName().toString())) {
- containerIndex = i;
- container = rawAttributes[i];
+ attribute.type.tsym.flatName().contentEquals(containerTypeName)) {
+ containerIndex = index;
+ container = attribute;
}
}
// Deal with inherited annotations
- if (annotated.kind == Kinds.TYP &&
- (annotated instanceof ClassSymbol)) {
- ClassSymbol s = (ClassSymbol)annotated;
- if (direct == null && container == null) {
- direct = getAttributeOnClass(s, annoType);
- container = getAttributeOnClass(s, containerType);
-
- // both are inherited and found, put container last
- if (direct != null && container != null) {
- directIndex = 0;
- containerIndex = 1;
- } else if (direct != null) {
- directIndex = 0;
- } else {
- containerIndex = 0;
- }
- } else if (direct == null) {
- direct = getAttributeOnClass(s, annoType);
- if (direct != null)
- directIndex = containerIndex + 1;
- } else if (container == null) {
- container = getAttributeOnClass(s, containerType);
- if (container != null)
- containerIndex = directIndex + 1;
+ if (direct == null && container == null) {
+ if (annotated.kind == Kinds.TYP &&
+ (annotated instanceof ClassSymbol)) {
+ ClassSymbol s = nextSupertypeToSearch((ClassSymbol)annotated);
+ if (s != null)
+ return getAnnotationsByType(s, annoType);
}
}
// Pack them in an array
- Attribute[] contained0 = new Attribute[0];
+ Attribute[] contained0 = null;
if (container != null)
contained0 = unpackAttributes(container);
ListBuffer<Attribute.Compound> compounds = ListBuffer.lb();
- for (Attribute a : contained0)
- if (a instanceof Attribute.Compound)
- compounds = compounds.append((Attribute.Compound)a);
- Attribute.Compound[] contained = compounds.toArray(new Attribute.Compound[0]);
+ if (contained0 != null) {
+ for (Attribute a : contained0)
+ if (a instanceof Attribute.Compound)
+ compounds = compounds.append((Attribute.Compound)a);
+ }
+ Attribute.Compound[] contained = compounds.toArray(new Attribute.Compound[compounds.size()]);
int size = (direct == null ? 0 : 1) + contained.length;
@SuppressWarnings("unchecked") // annoType is the Class for A
@@ -298,35 +303,38 @@
}
// So we have a containing type
- String name = annoType.getName();
String annoTypeName = annoType.getSimpleName();
String containerTypeName = containerType.getSimpleName();
int directIndex = -1, containerIndex = -1;
Attribute.Compound direct = null, container = null;
- Attribute.Compound[] rawAttributes = annotated.getAnnotationMirrors().toArray(new Attribute.Compound[0]);
-
- // Find directly present annotations
- for (int i = 0; i < rawAttributes.length; i++) {
- if (annoTypeName.equals(rawAttributes[i].type.tsym.flatName().toString())) {
- directIndex = i;
- direct = rawAttributes[i];
+ // Find directly (explicit or implicit) present annotations
+ int index = -1;
+ for (List<? extends Attribute.Compound> list = annotated.getAnnotationMirrors();
+ !list.isEmpty();
+ list = list.tail) {
+ Attribute.Compound attribute = list.head;
+ index++;
+ if (attribute.type.tsym.flatName().contentEquals(annoTypeName)) {
+ directIndex = index;
+ direct = attribute;
} else if(containerTypeName != null &&
- containerTypeName.equals(rawAttributes[i].type.tsym.flatName().toString())) {
- containerIndex = i;
- container = rawAttributes[i];
+ attribute.type.tsym.flatName().contentEquals(containerTypeName)) {
+ containerIndex = index;
+ container = attribute;
}
}
// Pack them in an array
- Attribute[] contained0 = new Attribute[0];
+ Attribute[] contained0 = null;
if (container != null)
contained0 = unpackAttributes(container);
ListBuffer<Attribute.Compound> compounds = ListBuffer.lb();
- for (Attribute a : contained0) {
- if (a instanceof Attribute.Compound)
- compounds = compounds.append((Attribute.Compound)a);
+ if (contained0 != null) {
+ for (Attribute a : contained0)
+ if (a instanceof Attribute.Compound)
+ compounds = compounds.append((Attribute.Compound)a);
}
- Attribute.Compound[] contained = compounds.toArray(new Attribute.Compound[0]);
+ Attribute.Compound[] contained = compounds.toArray(new Attribute.Compound[compounds.size()]);
int size = (direct == null ? 0 : 1) + contained.length;
@SuppressWarnings("unchecked") // annoType is the Class for A
--- a/langtools/test/tools/javac/processing/model/element/repeatingAnnotations/MixRepeatableAndOfficialContainerInheritedA1Test.java Wed Jul 24 17:35:42 2013 -0700
+++ b/langtools/test/tools/javac/processing/model/element/repeatingAnnotations/MixRepeatableAndOfficialContainerInheritedA1Test.java Thu Jul 25 11:02:27 2013 +0200
@@ -23,12 +23,11 @@
/*
* @test
- * @bug 8004822
+ * @bug 8004822 8007961
* @author mnunez
* @summary Language model api test basics for repeating annotations
* @library /tools/javac/lib
* @library supportingAnnotations
- * @ignore 8013407: test failures for repeating annotations
* @build JavacTestingAbstractProcessor ElementRepAnnoTester
* @compile -processor ElementRepAnnoTester -proc:only
* MixRepeatableAndOfficialContainerInheritedA1Test.java
--- a/langtools/test/tools/javac/processing/model/element/repeatingAnnotations/MixRepeatableAndOfficialContainerInheritedB1Test.java Wed Jul 24 17:35:42 2013 -0700
+++ b/langtools/test/tools/javac/processing/model/element/repeatingAnnotations/MixRepeatableAndOfficialContainerInheritedB1Test.java Thu Jul 25 11:02:27 2013 +0200
@@ -23,12 +23,11 @@
/*
* @test
- * @bug 8004822
+ * @bug 8004822 8007961
* @author mnunez
* @summary Language model api test basics for repeating annotations
* @library /tools/javac/lib
* @library supportingAnnotations
- * @ignore 8013407: test failures for repeating annotations
* @build JavacTestingAbstractProcessor ElementRepAnnoTester
* @compile -processor ElementRepAnnoTester -proc:only
* MixRepeatableAndOfficialContainerInheritedB1Test.java
--- a/langtools/test/tools/javac/processing/model/element/repeatingAnnotations/MixRepeatableAndOfficialContainerInheritedB2Test.java Wed Jul 24 17:35:42 2013 -0700
+++ b/langtools/test/tools/javac/processing/model/element/repeatingAnnotations/MixRepeatableAndOfficialContainerInheritedB2Test.java Thu Jul 25 11:02:27 2013 +0200
@@ -23,12 +23,11 @@
/*
* @test
- * @bug 8004822
+ * @bug 8004822 8007961
* @author mnunez
* @summary Language model api test basics for repeating annotations
* @library /tools/javac/lib
* @library supportingAnnotations
- * @ignore 8013407: test failures for repeating annotations
* @build JavacTestingAbstractProcessor ElementRepAnnoTester
* @compile -processor ElementRepAnnoTester -proc:only
* MixRepeatableAndOfficialContainerInheritedB2Test.java
--- a/langtools/test/tools/javac/processing/model/element/repeatingAnnotations/RepeatableOverrideATest.java Wed Jul 24 17:35:42 2013 -0700
+++ b/langtools/test/tools/javac/processing/model/element/repeatingAnnotations/RepeatableOverrideATest.java Thu Jul 25 11:02:27 2013 +0200
@@ -23,12 +23,11 @@
/*
* @test
- * @bug 8004822
+ * @bug 8004822 8007961
* @author mnunez
* @summary Language model api test basics for repeating annotations
* @library /tools/javac/lib
* @library supportingAnnotations
- * @ignore 8013407: test failures for repeating annotations
* @build JavacTestingAbstractProcessor ElementRepAnnoTester
* @compile -processor ElementRepAnnoTester -proc:only RepeatableOverrideATest.java
*/
--- a/langtools/test/tools/javac/processing/model/element/repeatingAnnotations/RepeatableOverrideBTest.java Wed Jul 24 17:35:42 2013 -0700
+++ b/langtools/test/tools/javac/processing/model/element/repeatingAnnotations/RepeatableOverrideBTest.java Thu Jul 25 11:02:27 2013 +0200
@@ -23,12 +23,11 @@
/*
* @test
- * @bug 8004822
+ * @bug 8004822 8007961
* @author mnunez
* @summary Language model api test basics for repeating annotations
* @library /tools/javac/lib
* @library supportingAnnotations
- * @ignore 8013407: test failures for repeating annotations
* @build JavacTestingAbstractProcessor ElementRepAnnoTester
* @compile -processor ElementRepAnnoTester -proc:only RepeatableOverrideBTest.java
*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/processing/model/inheritedByType/EnsureOrder.java Thu Jul 25 11:02:27 2013 +0200
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @summary test that order is respected when inheriting both legacy container and single anno
+ * @bug 8007961
+ * @library /tools/javac/lib
+ * @build JavacTestingAbstractProcessor EnsureOrder
+ * @compile -processor EnsureOrder -proc:only EnsureOrder.java
+ */
+
+import java.util.Set;
+import java.lang.annotation.*;
+import javax.annotation.processing.*;
+import javax.lang.model.SourceVersion;
+import static javax.lang.model.SourceVersion.*;
+import javax.lang.model.element.*;
+import javax.lang.model.util.*;
+import static javax.lang.model.util.ElementFilter.*;
+import static javax.tools.Diagnostic.Kind.*;
+import static javax.tools.StandardLocation.*;
+import com.sun.tools.javac.util.Assert;
+
+@Target({ElementType.TYPE_PARAMETER, ElementType.TYPE})
+@Inherited
+@Retention(RetentionPolicy.RUNTIME)
+@Repeatable(Foos.class)
+@interface Foo {
+ int value();
+}
+
+@Target({ElementType.TYPE_PARAMETER, ElementType.TYPE})
+@Inherited
+@Retention(RetentionPolicy.RUNTIME)
+@interface Foos {
+ Foo[] value();
+}
+
+@Foos({@Foo(0), @Foo(1)}) @Foo(2)
+class Base {}
+
+class Sub extends Base {}
+
+public class EnsureOrder<@Foos({@Foo(0), @Foo(1)}) @Foo(2)T> extends JavacTestingAbstractProcessor {
+ public boolean process(Set<? extends TypeElement> annotations,
+ RoundEnvironment roundEnv) {
+ if (!roundEnv.processingOver()) {
+ int hasRun = 0;
+ for (Element element : roundEnv.getRootElements()) {
+ Name elemName = element.getSimpleName();
+ if (elemName.contentEquals("Base")) {
+ hasRun++;
+ Foo[] foos = element.getAnnotationsByType(Foo.class);
+ Assert.check(foos.length == 3);
+ Assert.check(foos[0].value() == 0);
+ Assert.check(foos[1].value() == 1);
+ Assert.check(foos[2].value() == 2);
+ }
+ if (elemName.contentEquals("Sub")) {
+ hasRun++;
+ Foo[] foos = element.getAnnotationsByType(Foo.class);
+ Assert.check(foos.length == 3);
+ Assert.check(foos[0].value() == 0);
+ Assert.check(foos[1].value() == 1);
+ Assert.check(foos[2].value() == 2);
+ }
+ if (elemName.contentEquals("EnsureOrder")) {
+ for (TypeParameterElement t : ((TypeElement)element).getTypeParameters()) {
+ if (t.getSimpleName().contentEquals("T")) {
+ hasRun++;
+ Foo[] foos = t.getAnnotationsByType(Foo.class);
+ Assert.check(foos.length == 3);
+ Assert.check(foos[0].value() == 0);
+ Assert.check(foos[1].value() == 1);
+ Assert.check(foos[2].value() == 2);
+ }
+ }
+ }
+ }
+ if (hasRun != 3)
+ throw new RuntimeException("Couldn't find elements");
+ }
+ return true;
+ }
+}