8044411: Implement classfile tests for RuntimeAnnotations and RuntimeParameterAnnotations attribute.
Reviewed-by: jjg, shurailine, anazarov
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/classfiles/attributes/annotations/AnnotationsTestBase.java Fri Jul 10 12:42:00 2015 +0300
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2015, 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.
+ */
+
+import com.sun.tools.classfile.Attribute;
+import com.sun.tools.classfile.ConstantPoolException;
+import com.sun.tools.classfile.Descriptor;
+
+import javax.tools.JavaFileObject;
+import java.io.IOException;
+import java.lang.annotation.RetentionPolicy;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.*;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+public abstract class AnnotationsTestBase extends TestResult {
+
+ /**
+ * Element values which are used in generation of annotations.
+ */
+ private static final TestAnnotationInfo.Pair[] elementValues = {
+ new TestAnnotationInfo.Pair("booleanValue", new TestAnnotationInfo.TestBooleanElementValue(true)),
+ new TestAnnotationInfo.Pair("byteValue", new TestAnnotationInfo.TestIntegerElementValue('B', 83)),
+ new TestAnnotationInfo.Pair("charValue", new TestAnnotationInfo.TestCharElementValue('H')),
+ new TestAnnotationInfo.Pair("shortValue", new TestAnnotationInfo.TestIntegerElementValue('S', 14)),
+ new TestAnnotationInfo.Pair("intValue", new TestAnnotationInfo.TestIntegerElementValue('I', 18)),
+ new TestAnnotationInfo.Pair("longValue", new TestAnnotationInfo.TestLongElementValue(14)),
+ new TestAnnotationInfo.Pair("floatValue", new TestAnnotationInfo.TestFloatElementValue(-1)),
+ new TestAnnotationInfo.Pair("doubleValue", new TestAnnotationInfo.TestDoubleElementValue(-83)),
+ new TestAnnotationInfo.Pair("stringValue", new TestAnnotationInfo.TestStringElementValue("///")),
+ new TestAnnotationInfo.Pair("arrayValue1", new TestAnnotationInfo.TestArrayElementValue(
+ new TestAnnotationInfo.TestIntegerElementValue('I', 1),
+ new TestAnnotationInfo.TestIntegerElementValue('I', 4),
+ new TestAnnotationInfo.TestIntegerElementValue('I', 8),
+ new TestAnnotationInfo.TestIntegerElementValue('I', 3))),
+ new TestAnnotationInfo.Pair("arrayValue2", new TestAnnotationInfo.TestArrayElementValue(
+ new TestAnnotationInfo.TestStringElementValue("AAA"),
+ new TestAnnotationInfo.TestStringElementValue("BBB"))),
+ new TestAnnotationInfo.Pair("enumValue", new TestAnnotationInfo.TestEnumElementValue("EnumValue", "VALUE2")),
+ new TestAnnotationInfo.Pair("classValue1", new TestAnnotationInfo.TestClassElementValue("void.class")),
+ new TestAnnotationInfo.Pair("classValue2", new TestAnnotationInfo.TestClassElementValue("Character.class")),
+ new TestAnnotationInfo.Pair("annoValue", new TestAnnotationInfo.TestAnnotationElementValue("AnnotationValue",
+ new TestAnnotationInfo("AnnotationValue", RetentionPolicy.CLASS,
+ new TestAnnotationInfo.Pair("stringValue",
+ new TestAnnotationInfo.TestStringElementValue("StringValue1"))))),
+ new TestAnnotationInfo.Pair("annoArrayValue", new TestAnnotationInfo.TestArrayElementValue(
+ new TestAnnotationInfo.TestAnnotationElementValue("AnnotationValue",
+ new TestAnnotationInfo("AnnotationValue", RetentionPolicy.CLASS,
+ new TestAnnotationInfo.Pair("stringValue",
+ new TestAnnotationInfo.TestStringElementValue("StringValue1")))),
+ new TestAnnotationInfo.TestAnnotationElementValue("AnnotationValue",
+ new TestAnnotationInfo("AnnotationValue", RetentionPolicy.CLASS,
+ new TestAnnotationInfo.Pair("stringValue",
+ new TestAnnotationInfo.TestStringElementValue("StringValue1"))))))
+ };
+
+ /**
+ * Masks which are used in generation of annotations.
+ * E.g. mask 0 corresponds to an annotation without element values.
+ */
+ private static final int[] elementValuesCombinations;
+
+ static {
+ List<Integer> combinations = new ArrayList<>();
+ combinations.add(0);
+ for (int i = 0; i < elementValues.length; ++i) {
+ combinations.add(1 << i);
+ }
+ // pairs int value and another value
+ for (int i = 0; i < elementValues.length; ++i) {
+ combinations.add((1 << 5) | (1 << i));
+ }
+ combinations.add((1 << elementValues.length) - 1);
+ elementValuesCombinations = combinations.stream().mapToInt(Integer::intValue).toArray();
+ }
+
+ /**
+ * Method generates a list of test cases.
+ * Method is called in the method {@code call()}.
+ *
+ * @return a list of test cases
+ */
+ public abstract List<TestCase> generateTestCases();
+
+ public abstract void test(TestCase testCase, Map<String, ? extends JavaFileObject> classes)
+ throws IOException, ConstantPoolException, Descriptor.InvalidDescriptor;
+
+ /**
+ * The method is used to create a repeatable annotation.
+ */
+ private TestAnnotationInfo createSomeAnnotation(String annotationName) {
+ return new TestAnnotationInfo(annotationName, getRetentionPolicy(annotationName),
+ new TestAnnotationInfo.Pair("booleanValue",
+ new TestAnnotationInfo.TestBooleanElementValue(true)),
+ new TestAnnotationInfo.Pair("intValue",
+ new TestAnnotationInfo.TestIntegerElementValue('I', 1)),
+ new TestAnnotationInfo.Pair("enumValue",
+ new TestAnnotationInfo.TestEnumElementValue("EnumValue", "VALUE1")));
+ }
+
+ private TestAnnotationInfo getAnnotationByMask(String annotationName, int mask) {
+ List<TestAnnotationInfo.Pair> pairs = new ArrayList<>();
+ for (int i = 0; i < elementValues.length; ++i) {
+ if ((mask & (1 << i)) != 0) {
+ pairs.add(elementValues[i]);
+ }
+ }
+ return new TestAnnotationInfo(
+ annotationName,
+ getRetentionPolicy(annotationName),
+ pairs.toArray(new TestAnnotationInfo.Pair[pairs.size()]));
+ }
+
+ /**
+ * Class represents annotations which will be applied to one method.
+ */
+ public static class TestAnnotationInfos {
+ public final List<TestAnnotationInfo> annotations;
+
+ public TestAnnotationInfos(List<TestAnnotationInfo> a) {
+ this.annotations = a;
+ }
+
+ public void annotate(TestCase.TestMemberInfo memberInfo) {
+ annotations.forEach(memberInfo::addAnnotation);
+ }
+ }
+
+ /**
+ * Convenience method to group test cases.
+ * Increases speed of tests.
+ */
+ public List<List<TestAnnotationInfos>> groupAnnotations(List<TestAnnotationInfos> annotations) {
+ List<List<TestAnnotationInfos>> groupedAnnotations = new ArrayList<>();
+ int size = 32;
+ List<TestAnnotationInfos> current = null;
+ for (TestAnnotationInfos infos : annotations) {
+ if (current == null || current.size() == size) {
+ current = new ArrayList<>();
+ groupedAnnotations.add(current);
+ }
+ current.add(infos);
+ }
+ return groupedAnnotations;
+ }
+
+ public List<TestAnnotationInfos> getAllCombinationsOfAnnotations() {
+ List<TestAnnotationInfos> combinations = new ArrayList<>();
+ for (Annotations annotationName1 : Annotations.values()) {
+ List<TestAnnotationInfo> list = IntStream.of(elementValuesCombinations)
+ .mapToObj(e -> getAnnotationByMask(annotationName1.getAnnotationName(), e))
+ .collect(Collectors.toList());
+ // add cases with a single annotation
+ combinations.addAll(list.stream()
+ .map(Collections::singletonList)
+ .map(TestAnnotationInfos::new)
+ .collect(Collectors.toList()));
+
+ // add cases with a repeatable annotation
+ for (Annotations annotationName2 : Annotations.values()) {
+ if (annotationName1 == annotationName2 && !annotationName1.isRepeatable()) {
+ continue;
+ }
+ TestAnnotationInfo annotation2 = createSomeAnnotation(annotationName2.getAnnotationName());
+ for (TestAnnotationInfo annotation1 : list) {
+ List<TestAnnotationInfo> list1 = new ArrayList<>();
+ Collections.addAll(list1, annotation1, annotation2);
+ combinations.add(new TestAnnotationInfos(list1));
+ }
+ }
+ }
+ return combinations;
+ }
+
+ protected RetentionPolicy getRetentionPolicy(String name) {
+ if (name.contains("Visible")) {
+ return RetentionPolicy.RUNTIME;
+ } else if (name.contains("Invisible")) {
+ return RetentionPolicy.CLASS;
+ }
+ throw new IllegalArgumentException(name);
+ }
+
+ protected long countNumberOfAttributes(Attribute[] attrs,
+ Class<? extends Attribute> clazz) {
+ return Stream.of(attrs)
+ .filter(clazz::isInstance)
+ .count();
+ }
+
+ public void test() throws TestFailedException {
+ try {
+ List<TestCase> testCases = generateTestCases();
+ for (int i = 0; i < testCases.size(); ++i) {
+ TestCase testCase = testCases.get(i);
+ String source = testCase.generateSource();
+ Path sourceFile = Paths.get(getClass().getSimpleName() + i + ".java");
+ addTestCase(sourceFile.toAbsolutePath().toString());
+ writeToFile(sourceFile, source);
+ echo("Testing: " + sourceFile.toString());
+ try {
+ test(testCase, compile(source).getClasses());
+ } catch (Exception e) {
+ addFailure(e);
+ }
+ }
+ } catch (RuntimeException | IOException e) {
+ addFailure(e);
+ } finally {
+ checkStatus();
+ }
+ }
+
+ public enum Annotations {
+ RUNTIME_INVISIBLE_REPEATABLE("RuntimeInvisibleRepeatable", true),
+ RUNTIME_INVISIBLE_NOT_REPEATABLE("RuntimeInvisibleNotRepeatable", false),
+ RUNTIME_VISIBLE_REPEATABLE("RuntimeVisibleRepeatable", true),
+ RUNTIME_VISIBLE_NOT_REPEATABLE("RuntimeVisibleNotRepeatable", false);
+
+ private final String annotationName;
+ private final boolean isRepeatable;
+
+ Annotations(String annotationName, boolean isRepeatable) {
+ this.annotationName = annotationName;
+ this.isRepeatable = isRepeatable;
+ }
+
+ public String getAnnotationName() {
+ return annotationName;
+ }
+
+ public boolean isRepeatable() {
+ return isRepeatable;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/classfiles/attributes/annotations/ClassType.java Fri Jul 10 12:42:00 2015 +0300
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2015, 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.
+ */
+
+import java.util.Collection;
+import java.util.stream.Collectors;
+
+public enum ClassType {
+ CLASS("class"),
+ INTERFACE("interface") {
+ @Override
+ public String methodToString(TestCase.TestMethodInfo method) {
+ String modifiers = method.mods.stream()
+ .collect(Collectors.joining(" "));
+ boolean hasBody = modifiers.contains("static") || modifiers.contains("default");
+ String parameters = method.parameters.stream()
+ .map(TestCase.TestMemberInfo::generateSource)
+ .collect(Collectors.joining(", "));
+ return String.format("%s %s %s(%s) %s",
+ method.indention() + modifiers,
+ "int",
+ method.getName(),
+ parameters,
+ hasBody ? "{return 0;}" : ";");
+ }
+ },
+ ANNOTATION("@interface") {
+ @Override
+ public String methodToString(TestCase.TestMethodInfo method) {
+ String modifiers = method.mods.stream()
+ .collect(Collectors.joining(" "));
+ return String.format("%s %s %s() %s",
+ method.indention() + modifiers,
+ "int",
+ method.getName(),
+ ";");
+ }
+ },
+ ENUM("enum") {
+ @Override
+ public String fieldToString(TestCase.TestFieldInfo field) {
+ return field.indention() + field.name;
+ }
+
+ @Override
+ public String collectFields(Collection<TestCase.TestFieldInfo> fields) {
+ return fields.stream()
+ .map(TestCase.TestMemberInfo::generateSource)
+ .collect(Collectors.joining(",\n")) + ";\n";
+ }
+ };
+
+ private final String classType;
+
+ ClassType(String classType) {
+ this.classType = classType;
+ }
+
+ private String collectSrc(Collection<? extends TestCase.TestMemberInfo> members) {
+ String src = members.stream()
+ .map(TestCase.TestMemberInfo::generateSource)
+ .collect(Collectors.joining("\n"));
+ return src.trim().isEmpty() ? "" : src + "\n\n";
+ }
+
+ public String collectInnerClasses(Collection<TestCase.TestClassInfo> innerClasses) {
+ return collectSrc(innerClasses);
+ }
+
+ public String collectFields(Collection<TestCase.TestFieldInfo> fields) {
+ return collectSrc(fields);
+ }
+
+ public String collectMethods(Collection<TestCase.TestMethodInfo> methods) {
+ return collectSrc(methods);
+ }
+
+ public String methodToString(TestCase.TestMethodInfo method) {
+ String modifiers = method.mods.stream()
+ .collect(Collectors.joining(" "));
+ String parameters = method.parameters.stream()
+ .map(TestCase.TestMemberInfo::generateSource)
+ .collect(Collectors.joining(", "));
+ String localClasses = collectInnerClasses(method.localClasses.values());
+ String methodBody = modifiers.contains("abstract") ? ";" :
+ String.format("{%n%s%s%n%s}",
+ localClasses,
+ method.isConstructor
+ ? ""
+ : method.indention() + "return false;",
+ method.indention());
+ return String.format("%s %s %s(%s) %s",
+ method.indention() + modifiers,
+ method.isConstructor ? "" : "boolean",
+ method.getName(),
+ parameters,
+ methodBody);
+ }
+
+ public String fieldToString(TestCase.TestFieldInfo field) {
+ String modifiers = field.mods.stream()
+ .collect(Collectors.joining(" "));
+ return String.format("%s int %s = 0;",
+ field.indention() + modifiers,
+ field.name);
+ }
+
+ public String getDescription() {
+ return classType;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/classfiles/attributes/annotations/README.txt Fri Jul 10 12:42:00 2015 +0300
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2015, 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.
+ */
+
+== Description of tests for RuntimeVisibleAnnotations, RuntimeInVisibleAnnotations
+RuntimeVisibleParameterAnnotations and RuntimeInvisibleParameterAnnotations attributes ==
+
+* AnnotationsTestBase class is a base class for the Annotations attribute tests.
+It contains some convenience methods which might be used in derived classes.
+
+* ClassType is a enum which is used for convenience code generation (see TestCase).
+
+* TestCase is a class which represent a test case. TestCase contains TestClassInfo,
+which represents a class, TestMethodInfo, which represents a method, TestFieldInfo,
+which represents a field, and TestParameterInfo, which represents a method's parameter.
+The class is used as test case builder. For example, the following code creates
+the top-level class Test with method classMethod() and local class Local.
+Each program member is annotated by some annotation which is an instance of
+TestAnnotationInfo (see TestAnnotationInfo):
+
+ TestCase test = new TestCase(ClassType.CLASS, "Test", "public");
+ test.clazz.addAnnotation(annotations);
+ TestCase.TestMethodInfo classMethod = test.clazz.addMethod("classMethod()");
+ classMethod.addAnnotation(annotation);
+ TestCase.TestClassInfo localClassInClassMethod = classMethod.addLocalClass("Local");
+ localClassInClassMethod.addAnnotation(annotations);
+
+Let "annotations" be a list of annotations A, B(i = 2). Thus, a test will generate the
+following code:
+
+ @A
+ @B(i = 2)
+ public class Test {
+ @A
+ @B(i = 2)
+ void classMethod() {
+ @A
+ @B(i = 2)
+ class Local {
+ }
+ }
+ }
+
+Thus, TestCase contains information about structure of classes and golden data
+about annotations. Thereafter, sources can be generated from this class representation
+by calling method generateSource(). Enum ClassType is used to handle "class type specific"
+code generation. For example, not-abstract method in a class always has body,
+while not-static and not-default method in an interface does not.
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/classfiles/attributes/annotations/RuntimeAnnotationsForGenericMethodTest.java Fri Jul 10 12:42:00 2015 +0300
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2015, 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
+ * @bug 8044411
+ * @summary Tests the RuntimeVisibleAnnotations/RuntimeInvisibleAnnotations attribute.
+ * Checks that the attribute is generated for bridge method.
+ * @library /tools/lib /tools/javac/lib ../lib
+ * @build WorkAnnotations TestBase TestResult InMemoryFileManager ToolBox
+ * @build TestCase ClassType TestAnnotationInfo
+ * @build RuntimeAnnotationsForGenericMethodTest AnnotationsTestBase RuntimeAnnotationsTestBase
+ * @run main RuntimeAnnotationsForGenericMethodTest
+ */
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * RuntimeAnnotationsGenericMethodTest is a test which check that
+ * RuntimeVisibleAnnotationsAttribute and RuntimeInvisibleAnnotationsAttribute
+ * are generated for both generic and appropriate bridge methods.
+ * All possible combinations of retention policies are tested.
+ *
+ * The test generates class which looks as follows:
+ *
+ * public class Test extends java.util.ArrayList<Integer> {
+ * here some annotations
+ * public boolean add(java.lang.Integer) {
+ * return false;
+ * }
+ * }
+ *
+ * Thereafter, various of combinations of annotations are applied
+ * to the add, the source is compiled and the generated byte code is checked.
+ *
+ * See README.txt for more information.
+ */
+public class RuntimeAnnotationsForGenericMethodTest extends RuntimeAnnotationsTestBase {
+
+ @Override
+ public List<TestCase> generateTestCases() {
+ List<TestCase> testCases = new ArrayList<>();
+ for (List<TestAnnotationInfos> groupedAnnotations : groupAnnotations(getAllCombinationsOfAnnotations())) {
+ TestCase testCase = new TestCase();
+ for (int i = 0; i < groupedAnnotations.size(); ++i) {
+ TestAnnotationInfos annotations = groupedAnnotations.get(i);
+ // generate: public class Test extends java.util.ArrayList<Integer>
+ TestCase.TestClassInfo clazz = testCase.addClassInfo("java.util.ArrayList<Integer>", ClassType.CLASS, "Test" + i);
+ TestCase.TestMethodInfo method = clazz.addMethodInfo("add(java.lang.Integer)", "public");
+ method.addParameter("Integer", "i");
+ annotations.annotate(method);
+ TestCase.TestMethodInfo synMethod = clazz.addMethodInfo("add(java.lang.Object)", true, "public");
+ annotations.annotate(synMethod);
+ }
+ testCases.add(testCase);
+ }
+ return testCases;
+ }
+
+ public static void main(String[] args) throws TestFailedException {
+ new RuntimeAnnotationsForGenericMethodTest().test();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/classfiles/attributes/annotations/RuntimeAnnotationsForInnerAnnotationTest.java Fri Jul 10 12:42:00 2015 +0300
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2015, 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
+ * @bug 8044411
+ * @summary Tests the RuntimeVisibleAnnotations/RuntimeInvisibleAnnotations attribute.
+ * @library /tools/lib /tools/javac/lib ../lib
+ * @build WorkAnnotations TestBase TestResult InMemoryFileManager ToolBox
+ * @build TestCase ClassType TestAnnotationInfo
+ * @build RuntimeAnnotationsForInnerAnnotationTest AnnotationsTestBase RuntimeAnnotationsTestBase
+ * @run main RuntimeAnnotationsForInnerAnnotationTest
+ */
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * The test checks that RuntimeVisibleAnnotationsAttribute and RuntimeInvisibleAnnotationsAttribute
+ * are generated properly for inner classes annotations, for methods, for fields
+ *
+ * The test checks both single and repeatable annotations. In addition, all possible combinations
+ * of retention policies are tested. The test generates source code, compiles it and checks the byte code.
+ *
+ * See README.txt for more information.
+ */
+public class RuntimeAnnotationsForInnerAnnotationTest extends RuntimeAnnotationsTestBase {
+ @Override
+ public List<TestCase> generateTestCases() {
+ List<TestCase> testCases = new ArrayList<>();
+ for (List<TestAnnotationInfos> groupedAnnotations : groupAnnotations(getAllCombinationsOfAnnotations())) {
+ for (ClassType outerClassType : ClassType.values()) {
+ TestCase test = new TestCase();
+ TestCase.TestClassInfo clazz = test.addClassInfo(outerClassType, "Test");
+ for (int i = 0; i < groupedAnnotations.size(); ++i) {
+ TestCase.TestClassInfo anno = clazz.addInnerClassInfo(ClassType.ANNOTATION, "InnerAnnotation" + i);
+ TestAnnotationInfos annotations = groupedAnnotations.get(i);
+ annotations.annotate(anno);
+
+ TestCase.TestMethodInfo annoMethod = anno.addMethodInfo("interMethod" + i + "()");
+ annotations.annotate(annoMethod);
+
+ TestCase.TestFieldInfo annoField = anno.addFieldInfo("annoField" + i);
+ annotations.annotate(annoField);
+ }
+ testCases.add(test);
+ }
+ }
+ return testCases;
+ }
+
+ public static void main(String[] args) throws TestFailedException {
+ new RuntimeAnnotationsForInnerAnnotationTest().test();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/classfiles/attributes/annotations/RuntimeAnnotationsForInnerClassTest.java Fri Jul 10 12:42:00 2015 +0300
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2015, 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
+ * @bug 8044411
+ * @summary Tests the RuntimeVisibleAnnotations/RuntimeInvisibleAnnotations attribute.
+ * @library /tools/lib /tools/javac/lib ../lib
+ * @build WorkAnnotations TestBase TestResult InMemoryFileManager ToolBox
+ * @build TestCase ClassType TestAnnotationInfo
+ * @build RuntimeAnnotationsForInnerClassTest AnnotationsTestBase RuntimeAnnotationsTestBase
+ * @run main RuntimeAnnotationsForInnerClassTest
+ */
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * The test checks that RuntimeVisibleAnnotationsAttribute and RuntimeInvisibleAnnotationsAttribute
+ * are generated properly for inner classes, for constructors, for methods, for fields.
+ * The test checks both single and repeatable annotations. In addition, all possible combinations
+ * of retention policies are tested.
+ *
+ * The test generates source code, compiles it and checks the byte code.
+ *
+ * See README.txt for more information.
+ */
+public class RuntimeAnnotationsForInnerClassTest extends RuntimeAnnotationsTestBase {
+ @Override
+ public List<TestCase> generateTestCases() {
+ List<TestCase> testCases = new ArrayList<>();
+ for (List<TestAnnotationInfos> groupedAnnotations : groupAnnotations(getAllCombinationsOfAnnotations())) {
+ for (ClassType outerClassType : ClassType.values()) {
+ TestCase test = new TestCase();
+ TestCase.TestClassInfo outerClazz = test.addClassInfo(outerClassType, "Test");
+ for (int i = 0; i < groupedAnnotations.size(); ++i) {
+ TestAnnotationInfos annotations = groupedAnnotations.get(i);
+ TestCase.TestClassInfo clazz = outerClazz.addInnerClassInfo(ClassType.CLASS, "InnerClass" + i, "static");
+ annotations.annotate(clazz);
+
+ TestCase.TestMethodInfo constructor = clazz.addMethodInfo("<init>()");
+ annotations.annotate(constructor);
+
+ TestCase.TestClassInfo localClassInConstructor = constructor.addLocalClassInfo("Local1" + i);
+ annotations.annotate(localClassInConstructor);
+
+ TestCase.TestMethodInfo innerClazzMethod = clazz.addMethodInfo("innerClassMethod" + i + "()");
+ annotations.annotate(innerClazzMethod);
+
+ TestCase.TestClassInfo localClassInClassMethod = innerClazzMethod.addLocalClassInfo("Local2" + i);
+ annotations.annotate(localClassInClassMethod);
+
+ TestCase.TestMethodInfo innerStaticClazzMethod = clazz.addMethodInfo("innerStaticClassMethod" + i + "()", "static");
+ annotations.annotate(innerStaticClazzMethod);
+
+ TestCase.TestClassInfo localClassInStaticMethod = innerStaticClazzMethod.addLocalClassInfo("Local3" + i);
+ annotations.annotate(localClassInStaticMethod);
+ }
+ testCases.add(test);
+ }
+ }
+ return testCases;
+ }
+
+ public static void main(String[] args) throws TestFailedException {
+ new RuntimeAnnotationsForInnerClassTest().test();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/classfiles/attributes/annotations/RuntimeAnnotationsForInnerEnumTest.java Fri Jul 10 12:42:00 2015 +0300
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2015, 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
+ * @bug 8044411
+ * @summary Tests the RuntimeVisibleAnnotations/RuntimeInvisibleAnnotations attribute.
+ * @library /tools/lib /tools/javac/lib ../lib
+ * @build WorkAnnotations TestBase TestResult InMemoryFileManager ToolBox
+ * @build TestCase ClassType TestAnnotationInfo
+ * @build RuntimeAnnotationsForInnerEnumTest AnnotationsTestBase RuntimeAnnotationsTestBase
+ * @run main RuntimeAnnotationsForInnerEnumTest
+ */
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * The test checks that RuntimeVisibleAnnotationsAttribute and RuntimeInvisibleAnnotationsAttribute
+ * are generated properly for inner classes enums, for constructors, for methods,
+ * for fields (enum, class, annotation, interface). The test checks both
+ * single and repeatable annotations. In addition, all possible combinations
+ * of retention policies are tested.
+ *
+ * The test generates source code, compiles it and checks the byte code.
+ *
+ * See README.txt for more information.
+ */
+public class RuntimeAnnotationsForInnerEnumTest extends RuntimeAnnotationsTestBase {
+ @Override
+ public List<TestCase> generateTestCases() {
+ List<TestCase> testCases = new ArrayList<>();
+ for (List<TestAnnotationInfos> groupedAnnotations : groupAnnotations(getAllCombinationsOfAnnotations())) {
+ for (ClassType outerClassType : ClassType.values()) {
+ TestCase test = new TestCase();
+ TestCase.TestClassInfo outerClassInfo = test.addClassInfo(outerClassType, "Test");
+ for (int i = 0; i < groupedAnnotations.size(); i++) {
+ TestAnnotationInfos annotations = groupedAnnotations.get(i);
+ TestCase.TestClassInfo clazz = outerClassInfo.addInnerClassInfo(ClassType.ENUM, "Enum" + i);
+ annotations.annotate(clazz);
+
+ TestCase.TestMethodInfo innerClazzMethod = clazz.addMethodInfo("innerClassMethod" + i + "()");
+ annotations.annotate(innerClazzMethod);
+
+ TestCase.TestClassInfo localClassInClassMethod = innerClazzMethod.addLocalClassInfo("Local1" + i);
+ annotations.annotate(localClassInClassMethod);
+
+ TestCase.TestMethodInfo innerStaticClazzMethod = clazz.addMethodInfo("innerStaticClassMethod" + i + "()", "static");
+ annotations.annotate(innerStaticClazzMethod);
+
+ TestCase.TestClassInfo localClassInStaticMethod = innerStaticClazzMethod.addLocalClassInfo("Local2" + i);
+ annotations.annotate(localClassInStaticMethod);
+
+ TestCase.TestFieldInfo valueA = clazz.addFieldInfo("A" + i);
+ annotations.annotate(valueA);
+
+ TestCase.TestFieldInfo valueB = clazz.addFieldInfo("B" + i);
+ annotations.annotate(valueB);
+ }
+ testCases.add(test);
+ }
+ }
+ return testCases;
+ }
+
+ public static void main(String[] args) throws TestFailedException {
+ new RuntimeAnnotationsForInnerEnumTest().test();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/classfiles/attributes/annotations/RuntimeAnnotationsForInnerInterfaceTest.java Fri Jul 10 12:42:00 2015 +0300
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2015, 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
+ * @bug 8044411
+ * @summary Tests the RuntimeVisibleAnnotations/RuntimeInvisibleAnnotations attribute.
+ * @library /tools/lib /tools/javac/lib ../lib
+ * @build WorkAnnotations TestBase TestResult InMemoryFileManager ToolBox
+ * @build TestCase ClassType TestAnnotationInfo
+ * @build RuntimeAnnotationsForInnerInterfaceTest AnnotationsTestBase RuntimeAnnotationsTestBase
+ * @run main RuntimeAnnotationsForInnerInterfaceTest
+ */
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * The test checks that RuntimeVisibleAnnotationsAttribute and RuntimeInvisibleAnnotationsAttribute
+ * are generated properly for inner interfaces, for methods, for fields. The test checks both
+ * single and repeatable annotations. In addition, all possible combinations
+ * of retention policies are tested.
+ *
+ * The test generates source code, compiles it and checks the byte code.
+ *
+ * See README.txt for more information.
+ */
+public class RuntimeAnnotationsForInnerInterfaceTest extends RuntimeAnnotationsTestBase {
+ @Override
+ public List<TestCase> generateTestCases() {
+ List<TestCase> testCases = new ArrayList<>();
+ for (List<TestAnnotationInfos> groupedAnnotations : groupAnnotations(getAllCombinationsOfAnnotations())) {
+ for (ClassType outerClassType : ClassType.values()) {
+ TestCase test = new TestCase();
+ TestCase.TestClassInfo outerClass = test.addClassInfo(outerClassType, "Test");
+ for (int i = 0; i < groupedAnnotations.size(); ++i) {
+ TestAnnotationInfos annotations = groupedAnnotations.get(i);
+ TestCase.TestClassInfo inter = outerClass.addInnerClassInfo(ClassType.INTERFACE, "InnerInterface" + i);
+ annotations.annotate(inter);
+
+ TestCase.TestFieldInfo interField = inter.addFieldInfo("interField" + i);
+ annotations.annotate(interField);
+
+ TestCase.TestMethodInfo interMethod = inter.addMethodInfo("interMethod" + i + "()");
+ annotations.annotate(interMethod);
+
+ TestCase.TestMethodInfo interStaticMethod = inter.addMethodInfo("interStaticMethod" + i + "()", "static");
+ annotations.annotate(interStaticMethod);
+
+ TestCase.TestClassInfo localClassInStaticMethod = interStaticMethod.addLocalClassInfo("Local1" + i);
+ annotations.annotate(localClassInStaticMethod);
+
+ TestCase.TestMethodInfo interDefaultMethod = inter.addMethodInfo("interDefaultMethod" + i + "()", "default");
+ annotations.annotate(interDefaultMethod);
+
+ TestCase.TestClassInfo localClassInDefaultMethod = interDefaultMethod.addLocalClassInfo("Local2" + i);
+ annotations.annotate(localClassInDefaultMethod);
+ }
+ testCases.add(test);
+ }
+ }
+ return testCases;
+ }
+
+ public static void main(String[] args) throws TestFailedException {
+ new RuntimeAnnotationsForInnerInterfaceTest().test();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/classfiles/attributes/annotations/RuntimeAnnotationsForTopLevelClassTest.java Fri Jul 10 12:42:00 2015 +0300
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2015, 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
+ * @bug 8044411
+ * @summary Tests the RuntimeVisibleAnnotations/RuntimeInvisibleAnnotations attribute.
+ * @library /tools/lib /tools/javac/lib ../lib
+ * @build WorkAnnotations TestBase TestResult InMemoryFileManager ToolBox
+ * @build TestCase ClassType TestAnnotationInfo
+ * @build RuntimeAnnotationsForTopLevelClassTest AnnotationsTestBase RuntimeAnnotationsTestBase
+ * @run main RuntimeAnnotationsForTopLevelClassTest
+ */
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * The test checks that RuntimeVisibleAnnotationsAttribute and RuntimeInvisibleAnnotationsAttribute
+ * are generated properly for top-level class (class, enum, annotation, interface),
+ * for constructors (in enum and in class), for methods (abstract methods, static and default methods in interface),
+ * for fields. The test checks both single and repeatable annotations.
+ * In addition, all possible combinations of retention policies are tested.
+ *
+ * The test generates source code, compiles it and checks the byte code.
+ *
+ * See README.txt for more information.
+ */
+public class RuntimeAnnotationsForTopLevelClassTest extends RuntimeAnnotationsTestBase {
+
+ @Override
+ public List<TestCase> generateTestCases() {
+ List<TestCase> testCases = new ArrayList<>();
+ for (List<TestAnnotationInfos> groupedAnnotations : groupAnnotations(getAllCombinationsOfAnnotations())) {
+ for (ClassType classType : ClassType.values()) {
+ TestCase test = new TestCase();
+ for (int i = 0; i < groupedAnnotations.size(); ++i) {
+ TestAnnotationInfos annotations = groupedAnnotations.get(i);
+ TestCase.TestClassInfo clazz = test.addClassInfo(classType, "Test" + i);
+ annotations.annotate(clazz);
+
+ if (classType != ClassType.ENUM) {
+ TestCase.TestMethodInfo constructor = clazz.addMethodInfo("<init>()");
+ annotations.annotate(constructor);
+
+ TestCase.TestClassInfo localClass = constructor.addLocalClassInfo("Local1" + i);
+ annotations.annotate(localClass);
+ }
+ if (classType != ClassType.ANNOTATION) {
+ TestCase.TestMethodInfo staticClassMethod = clazz.addMethodInfo("staticClassMethod" + i + "()", "static");
+ annotations.annotate(staticClassMethod);
+
+ TestCase.TestClassInfo localClassInStaticMethod = staticClassMethod.addLocalClassInfo("Local2" + i);
+ annotations.annotate(localClassInStaticMethod);
+ }
+ TestCase.TestMethodInfo classMethod = clazz.addMethodInfo("classMethod" + i + "()");
+ annotations.annotate(classMethod);
+
+ TestCase.TestClassInfo localClassInClassMethod = classMethod.addLocalClassInfo("Local3" + i);
+ annotations.annotate(localClassInClassMethod);
+
+ TestCase.TestFieldInfo field = clazz.addFieldInfo("field" + i);
+ annotations.annotate(field);
+
+ TestCase.TestFieldInfo staticField = clazz.addFieldInfo("staticField" + i, "static");
+ annotations.annotate(staticField);
+ }
+ testCases.add(test);
+ }
+ }
+ return testCases;
+ }
+
+ public static void main(String[] args) throws TestFailedException {
+ new RuntimeAnnotationsForTopLevelClassTest().test();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/classfiles/attributes/annotations/RuntimeAnnotationsTestBase.java Fri Jul 10 12:42:00 2015 +0300
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2015, 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.
+ */
+
+import com.sun.tools.classfile.*;
+
+import java.io.IOException;
+import java.lang.annotation.RetentionPolicy;
+import java.util.*;
+import java.util.function.Supplier;
+
+import javax.tools.JavaFileObject;
+
+public abstract class RuntimeAnnotationsTestBase extends AnnotationsTestBase {
+
+ @Override
+ public void test(TestCase testCase, Map<String, ? extends JavaFileObject> classes)
+ throws IOException, ConstantPoolException, Descriptor.InvalidDescriptor {
+ for (Map.Entry<String, ? extends JavaFileObject> entry : classes.entrySet()) {
+ String className = entry.getKey();
+ TestCase.TestClassInfo clazz = testCase.getTestClassInfo(className);
+ echo("Testing class : " + className);
+ ClassFile classFile = readClassFile(entry.getValue());
+
+ testAttributes(clazz, classFile, () -> classFile.attributes);
+
+ testMethods(clazz, classFile);
+
+ testFields(clazz, classFile);
+ }
+ }
+
+ private void testMethods(TestCase.TestClassInfo clazz, ClassFile classFile)
+ throws ConstantPoolException, Descriptor.InvalidDescriptor {
+ String className = clazz.getName();
+ Set<String> foundMethods = new HashSet<>();
+ for (Method method : classFile.methods) {
+ String methodName = method.getName(classFile.constant_pool) +
+ method.descriptor.getParameterTypes(classFile.constant_pool);
+ if (methodName.startsWith("<init>")) {
+ String constructorName = className.replaceAll(".*\\$", "");
+ methodName = methodName.replace("<init>", constructorName);
+ }
+ echo("Testing method : " + methodName);
+
+ TestCase.TestMethodInfo testMethod = clazz.getTestMethodInfo(methodName);
+ foundMethods.add(methodName);
+ if (testMethod == null) {
+ continue;
+ }
+ testAttributes(testMethod, classFile, () -> method.attributes);
+ }
+ checkContains(foundMethods, clazz.methods.keySet(), "Methods in class : " + className);
+ }
+
+ private void testFields(TestCase.TestClassInfo clazz, ClassFile classFile)
+ throws ConstantPoolException {
+ Set<String> foundFields = new HashSet<>();
+ for (Field field : classFile.fields) {
+ String fieldName = field.getName(classFile.constant_pool);
+ echo("Testing field : " + fieldName);
+
+ TestCase.TestFieldInfo testField = clazz.getTestFieldInfo(fieldName);
+ foundFields.add(fieldName);
+ if (testField == null) {
+ continue;
+ }
+ testAttributes(testField, classFile, () -> field.attributes);
+ }
+ checkContains(foundFields, clazz.fields.keySet(), "Fields in class : " + clazz.getName());
+ }
+
+ private void testAttributes(
+ TestCase.TestMemberInfo member,
+ ClassFile classFile,
+ Supplier<Attributes> attributes)
+ throws ConstantPoolException {
+ Map<String, Annotation> actualInvisible = collectAnnotations(
+ classFile,
+ member,
+ attributes.get(),
+ Attribute.RuntimeInvisibleAnnotations);
+ Map<String, Annotation> actualVisible = collectAnnotations(
+ classFile,
+ member,
+ attributes.get(),
+ Attribute.RuntimeVisibleAnnotations);
+
+ checkEquals(actualInvisible.keySet(),
+ member.getRuntimeInvisibleAnnotations(), "RuntimeInvisibleAnnotations");
+ checkEquals(actualVisible.keySet(),
+ member.getRuntimeVisibleAnnotations(), "RuntimeVisibleAnnotations");
+
+ for (TestAnnotationInfo expectedAnnotation : member.annotations.values()) {
+ RetentionPolicy policy = getRetentionPolicy(expectedAnnotation.annotationName);
+ if (policy == RetentionPolicy.SOURCE) {
+ continue;
+ }
+ printf("Testing: isVisible: %s %s%n", policy.toString(), expectedAnnotation.annotationName);
+ Annotation actualAnnotation =
+ (policy == RetentionPolicy.RUNTIME ? actualVisible : actualInvisible)
+ .get(expectedAnnotation.annotationName);
+ if (checkNotNull(actualAnnotation, "Annotation is found : "
+ + expectedAnnotation.annotationName)) {
+ expectedAnnotation.testAnnotation(this, classFile, actualAnnotation);
+ }
+ }
+ }
+
+ private Map<String, Annotation> collectAnnotations(
+ ClassFile classFile,
+ TestCase.TestMemberInfo member,
+ Attributes attributes,
+ String attribute) throws ConstantPoolException {
+
+ RuntimeAnnotations_attribute attr = (RuntimeAnnotations_attribute) attributes.get(attribute);
+ Map<String, Annotation> actualAnnotations = new HashMap<>();
+ RetentionPolicy policy = getRetentionPolicy(attribute);
+ if (member.isAnnotated(policy)) {
+ if (!checkNotNull(attr, String.format("%s should be not null value", attribute))) {
+ // test case failed, stop checking
+ return actualAnnotations;
+ }
+ for (Annotation ann : attr.annotations) {
+ String name = classFile.constant_pool.getUTF8Value(ann.type_index);
+ actualAnnotations.put(name.substring(1, name.length() - 1), ann);
+ }
+ checkEquals(countNumberOfAttributes(attributes.attrs,
+ getRetentionPolicy(attribute) == RetentionPolicy.RUNTIME
+ ? RuntimeVisibleAnnotations_attribute.class
+ : RuntimeInvisibleAnnotations_attribute.class),
+ 1l,
+ String.format("Number of %s", attribute));
+ } else {
+ checkNull(attr, String.format("%s should be null", attribute));
+ }
+ return actualAnnotations;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/classfiles/attributes/annotations/RuntimeParameterAnnotationsForGenericMethodTest.java Fri Jul 10 12:42:00 2015 +0300
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2015, 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
+ * @bug 8044411
+ * @summary Tests the RuntimeParameterVisibleAnnotations/RuntimeParameterInvisibleAnnotations attribute.
+ * Checks that the attribute is generated for bridge method.
+ * @library /tools/lib /tools/javac/lib ../lib
+ * @build WorkAnnotations TestBase TestResult InMemoryFileManager ToolBox
+ * @build TestCase ClassType TestAnnotationInfo
+ * @build RuntimeParameterAnnotationsForGenericMethodTest AnnotationsTestBase RuntimeParameterAnnotationsTestBase
+ * @run main RuntimeParameterAnnotationsForGenericMethodTest
+ */
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * RuntimeParameterAnnotationsGenericMethodTest is a test which check that
+ * RuntimeVisibleParameterAnnotationsAttribute and
+ * RuntimeInvisibleParameterAnnotationsAttribute are generated for both
+ * generic and appropriate bridge methods.
+ * All possible combinations of retention policies are tested.
+ *
+ * The test generates class which looks as follows:
+ *
+ * public class Test extends java.util.ArrayList<Integer> {
+ *
+ * public boolean add(here some annotations java.lang.Integer) {
+ * return false;
+ * }
+ * }
+ *
+ * Thereafter, various of combinations of annotations are applied
+ * to the add, the source is compiled and the generated byte code is checked.
+ *
+ * See README.txt for more information.
+ */
+public class RuntimeParameterAnnotationsForGenericMethodTest extends RuntimeParameterAnnotationsTestBase {
+ @Override
+ public List<TestCase> generateTestCases() {
+ List<TestCase> testCases = new ArrayList<>();
+ for (TestAnnotationInfos annotations : getAllCombinationsOfAnnotations()) {
+ // generate: public class Test extends java.util.ArrayList<Integer>
+ TestCase testCase = new TestCase();
+ TestCase.TestClassInfo clazz = testCase.addClassInfo("java.util.ArrayList<Integer>", ClassType.CLASS, "Test");
+ TestCase.TestParameterInfo parameter = clazz.addMethodInfo("add(java.lang.Integer)", "public").addParameter("Integer", "i");
+ annotations.annotate(parameter);
+ TestCase.TestParameterInfo synParameter = clazz.addMethodInfo("add(java.lang.Object)", true, "public").addParameter("Object", "i");
+ annotations.annotate(synParameter);
+ testCases.add(testCase);
+ }
+ return testCases;
+ }
+
+ public static void main(String[] args) throws TestFailedException {
+ new RuntimeParameterAnnotationsForGenericMethodTest().test();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/classfiles/attributes/annotations/RuntimeParameterAnnotationsForLambdaTest.java Fri Jul 10 12:42:00 2015 +0300
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2015, 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
+ * @bug 8044411 8079060
+ * @summary Tests the RuntimeParameterVisibleAnnotations/RuntimeParameterInvisibleAnnotations attribute.
+ * @library /tools/lib /tools/javac/lib ../lib
+ * @ignore 8079060 javac does not generate RuntimeParameterAnnotation attributes for lambda expressions
+ * @build WorkAnnotations TestBase TestResult InMemoryFileManager ToolBox
+ * @build TestCase ClassType TestAnnotationInfo
+ * @build RuntimeParameterAnnotationsForLambdaTest AnnotationsTestBase RuntimeParameterAnnotationsTestBase
+ * @run main RuntimeParameterAnnotationsForLambdaTest
+ */
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+import com.sun.tools.classfile.ClassFile;
+import com.sun.tools.classfile.Method;
+
+/**
+ * RuntimeParameterAnnotationsForLambdaTest is a test which checks that RuntimeVisibleParameterAnnotationsAttribute
+ * and RuntimeInvisibleParameterAnnotationsAttribute are generated properly for lambda expressions.
+ * The test checks both single and repeatable annotations.
+ * All possible combinations of retention policies are tested.
+ *
+ * The test generates source code, compiles it and checks the byte code.
+ *
+ * See README.txt for more information.
+ */
+public class RuntimeParameterAnnotationsForLambdaTest extends RuntimeParameterAnnotationsTestBase {
+
+ private static final String CLASS_NAME = "Test";
+ private static final String SOURCE_TEMPLATE =
+ "public class " + CLASS_NAME + " {\n" +
+ " interface I { void method(int a, double b, String c); }\n" +
+ " %SOURCE%\n" +
+ "}";
+
+ public static void main(String[] args) throws TestFailedException {
+ new RuntimeParameterAnnotationsForLambdaTest().test();
+ }
+
+ @Override
+ public void test() throws TestFailedException {
+ try {
+ for (TestAnnotationInfos annotations : getAllCombinationsOfAnnotations()) {
+ try {
+ TestCase.TestMethodInfo testMethodInfo = new TestCase.TestMethodInfo(0, null, "lambda", false, false);
+ TestCase.TestParameterInfo p1 = testMethodInfo.addParameter("int", "a");
+ annotations.annotate(p1);
+ testMethodInfo.addParameter("double", "b");
+ TestCase.TestParameterInfo p3 = testMethodInfo.addParameter("String", "c");
+ annotations.annotate(p3);
+ String source = SOURCE_TEMPLATE.replace("%SOURCE%", generateLambdaSource(testMethodInfo));
+ echo("Testing:\n" + source);
+ addTestCase(source);
+ ClassFile classFile = readClassFile(compile(source).getClasses().get(CLASS_NAME));
+ boolean isFoundLambda = false;
+ for (Method method : classFile.methods) {
+ if (method.getName(classFile.constant_pool).startsWith("lambda$")) {
+ isFoundLambda = true;
+ testAttributes(testMethodInfo, classFile, method);
+ }
+ }
+ checkTrue(isFoundLambda, "The tested lambda method was not found.");
+ } catch (Exception e) {
+ addFailure(e);
+ }
+ }
+ } finally {
+ checkStatus();
+ }
+ }
+
+ public String generateLambdaSource(TestCase.TestMethodInfo method) {
+ return method.parameters.stream()
+ .map(TestCase.TestParameterInfo::generateSource)
+ .collect(Collectors.joining(", ", "I i = (", ") -> {};"));
+ }
+
+ @Override
+ public List<TestCase> generateTestCases() {
+ throw new UnsupportedOperationException();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/classfiles/attributes/annotations/RuntimeParameterAnnotationsTest.java Fri Jul 10 12:42:00 2015 +0300
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2015, 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
+ * @bug 8044411
+ * @summary Tests the RuntimeParameterVisibleAnnotations/RuntimeParameterInvisibleAnnotations attribute.
+ * @library /tools/lib /tools/javac/lib ../lib
+ * @build WorkAnnotations TestBase TestResult InMemoryFileManager ToolBox
+ * @build TestCase ClassType TestAnnotationInfo
+ * @build RuntimeParameterAnnotationsTest AnnotationsTestBase RuntimeParameterAnnotationsTestBase
+ * @run main RuntimeParameterAnnotationsTest
+ */
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * RuntimeParameterAnnotationsTest is a test which checks that RuntimeVisibleParameterAnnotationsAttribute
+ * and RuntimeInvisibleParameterAnnotationsAttribute are generated properly for constructors,
+ * for static and abstract methods of class, for abstract, default and static methods of interface.
+ * The test checks both single and repeatable annotations.
+ * All possible combinations of retention policies are tested.
+ *
+ * The test generates source code, compiles it and checks the byte code.
+ *
+ * See README.txt for more information.
+ */
+public class RuntimeParameterAnnotationsTest extends RuntimeParameterAnnotationsTestBase {
+
+ @Override
+ public List<TestCase> generateTestCases() {
+ List<TestCase> testCases = new ArrayList<>();
+ for (List<TestAnnotationInfos> groupedAnnotations : groupAnnotations(getAllCombinationsOfAnnotations())) {
+ for (ClassType classType : new ClassType[]{ClassType.CLASS, ClassType.INTERFACE}) {
+ TestCase test = new TestCase();
+ for (int i = 0; i < groupedAnnotations.size(); i++) {
+ TestAnnotationInfos annotations = groupedAnnotations.get(i);
+ TestCase.TestClassInfo clazz = test.addClassInfo(classType, "Test" + i, "abstract");
+
+ initMethod(annotations, clazz, "<init>");
+
+ initMethod(annotations, clazz, "method1");
+
+ initMethod(annotations, clazz, "method2",
+ classType == ClassType.CLASS ? "abstract" : "default");
+
+ initMethod(annotations, clazz, "staticMethod", "static");
+ }
+ testCases.add(test);
+ }
+ }
+ return testCases;
+ }
+
+ /**
+ * Adds a method to the {@code testCase} with {@code methodName}.
+ *
+ * @param annotations a list of annotations
+ * @param clazz a test class
+ * @param methodName a method name
+ * @param mods an array of modifiers
+ */
+ private void initMethod(TestAnnotationInfos annotations, TestCase.TestClassInfo clazz, String methodName, String...mods) {
+ String methodDescriptor = methodName + "(int, double, java.lang.String)";
+ TestCase.TestMethodInfo method = clazz.addMethodInfo(methodDescriptor, mods);
+ TestCase.TestParameterInfo p1 = method.addParameter("int", "a");
+ annotations.annotate(p1);
+ method.addParameter("double", "b");
+ TestCase.TestParameterInfo p3 = method.addParameter("String", "c");
+ annotations.annotate(p3);
+ }
+
+ public static void main(String[] args) throws TestFailedException {
+ new RuntimeParameterAnnotationsTest().test();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/classfiles/attributes/annotations/RuntimeParameterAnnotationsTestBase.java Fri Jul 10 12:42:00 2015 +0300
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2015, 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.
+ */
+
+import com.sun.tools.classfile.*;
+
+import javax.tools.JavaFileObject;
+import java.io.IOException;
+import java.lang.annotation.RetentionPolicy;
+import java.util.*;
+
+public abstract class RuntimeParameterAnnotationsTestBase extends AnnotationsTestBase {
+
+ @Override
+ public void test(TestCase testCase, Map<String, ? extends JavaFileObject> classes)
+ throws IOException, ConstantPoolException, Descriptor.InvalidDescriptor {
+ for (Map.Entry<String, ? extends JavaFileObject> entry : classes.entrySet()) {
+ ClassFile classFile = readClassFile(classes.get(entry.getKey()));
+ Set<String> foundMethods = new HashSet<>();
+ String className = classFile.getName();
+ TestCase.TestClassInfo testClassInfo = testCase.classes.get(className);
+ for (Method method : classFile.methods) {
+ String methodName = method.getName(classFile.constant_pool) +
+ method.descriptor.getParameterTypes(classFile.constant_pool);
+ if (methodName.startsWith("<init>")) {
+ methodName = methodName.replace("<init>", className);
+ }
+ foundMethods.add(methodName);
+ echo("Testing method : " + methodName);
+
+ TestCase.TestMethodInfo testMethod = testClassInfo.getTestMethodInfo(methodName);
+ if (testMethod == null) {
+ continue;
+ }
+ testAttributes(testMethod, classFile, method);
+ }
+ checkContains(foundMethods, testClassInfo.methods.keySet(), "Methods in " + className);
+ }
+ }
+
+ protected void testAttributes(
+ TestCase.TestMethodInfo testMethod,
+ ClassFile classFile,
+ Method method) throws ConstantPoolException {
+ List<Map<String, Annotation>> actualInvisible = collectAnnotations(
+ classFile,
+ testMethod,
+ method,
+ Attribute.RuntimeInvisibleParameterAnnotations);
+ List<Map<String, Annotation>> actualVisible = collectAnnotations(
+ classFile,
+ testMethod,
+ method,
+ Attribute.RuntimeVisibleParameterAnnotations);
+
+ List<TestCase.TestParameterInfo> parameters = testMethod.parameters;
+ for (int i = 0; i < parameters.size(); ++i) {
+ TestCase.TestParameterInfo parameter = parameters.get(i);
+ checkEquals(actualInvisible.get(i).keySet(), parameter.getRuntimeInvisibleAnnotations(),
+ "RuntimeInvisibleParameterAnnotations");
+ checkEquals(actualVisible.get(i).keySet(), parameter.getRuntimeVisibleAnnotations(),
+ "RuntimeVisibleParameterAnnotations");
+ }
+
+ for (int i = 0; i < parameters.size(); ++i) {
+ TestCase.TestParameterInfo parameter = parameters.get(i);
+ for (TestAnnotationInfo expectedAnnotation : parameter.annotations.values()) {
+ RetentionPolicy policy = getRetentionPolicy(expectedAnnotation.annotationName);
+ if (policy == RetentionPolicy.SOURCE) {
+ continue;
+ }
+ printf("Testing: isVisible: %s %s%n", policy.toString(), expectedAnnotation.annotationName);
+ Annotation actualAnnotation =
+ (policy == RetentionPolicy.RUNTIME
+ ? actualVisible
+ : actualInvisible)
+ .get(i).get(expectedAnnotation.annotationName);
+ if (checkNotNull(actualAnnotation, "Annotation is found : "
+ + expectedAnnotation.annotationName)) {
+ expectedAnnotation.testAnnotation(this, classFile,
+ actualAnnotation);
+ }
+ }
+ }
+ }
+
+ private List<Map<String, Annotation>> collectAnnotations(
+ ClassFile classFile,
+ TestCase.TestMethodInfo testMethod,
+ Method method,
+ String attribute) throws ConstantPoolException {
+
+ Attributes attributes = method.attributes;
+ RuntimeParameterAnnotations_attribute attr = (RuntimeParameterAnnotations_attribute) attributes.get(attribute);
+
+ List<Map<String, Annotation>> actualAnnotations = new ArrayList<>();
+ RetentionPolicy policy = getRetentionPolicy(attribute);
+ if (testMethod.isParameterAnnotated(policy)) {
+ if (!checkNotNull(attr, "Attribute " + attribute + " must not be null")) {
+ testMethod.parameters.forEach($ -> actualAnnotations.add(new HashMap<>()));
+ return actualAnnotations;
+ }
+ for (Annotation[] anns : attr.parameter_annotations) {
+ Map<String, Annotation> annotations = new HashMap<>();
+ for (Annotation ann : anns) {
+ String name = classFile.constant_pool.getUTF8Value(ann.type_index);
+ annotations.put(name.substring(1, name.length() - 1), ann);
+ }
+ actualAnnotations.add(annotations);
+ }
+ checkEquals(countNumberOfAttributes(attributes.attrs,
+ getRetentionPolicy(attribute) == RetentionPolicy.RUNTIME
+ ? RuntimeVisibleParameterAnnotations_attribute.class
+ : RuntimeInvisibleParameterAnnotations_attribute.class),
+ 1l,
+ String.format("Number of %s", attribute));
+ } else {
+ checkNull(attr, String.format("%s should be null", attribute));
+ testMethod.parameters.forEach($ -> actualAnnotations.add(new HashMap<>()));
+ }
+ return actualAnnotations;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/classfiles/attributes/annotations/TestAnnotationInfo.java Fri Jul 10 12:42:00 2015 +0300
@@ -0,0 +1,441 @@
+/*
+ * Copyright (c) 2015, 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.
+ */
+
+import com.sun.tools.classfile.Annotation;
+import com.sun.tools.classfile.ClassFile;
+import com.sun.tools.classfile.ConstantPool;
+import com.sun.tools.classfile.ConstantPoolException;
+
+import java.lang.annotation.RetentionPolicy;
+import java.util.*;
+import java.util.stream.Collectors;
+
+public class TestAnnotationInfo {
+ public final String annotationName;
+ public final RetentionPolicy policy;
+ public final boolean isContainer;
+ public final List<Pair> elementValues;
+
+ public TestAnnotationInfo(String typeIndexName, RetentionPolicy policy, Pair... values) {
+ this(typeIndexName, policy, false, values);
+ }
+
+ public TestAnnotationInfo(String typeIndexName, RetentionPolicy policy, boolean isRepeatable, Pair... values) {
+ this.annotationName = typeIndexName;
+ this.policy = policy;
+ this.isContainer = isRepeatable;
+ elementValues = Arrays.asList(values);
+ }
+
+ public void testAnnotation(TestResult testResult, ClassFile classFile, Annotation annotation)
+ throws ConstantPoolException {
+ testResult.checkEquals(classFile.constant_pool.getUTF8Value(annotation.type_index),
+ String.format("L%s;", annotationName), "Testing annotation name : " + annotationName);
+ testResult.checkEquals(annotation.num_element_value_pairs,
+ elementValues.size(), "Number of element values");
+ if (!testResult.checkEquals(annotation.num_element_value_pairs, elementValues.size(),
+ "Number of element value pairs")) {
+ return;
+ }
+ for (int i = 0; i < annotation.num_element_value_pairs; ++i) {
+ Annotation.element_value_pair pair = annotation.element_value_pairs[i];
+ testResult.checkEquals(classFile.constant_pool.getUTF8Value(pair.element_name_index),
+ elementValues.get(i).elementName, "element_name_index : " + elementValues.get(i).elementName);
+ elementValues.get(i).elementValue.testElementValue(testResult, classFile, pair.value);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return String.format("@%s(%s)", annotationName,
+ elementValues.stream()
+ .map(Pair::toString)
+ .filter(s -> !s.isEmpty())
+ .collect(Collectors.joining(", ")));
+ }
+
+ public static class Pair {
+ public final String elementName;
+ public final TestElementValue elementValue;
+
+ public Pair(String elementName, TestElementValue elementValue) {
+ this.elementName = elementName;
+ this.elementValue = elementValue;
+ }
+
+ @Override
+ public String toString() {
+ return elementName + "=" + elementValue;
+ }
+ }
+
+ public static abstract class TestElementValue {
+ private final int tag;
+
+ public TestElementValue(int tag) {
+ this.tag = tag;
+ }
+
+ public void testTag(TestResult testCase, int actualTag) {
+ testCase.checkEquals(actualTag, tag, "tag " + (char) tag);
+ }
+
+ public abstract void testElementValue(TestResult testResult,
+ ClassFile classFile,
+ Annotation.element_value element_value)
+ throws ConstantPoolException;
+ }
+
+ public static class TestIntegerElementValue extends TestElementValue {
+ private final int value;
+
+ public TestIntegerElementValue(int tag, int value) {
+ super(tag);
+ this.value = value;
+ }
+
+ @Override
+ public void testElementValue(TestResult testResult,
+ ClassFile classFile,
+ Annotation.element_value element_value)
+ throws ConstantPoolException {
+ testTag(testResult, element_value.tag);
+ Annotation.Primitive_element_value ev =
+ (Annotation.Primitive_element_value) element_value;
+ ConstantPool.CONSTANT_Integer_info info =
+ (ConstantPool.CONSTANT_Integer_info) classFile.constant_pool.get(ev.const_value_index);
+ testResult.checkEquals(info.value, value, "const_value_index : " + value);
+ }
+
+ @Override
+ public String toString() {
+ return String.valueOf(value);
+ }
+ }
+
+ public static class TestBooleanElementValue extends TestElementValue {
+ private final boolean value;
+
+ public TestBooleanElementValue(boolean value) {
+ super('Z');
+ this.value = value;
+ }
+
+ @Override
+ public void testElementValue(TestResult testResult,
+ ClassFile classFile,
+ Annotation.element_value element_value)
+ throws ConstantPoolException {
+ testTag(testResult, element_value.tag);
+ Annotation.Primitive_element_value ev =
+ (Annotation.Primitive_element_value) element_value;
+ ConstantPool.CONSTANT_Integer_info info =
+ (ConstantPool.CONSTANT_Integer_info) classFile.constant_pool.get(ev.const_value_index);
+ testResult.checkEquals(info.value, value ? 1 : 0, "const_value_index : " + value);
+ }
+
+ @Override
+ public String toString() {
+ return String.valueOf(value);
+ }
+ }
+
+ public static class TestCharElementValue extends TestElementValue {
+ private final char value;
+
+ public TestCharElementValue(char value) {
+ super('C');
+ this.value = value;
+ }
+
+ @Override
+ public void testElementValue(TestResult testResult,
+ ClassFile classFile,
+ Annotation.element_value element_value)
+ throws ConstantPoolException {
+ testTag(testResult, element_value.tag);
+ Annotation.Primitive_element_value ev =
+ (Annotation.Primitive_element_value) element_value;
+ ConstantPool.CONSTANT_Integer_info info =
+ (ConstantPool.CONSTANT_Integer_info)
+ classFile.constant_pool.get(ev.const_value_index);
+ testResult.checkEquals(info.value, (int) value, "const_value_index : " + value);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("\'%c\'", value);
+ }
+ }
+
+ public static class TestLongElementValue extends TestElementValue {
+ private final long value;
+
+ public TestLongElementValue(long value) {
+ super('J');
+ this.value = value;
+ }
+
+ @Override
+ public void testElementValue(TestResult testResult,
+ ClassFile classFile,
+ Annotation.element_value element_value)
+ throws ConstantPool.InvalidIndex {
+ testTag(testResult, element_value.tag);
+ Annotation.Primitive_element_value ev =
+ (Annotation.Primitive_element_value) element_value;
+ ConstantPool.CONSTANT_Long_info info =
+ (ConstantPool.CONSTANT_Long_info) classFile.constant_pool.get(ev.const_value_index);
+ testResult.checkEquals(info.value, value, "const_value_index");
+ }
+
+ @Override
+ public String toString() {
+ return String.valueOf(value);
+ }
+ }
+
+ public static class TestFloatElementValue extends TestElementValue {
+ private final float value;
+
+ public TestFloatElementValue(float value) {
+ super('F');
+ this.value = value;
+ }
+
+ @Override
+ public void testElementValue(TestResult testResult,
+ ClassFile classFile,
+ Annotation.element_value element_value)
+ throws ConstantPool.InvalidIndex {
+ testTag(testResult, element_value.tag);
+ Annotation.Primitive_element_value ev =
+ (Annotation.Primitive_element_value) element_value;
+ ConstantPool.CONSTANT_Float_info info =
+ (ConstantPool.CONSTANT_Float_info) classFile.constant_pool.get(ev.const_value_index);
+ testResult.checkEquals(info.value, value, "const_value_index");
+ }
+
+ @Override
+ public String toString() {
+ return String.valueOf(value) + "f";
+ }
+ }
+
+ public static class TestDoubleElementValue extends TestElementValue {
+ private final double value;
+
+ public TestDoubleElementValue(double value) {
+ super('D');
+ this.value = value;
+ }
+
+ @Override
+ public void testElementValue(TestResult testResult,
+ ClassFile classFile,
+ Annotation.element_value element_value)
+ throws ConstantPoolException {
+ testTag(testResult, element_value.tag);
+ Annotation.Primitive_element_value ev =
+ (Annotation.Primitive_element_value) element_value;
+ ConstantPool.CONSTANT_Double_info info = (ConstantPool.CONSTANT_Double_info)
+ classFile.constant_pool.get(ev.const_value_index);
+ testResult.checkEquals(info.value, value, "const_value_index");
+ }
+
+ @Override
+ public String toString() {
+ return String.valueOf(value);
+ }
+ }
+
+ public static class TestStringElementValue extends TestElementValue {
+ private final String value;
+
+ public TestStringElementValue(String value) {
+ super('s');
+ this.value = value;
+ }
+
+ @Override
+ public void testElementValue(TestResult testResult,
+ ClassFile classFile,
+ Annotation.element_value element_value)
+ throws ConstantPoolException {
+ testTag(testResult, element_value.tag);
+ Annotation.Primitive_element_value ev =
+ (Annotation.Primitive_element_value) element_value;
+ ConstantPool.CONSTANT_Utf8_info info =
+ (ConstantPool.CONSTANT_Utf8_info) classFile.constant_pool.get(ev.const_value_index);
+ testResult.checkEquals(info.value, value, "const_value_index");
+ }
+
+ @Override
+ public String toString() {
+ return String.format("\"%s\"", value);
+ }
+ }
+
+ public static class TestEnumElementValue extends TestElementValue {
+ private final String typeName;
+ private final String constName;
+
+ public TestEnumElementValue(String typeName, String constName) {
+ super('e');
+ this.typeName = typeName;
+ this.constName = constName;
+ }
+
+ @Override
+ public void testElementValue(
+ TestResult testResult,
+ ClassFile classFile,
+ Annotation.element_value element_value)
+ throws ConstantPoolException {
+ testTag(testResult, element_value.tag);
+ Annotation.Enum_element_value ev = (Annotation.Enum_element_value) element_value;
+ testResult.checkEquals(classFile.constant_pool.getUTF8Info(ev.type_name_index).value,
+ String.format("L%s;", typeName), "type_name_index");
+ testResult.checkEquals(classFile.constant_pool.getUTF8Info(ev.const_name_index).value,
+ constName, "const_name_index");
+ }
+
+ @Override
+ public String toString() {
+ return typeName + "." + constName;
+ }
+ }
+
+ public static class TestClassElementValue extends TestElementValue {
+ private final String className;
+
+ private final static Map<String, String> mappedClassName;
+
+ static {
+ mappedClassName = new HashMap<>();
+ mappedClassName.put("void", "V");
+ mappedClassName.put("char", "C");
+ mappedClassName.put("byte", "B");
+ mappedClassName.put("short", "S");
+ mappedClassName.put("int", "I");
+ mappedClassName.put("long", "J");
+ mappedClassName.put("float", "F");
+ mappedClassName.put("double", "D");
+ }
+
+ public TestClassElementValue(String className) {
+ super('c');
+ this.className = className;
+ }
+
+ @Override
+ public void testElementValue(
+ TestResult testResult,
+ ClassFile classFile,
+ Annotation.element_value element_value)
+ throws ConstantPoolException {
+ testTag(testResult, element_value.tag);
+ Annotation.Class_element_value ev = (Annotation.Class_element_value) element_value;
+ String expectedClassName = className.replace(".class", "");
+ expectedClassName = mappedClassName.getOrDefault(expectedClassName,
+ String.format("Ljava/lang/%s;", expectedClassName));
+ testResult.checkEquals(
+ classFile.constant_pool.getUTF8Info(ev.class_info_index).value,
+ expectedClassName, "class_info_index : " + expectedClassName);
+ }
+
+ @Override
+ public String toString() {
+ return className;
+ }
+ }
+
+ public static class TestArrayElementValue extends TestElementValue {
+ public final List<TestElementValue> values;
+
+ public TestArrayElementValue(TestElementValue...values) {
+ super('[');
+ this.values = new ArrayList<>(Arrays.asList(values));
+ }
+
+ @Override
+ public void testElementValue(
+ TestResult testResult,
+ ClassFile classFile,
+ Annotation.element_value element_value)
+ throws ConstantPoolException {
+ testTag(testResult, element_value.tag);
+ Annotation.Array_element_value ev = (Annotation.Array_element_value) element_value;
+
+ for (int i = 0; i < values.size(); ++i) {
+ values.get(i).testElementValue(testResult, classFile, ev.values[i]);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return values.stream()
+ .map(TestElementValue::toString)
+ .collect(Collectors.joining(", ", "{", "}"));
+ }
+ }
+
+ public static class TestAnnotationElementValue extends TestElementValue {
+ private final String annotationName;
+ private final TestAnnotationInfo annotation;
+
+ public TestAnnotationElementValue(String className, TestAnnotationInfo annotation) {
+ super('@');
+ this.annotationName = className;
+ this.annotation = annotation;
+ }
+
+ @Override
+ public void testElementValue(
+ TestResult testResult,
+ ClassFile classFile,
+ Annotation.element_value element_value)
+ throws ConstantPoolException {
+ testTag(testResult, element_value.tag);
+ Annotation ev = ((Annotation.Annotation_element_value) element_value).annotation_value;
+ testResult.checkEquals(
+ classFile.constant_pool.getUTF8Info(ev.type_index).value,
+ String.format("L%s;", annotationName),
+ "type_index");
+ for (int i = 0; i < ev.num_element_value_pairs; ++i) {
+ Annotation.element_value_pair pair = ev.element_value_pairs[i];
+ Pair expectedPair = annotation.elementValues.get(i);
+ expectedPair.elementValue.testElementValue(testResult, classFile, pair.value);
+ testResult.checkEquals(
+ classFile.constant_pool.getUTF8Info(pair.element_name_index).value,
+ expectedPair.elementName,
+ "element_name_index");
+ }
+ }
+
+ @Override
+ public String toString() {
+ return annotation.toString();
+ }
+ }
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/classfiles/attributes/annotations/TestCase.java Fri Jul 10 12:42:00 2015 +0300
@@ -0,0 +1,459 @@
+/*
+ * Copyright (c) 2015, 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.
+ */
+
+import java.lang.annotation.RetentionPolicy;
+import java.util.*;
+import java.util.stream.Collectors;
+
+public class TestCase {
+
+ /**
+ * The top-level classes of the test case.
+ */
+ public final Map<String, TestClassInfo> classes = new LinkedHashMap<>();
+
+ /**
+ * Constructs a test class info with {@code classType} as top-level class,
+ * with {@code outerClassName} as name and {@code mods} as modifiers.
+ *
+ * @param classType a class type
+ * @param outerClassName a name
+ * @param mods an array of modifiers
+ */
+ public TestClassInfo addClassInfo(ClassType classType, String outerClassName, String...mods) {
+ return addClassInfo(null, classType, outerClassName, mods);
+ }
+
+ /**
+ * Constructs a test class info with {@code classType} as top-level class,
+ * with {@code outerClassName} as name, {@code parent} class name
+ * as parent class and {@code mods} as modifiers.
+ *
+ * @param classType a class type
+ * @param outerClassName a name
+ * @param mods an array of modifiers
+ */
+ public TestClassInfo addClassInfo(String parent, ClassType classType, String outerClassName, String...mods) {
+ TestClassInfo clazz = new TestClassInfo(classType, outerClassName, parent, mods);
+ if (classes.put(outerClassName, clazz) != null) {
+ throw new IllegalArgumentException("Duplicate class name: " + outerClassName);
+ }
+ return clazz;
+ }
+
+ public String generateSource() {
+ return classes.values().stream()
+ .map(TestMemberInfo::generateSource)
+ .collect(Collectors.joining("\n"));
+ }
+
+ /**
+ * Returns {@code TestClassInfo} by class signature.
+ * Example, {@code getTestClassInfo("Test$1Local")}
+ * returns local inner class of class {@code Test}.
+ *
+ * @param classSignature a class signature
+ * @return {@code TestClassInfo} by class signature
+ */
+ public TestClassInfo getTestClassInfo(String classSignature) {
+ String[] cs = classSignature.split("\\$");
+ if (cs.length > 0 && classes.containsKey(cs[0])) {
+ // check signature corresponds to top level class
+ if (cs.length == 1) {
+ return classes.get(cs[0]);
+ }
+ } else {
+ throw new IllegalArgumentException("Cannot find class : " + classSignature);
+ }
+ TestClassInfo current = classes.get(cs[0]);
+ // find class info in the inner classes
+ for (int i = 1; i < cs.length; ++i) {
+ Map<String, TestClassInfo> innerClasses = current.innerClasses;
+ Map<String, TestMethodInfo> methods = current.methods;
+ current = innerClasses.get(cs[i]);
+ // if current is null then class info does not exist or the class is local
+ if (current == null) {
+ if (!cs[i].isEmpty()) {
+ // the class is local, remove leading digit
+ String className = cs[i].substring(1);
+ Optional<TestClassInfo> opt = methods.values().stream()
+ .flatMap(c -> c.localClasses.values().stream())
+ .filter(c -> c.name.equals(className)).findAny();
+ if (opt.isPresent()) {
+ current = opt.get();
+ // continue analysis of local class
+ continue;
+ }
+ }
+ throw new IllegalArgumentException("Cannot find class : " + classSignature);
+ }
+ }
+ return current;
+ }
+
+ /**
+ * Class represents a program member.
+ */
+ public static abstract class TestMemberInfo {
+ // next two fields are used for formatting
+ protected final int indention;
+ protected final ClassType containerType;
+ public final List<String> mods;
+ public final String name;
+ public final Map<String, TestAnnotationInfo> annotations;
+
+ TestMemberInfo(int indention, ClassType containerType, String name, String... mods) {
+ this.indention = indention;
+ this.containerType = containerType;
+ this.mods = Arrays.asList(mods);
+ this.name = name;
+ this.annotations = new HashMap<>();
+ }
+
+ public abstract String generateSource();
+
+ public boolean isAnnotated(RetentionPolicy policy) {
+ return annotations.values().stream()
+ .filter(a -> a.policy == policy)
+ .findAny().isPresent();
+ }
+
+ public Set<String> getRuntimeVisibleAnnotations() {
+ return getRuntimeAnnotations(RetentionPolicy.RUNTIME);
+ }
+
+ public Set<String> getRuntimeInvisibleAnnotations() {
+ return getRuntimeAnnotations(RetentionPolicy.CLASS);
+ }
+
+ private Set<String> getRuntimeAnnotations(RetentionPolicy policy) {
+ return annotations.values().stream()
+ .filter(e -> e.policy == policy)
+ .map(a -> a.annotationName)
+ .distinct()
+ .collect(Collectors.toSet());
+ }
+
+ /**
+ * Generates source for annotations.
+ *
+ * @param prefix a leading text
+ * @param suffix a trailing text
+ * @param joining a text between annotations
+ * @return source for annotations
+ */
+ protected String generateSourceForAnnotations(String prefix, String suffix, String joining) {
+ StringBuilder sb = new StringBuilder();
+ for (TestAnnotationInfo annotation : annotations.values()) {
+ sb.append(prefix);
+ if (annotation.isContainer) {
+ // the annotation is repeatable
+ // container consists of an array of annotations
+ TestAnnotationInfo.TestArrayElementValue containerElementValue =
+ (TestAnnotationInfo.TestArrayElementValue) annotation.elementValues.get(0).elementValue;
+ // concatenate sources of repeatable annotations
+ sb.append(containerElementValue.values.stream()
+ .map(TestAnnotationInfo.TestElementValue::toString)
+ .collect(Collectors.joining(joining)));
+ } else {
+ sb.append(annotation);
+ }
+ sb.append(suffix);
+ }
+ String src = sb.toString();
+ return src.trim().isEmpty() ? "" : src;
+
+ }
+
+ /**
+ * Generates source for annotations.
+ *
+ * @return source for annotations
+ */
+ public String generateSourceForAnnotations() {
+ return generateSourceForAnnotations(indention(), "\n", "\n" + indention());
+ }
+
+ /**
+ * Adds annotation info to the member.
+ *
+ * @param anno an annotation info
+ */
+ public void addAnnotation(TestAnnotationInfo anno) {
+ String containerName = anno.annotationName + "Container";
+ TestAnnotationInfo annotation = annotations.get(anno.annotationName);
+ TestAnnotationInfo containerAnnotation = annotations.get(containerName);
+
+ if (annotation == null) {
+ // if annotation is null then either it is first adding of the annotation to the member
+ // or there is the container of the annotation.
+ if (containerAnnotation == null) {
+ // first adding to the member
+ annotations.put(anno.annotationName, anno);
+ } else {
+ // add annotation to container
+ TestAnnotationInfo.TestArrayElementValue containerElementValue =
+ ((TestAnnotationInfo.TestArrayElementValue) containerAnnotation.elementValues.get(0).elementValue);
+ containerElementValue.values.add(new TestAnnotationInfo.TestAnnotationElementValue(anno.annotationName, anno));
+ }
+ } else {
+ // remove previously added annotation and add new container of repeatable annotation
+ // which contains previously added and new annotation
+ annotations.remove(anno.annotationName);
+ containerAnnotation = new TestAnnotationInfo(
+ containerName,
+ anno.policy,
+ true,
+ new TestAnnotationInfo.Pair("value",
+ new TestAnnotationInfo.TestArrayElementValue(
+ new TestAnnotationInfo.TestAnnotationElementValue(anno.annotationName, annotation),
+ new TestAnnotationInfo.TestAnnotationElementValue(anno.annotationName, anno))));
+ annotations.put(containerName, containerAnnotation);
+ }
+ }
+
+ public String indention() {
+ char[] a = new char[4 * indention];
+ Arrays.fill(a, ' ');
+ return new String(a);
+ }
+
+ public String getName() {
+ return name;
+ }
+ }
+
+ /**
+ * The class represents a class.
+ */
+ public static class TestClassInfo extends TestMemberInfo {
+ public final ClassType classType;
+ public final String parent;
+ public final Map<String, TestClassInfo> innerClasses;
+ public final Map<String, TestMethodInfo> methods;
+ public final Map<String, TestFieldInfo> fields;
+
+ TestClassInfo(int indention, ClassType classType, String className, String... mods) {
+ this(indention, classType, className, null, mods);
+ }
+
+ TestClassInfo(ClassType classType, String className, String parent, String... mods) {
+ this(0, classType, className, parent, mods);
+ }
+
+ TestClassInfo(int indention, ClassType classType, String className, String parent, String... mods) {
+ super(indention, null, className, mods);
+ this.classType = classType;
+ this.parent = parent;
+ innerClasses = new LinkedHashMap<>();
+ methods = new LinkedHashMap<>();
+ fields = new LinkedHashMap<>();
+ }
+
+ /**
+ * Generates source which represents the class.
+ *
+ * @return source which represents the class
+ */
+ @Override
+ public String generateSource() {
+ String sourceForAnnotations = generateSourceForAnnotations();
+ String classModifiers = mods.stream().collect(Collectors.joining(" "));
+ return sourceForAnnotations
+ + String.format("%s%s %s %s %s {%n",
+ indention(),
+ classModifiers,
+ classType.getDescription(),
+ name,
+ parent == null ? "" : "extends " + parent)
+ + classType.collectFields(fields.values())
+ + classType.collectMethods(methods.values())
+ + classType.collectInnerClasses(innerClasses.values())
+ + indention() + "}";
+ }
+
+ /**
+ * Adds a new inner class to the class.
+ *
+ * @param classType a class type
+ * @param className a class name
+ * @param mods modifiers
+ * @return a new added inner class to the class
+ */
+ public TestClassInfo addInnerClassInfo(ClassType classType, String className, String... mods) {
+ TestClassInfo testClass = new TestClassInfo(indention + 1, classType, className, mods);
+ if (innerClasses.put(className, testClass) != null) {
+ throw new IllegalArgumentException("Duplicated class : " + className);
+ }
+ return testClass;
+ }
+
+ /**
+ * Adds a new method to the class.
+ *
+ * @param methodName a method name
+ * @param mods modifiers
+ * @return a new inner class to the class
+ */
+ public TestMethodInfo addMethodInfo(String methodName, String... mods) {
+ return addMethodInfo(methodName, false, mods);
+ }
+
+ /**
+ * Adds a new method to the class.
+ *
+ * @param methodName a method name
+ * @param isSynthetic if {@code true} the method is synthetic
+ * @param mods modifiers
+ * @return a new method added to the class
+ */
+ public TestMethodInfo addMethodInfo(String methodName, boolean isSynthetic, String... mods) {
+ boolean isConstructor = methodName.contains("<init>");
+ if (isConstructor) {
+ methodName = methodName.replace("<init>", name);
+ }
+ TestMethodInfo testMethod = new TestMethodInfo(indention + 1, classType, methodName, isConstructor, isSynthetic, mods);
+ if (methods.put(methodName, testMethod) != null) {
+ throw new IllegalArgumentException("Duplicated method : " + methodName);
+ }
+ return testMethod;
+ }
+
+ /**
+ * Adds a new field to the class.
+ *
+ * @param fieldName a method name
+ * @param mods modifiers
+ * @return a new field added to the class
+ */
+ public TestFieldInfo addFieldInfo(String fieldName, String... mods) {
+ TestFieldInfo field = new TestFieldInfo(indention + 1, classType, fieldName, mods);
+ if (fields.put(fieldName, field) != null) {
+ throw new IllegalArgumentException("Duplicated field : " + fieldName);
+ }
+ return field;
+ }
+
+ public TestMethodInfo getTestMethodInfo(String methodName) {
+ return methods.get(methodName);
+ }
+
+ public TestFieldInfo getTestFieldInfo(String fieldName) {
+ return fields.get(fieldName);
+ }
+ }
+
+ public static class TestMethodInfo extends TestMemberInfo {
+ public final boolean isConstructor;
+ public final boolean isSynthetic;
+ public final Map<String, TestClassInfo> localClasses;
+ public final List<TestParameterInfo> parameters;
+
+ TestMethodInfo(int indention, ClassType containerType, String methodName,
+ boolean isConstructor, boolean isSynthetic, String... mods) {
+ super(indention, containerType, methodName, mods);
+ this.isSynthetic = isSynthetic;
+ this.localClasses = new LinkedHashMap<>();
+ this.parameters = new ArrayList<>();
+ this.isConstructor = isConstructor;
+ }
+
+ public boolean isParameterAnnotated(RetentionPolicy policy) {
+ return parameters.stream()
+ .filter(p -> p.isAnnotated(policy))
+ .findFirst().isPresent();
+ }
+
+ public TestParameterInfo addParameter(String type, String name) {
+ TestParameterInfo testParameter = new TestParameterInfo(type, name);
+ parameters.add(testParameter);
+ return testParameter;
+ }
+
+ /**
+ * Adds a local class to the method.
+ *
+ * @param className a class name
+ * @param mods modifiers
+ * @return a local class added to the method
+ */
+ public TestClassInfo addLocalClassInfo(String className, String... mods) {
+ TestClassInfo testClass = new TestClassInfo(indention + 1, ClassType.CLASS, className, mods);
+ if (localClasses.put(className, testClass) != null) {
+ throw new IllegalArgumentException("Duplicated class : " + className);
+ }
+ return testClass;
+ }
+
+ @Override
+ public String generateSource() {
+ if (isSynthetic) {
+ return "";
+ }
+ return generateSourceForAnnotations() +
+ containerType.methodToString(this);
+ }
+
+ @Override
+ public String getName() {
+ return name.replaceAll("\\(.*\\)", "");
+ }
+ }
+
+ /**
+ * The class represents a method parameter.
+ */
+ public static class TestParameterInfo extends TestMemberInfo {
+ public final String type;
+
+ TestParameterInfo(String type, String name) {
+ super(0, null, name);
+ this.type = type;
+ }
+
+ @Override
+ public String generateSource() {
+ return generateSourceForAnnotations() + type + " " + name;
+ }
+
+ public String generateSourceForAnnotations() {
+ return generateSourceForAnnotations("", " ", " ");
+ }
+ }
+
+ /**
+ * The class represents a field.
+ */
+ public static class TestFieldInfo extends TestMemberInfo {
+
+ TestFieldInfo(int indention, ClassType containerType, String fieldName, String... mods) {
+ super(indention, containerType, fieldName, mods);
+ }
+
+ @Override
+ public String generateSource() {
+ return generateSourceForAnnotations() +
+ containerType.fieldToString(this);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/classfiles/attributes/annotations/WorkAnnotations.java Fri Jul 10 12:42:00 2015 +0300
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2015, 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.
+ */
+
+import java.lang.annotation.*;
+
+@Retention(RetentionPolicy.CLASS)
+@Repeatable(RuntimeInvisibleRepeatableContainer.class)
+@interface RuntimeInvisibleRepeatable {
+ boolean booleanValue() default false;
+ byte byteValue() default 0;
+ char charValue() default 0;
+ short shortValue() default 0;
+ int intValue() default 0;
+ long longValue() default 0;
+ float floatValue() default 0;
+ double doubleValue() default 0;
+ String stringValue() default "";
+ int[] arrayValue1() default {};
+ String[] arrayValue2() default {};
+ Class<?> classValue1() default void.class;
+ Class<?> classValue2() default void.class;
+ EnumValue enumValue() default EnumValue.VALUE1;
+ AnnotationValue annoValue() default @AnnotationValue(stringValue = "StringValue");
+ AnnotationValue[] annoArrayValue() default
+ {@AnnotationValue(stringValue = "StringValue1"),
+ @AnnotationValue(stringValue = "StringValue2"),
+ @AnnotationValue(stringValue = "StringValue3")};
+}
+
+@Retention(RetentionPolicy.CLASS)
+@interface RuntimeInvisibleRepeatableContainer {
+ RuntimeInvisibleRepeatable[] value();
+}
+
+@interface RuntimeInvisibleNotRepeatable {
+ boolean booleanValue() default false;
+ byte byteValue() default 0;
+ char charValue() default 0;
+ short shortValue() default 0;
+ int intValue() default 0;
+ long longValue() default 0;
+ float floatValue() default 0;
+ double doubleValue() default 0;
+ String stringValue() default "";
+ int[] arrayValue1() default {};
+ String[] arrayValue2() default {};
+ Class<?> classValue1() default void.class;
+ Class<?> classValue2() default void.class;
+ EnumValue enumValue() default EnumValue.VALUE1;
+ AnnotationValue annoValue() default @AnnotationValue(stringValue = "StringValue");
+ AnnotationValue[] annoArrayValue() default
+ {@AnnotationValue(stringValue = "StringValue1"),
+ @AnnotationValue(stringValue = "StringValue2"),
+ @AnnotationValue(stringValue = "StringValue3")};
+}
+
+@Retention(RetentionPolicy.RUNTIME)
+@Repeatable(RuntimeVisibleRepeatableContainer.class)
+@interface RuntimeVisibleRepeatable {
+ boolean booleanValue() default false;
+ byte byteValue() default 0;
+ char charValue() default 0;
+ short shortValue() default 0;
+ int intValue() default 0;
+ long longValue() default 0;
+ float floatValue() default 0;
+ double doubleValue() default 0;
+ String stringValue() default "";
+ int[] arrayValue1() default {};
+ String[] arrayValue2() default {};
+ Class<?> classValue1() default void.class;
+ Class<?> classValue2() default void.class;
+ EnumValue enumValue() default EnumValue.VALUE1;
+ AnnotationValue annoValue() default @AnnotationValue(stringValue = "StringValue");
+ AnnotationValue[] annoArrayValue() default
+ {@AnnotationValue(stringValue = "StringValue1"),
+ @AnnotationValue(stringValue = "StringValue2"),
+ @AnnotationValue(stringValue = "StringValue3")};
+}
+
+@Retention(RetentionPolicy.RUNTIME)
+@interface RuntimeVisibleRepeatableContainer {
+ RuntimeVisibleRepeatable[] value();
+}
+
+@Retention(RetentionPolicy.RUNTIME)
+@interface RuntimeVisibleNotRepeatable {
+ boolean booleanValue() default false;
+ byte byteValue() default 0;
+ char charValue() default 0;
+ short shortValue() default 0;
+ int intValue() default 0;
+ long longValue() default 0;
+ float floatValue() default 0;
+ double doubleValue() default 0;
+ String stringValue() default "";
+ int[] arrayValue1() default {};
+ String[] arrayValue2() default {};
+ Class<?> classValue1() default void.class;
+ Class<?> classValue2() default void.class;
+ EnumValue enumValue() default EnumValue.VALUE1;
+ AnnotationValue annoValue() default @AnnotationValue(stringValue = "StringValue");
+ AnnotationValue[] annoArrayValue() default
+ {@AnnotationValue(stringValue = "StringValue1"),
+ @AnnotationValue(stringValue = "StringValue2"),
+ @AnnotationValue(stringValue = "StringValue3")};
+}
+
+enum EnumValue {
+ VALUE1, VALUE2, VALUE3
+}
+
+@interface AnnotationValue {
+ String stringValue() default "";
+}
\ No newline at end of file
--- a/langtools/test/tools/javac/classfiles/attributes/lib/TestBase.java Wed Jul 05 20:41:30 2017 +0200
+++ b/langtools/test/tools/javac/classfiles/attributes/lib/TestBase.java Fri Jul 10 12:42:00 2015 +0300
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2015, 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
@@ -21,10 +21,9 @@
* questions.
*/
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
+import java.io.*;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
@@ -210,6 +209,12 @@
assertTrue(found.containsAll(expected), message + " : " + copy);
}
+ public void writeToFile(Path path, String source) throws IOException {
+ try (BufferedWriter writer = Files.newBufferedWriter(path)) {
+ writer.write(source);
+ }
+ }
+
public File getSourceDir() {
return new File(System.getProperty("test.src", "."));
}
--- a/langtools/test/tools/javac/classfiles/attributes/lib/TestResult.java Wed Jul 05 20:41:30 2017 +0200
+++ b/langtools/test/tools/javac/classfiles/attributes/lib/TestResult.java Fri Jul 10 12:42:00 2015 +0300
@@ -24,18 +24,16 @@
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.*;
-import java.util.stream.Collectors;
/**
* This class accumulates test results. Test results can be checked with method @{code checkStatus}.
*/
public class TestResult extends TestBase {
- private final List<Info> testCases;
+ private final List<Info> testCasesInfo;
public TestResult() {
- testCases = new ArrayList<>();
- testCases.add(new Info("Global test info"));
+ testCasesInfo = new ArrayList<>();
}
/**
@@ -44,21 +42,16 @@
* @param info the information about test case
*/
public void addTestCase(String info) {
- testCases.add(new Info(info));
- }
-
- private String errorMessage() {
- return testCases.stream().filter(Info::isFailed)
- .map(tc -> String.format("Failure in test case:\n%s\n%s", tc.info(), tc.getMessage()))
- .collect(Collectors.joining("\n"));
+ System.err.println("Test case: " + info);
+ testCasesInfo.add(new Info(info));
}
public boolean checkEquals(Object actual, Object expected, String message) {
echo("Testing : " + message);
if (!Objects.equals(actual, expected)) {
getLastTestCase().addAssert(String.format("%s\n" +
- "Expected: %s,\n" +
- " Got: %s", message, expected, actual));
+ "Expected: %s,\n" +
+ " Got: %s", message, expected, actual));
return false;
}
return true;
@@ -96,14 +89,17 @@
}
public void addFailure(Throwable th) {
- testCases.get(testCases.size() - 1).addFailure(th);
+ if (testCasesInfo.isEmpty()) {
+ testCasesInfo.add(new Info("Dummy info"));
+ }
+ getLastTestCase().addFailure(th);
}
private Info getLastTestCase() {
- if (testCases.size() == 1) {
+ if (testCasesInfo.isEmpty()) {
throw new IllegalStateException("Test case should be created");
}
- return testCases.get(testCases.size() - 1);
+ return testCasesInfo.get(testCasesInfo.size() - 1);
}
/**
@@ -114,22 +110,41 @@
* or an exception occurs
*/
public void checkStatus() throws TestFailedException {
- if (testCases.stream().anyMatch(Info::isFailed)) {
- echo(errorMessage());
+ int passed = 0;
+ int failed = 0;
+ for (Info testCaseInfo : testCasesInfo) {
+ if (testCaseInfo.isFailed()) {
+ String info = testCaseInfo.info().replace("\n", LINE_SEPARATOR);
+ String errorMessage = testCaseInfo.getMessage().replace("\n", LINE_SEPARATOR);
+ System.err.printf("Failure in test case:%n%s%n%s%n", info, errorMessage);
+ ++failed;
+ } else {
+ ++passed;
+ }
+ }
+ System.err.printf("Test cases: passed: %d, failed: %d, total: %d.%n", passed, failed, passed + failed);
+ if (failed > 0) {
throw new TestFailedException("Test failed");
}
+ if (passed + failed == 0) {
+ throw new TestFailedException("Test cases were not found");
+ }
}
- private class Info {
+ @Override
+ public void printf(String template, Object... args) {
+ getLastTestCase().printf(template, args);
+ }
+
+ private static class Info {
private final String info;
- private final List<String> asserts;
- private final List<Throwable> errors;
+ private final StringWriter writer;
+ private boolean isFailed;
private Info(String info) {
this.info = info;
- asserts = new ArrayList<>();
- errors = new ArrayList<>();
+ writer = new StringWriter();
}
public String info() {
@@ -137,34 +152,25 @@
}
public boolean isFailed() {
- return !asserts.isEmpty() || !errors.isEmpty();
+ return isFailed;
+ }
+
+ public void printf(String template, Object... args) {
+ writer.write(String.format(template, args));
}
public void addFailure(Throwable th) {
- errors.add(th);
+ isFailed = true;
printf("[ERROR] : %s\n", getStackTrace(th));
}
public void addAssert(String e) {
- asserts.add(e);
+ isFailed = true;
printf("[ASSERT] : %s\n", e);
}
public String getMessage() {
- return (asserts.size() > 0 ? getAssertMessages(asserts) + "\n" : "")
- + getErrorMessages(errors);
- }
-
- public String getAssertMessages(List<String> list) {
- return list.stream()
- .map(message -> String.format("[ASSERT] : %s", message))
- .collect(Collectors.joining("\n"));
- }
-
- public String getErrorMessages(List<? extends Throwable> list) {
- return list.stream()
- .map(throwable -> String.format("[ERROR] : %s", getStackTrace(throwable)))
- .collect(Collectors.joining("\n"));
+ return writer.toString();
}
public String getStackTrace(Throwable throwable) {