# HG changeset patch # User aeremeev # Date 1436521320 -10800 # Node ID 1ec80335c03d0d98e5b9ba737cfea274e3fa17ff # Parent 1fccc38cd6f56cb2173195e317ba2784b484c2d1 8044411: Implement classfile tests for RuntimeAnnotations and RuntimeParameterAnnotations attribute. Reviewed-by: jjg, shurailine, anazarov diff -r 1fccc38cd6f5 -r 1ec80335c03d test/tools/javac/classfiles/attributes/annotations/AnnotationsTestBase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/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 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 generateTestCases(); + + public abstract void test(TestCase testCase, Map 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 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 annotations; + + public TestAnnotationInfos(List 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> groupAnnotations(List annotations) { + List> groupedAnnotations = new ArrayList<>(); + int size = 32; + List 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 getAllCombinationsOfAnnotations() { + List combinations = new ArrayList<>(); + for (Annotations annotationName1 : Annotations.values()) { + List 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 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 clazz) { + return Stream.of(attrs) + .filter(clazz::isInstance) + .count(); + } + + public void test() throws TestFailedException { + try { + List 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; + } + } +} diff -r 1fccc38cd6f5 -r 1ec80335c03d test/tools/javac/classfiles/attributes/annotations/ClassType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/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 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 members) { + String src = members.stream() + .map(TestCase.TestMemberInfo::generateSource) + .collect(Collectors.joining("\n")); + return src.trim().isEmpty() ? "" : src + "\n\n"; + } + + public String collectInnerClasses(Collection innerClasses) { + return collectSrc(innerClasses); + } + + public String collectFields(Collection fields) { + return collectSrc(fields); + } + + public String collectMethods(Collection 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; + } +} diff -r 1fccc38cd6f5 -r 1ec80335c03d test/tools/javac/classfiles/attributes/annotations/README.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/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 diff -r 1fccc38cd6f5 -r 1ec80335c03d test/tools/javac/classfiles/attributes/annotations/RuntimeAnnotationsForGenericMethodTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/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 generateTestCases() { + List testCases = new ArrayList<>(); + for (List 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 + TestCase.TestClassInfo clazz = testCase.addClassInfo("java.util.ArrayList", 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(); + } +} diff -r 1fccc38cd6f5 -r 1ec80335c03d test/tools/javac/classfiles/attributes/annotations/RuntimeAnnotationsForInnerAnnotationTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/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 generateTestCases() { + List testCases = new ArrayList<>(); + for (List 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(); + } +} diff -r 1fccc38cd6f5 -r 1ec80335c03d test/tools/javac/classfiles/attributes/annotations/RuntimeAnnotationsForInnerClassTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/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 generateTestCases() { + List testCases = new ArrayList<>(); + for (List 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("()"); + 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(); + } +} diff -r 1fccc38cd6f5 -r 1ec80335c03d test/tools/javac/classfiles/attributes/annotations/RuntimeAnnotationsForInnerEnumTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/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 generateTestCases() { + List testCases = new ArrayList<>(); + for (List 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(); + } +} diff -r 1fccc38cd6f5 -r 1ec80335c03d test/tools/javac/classfiles/attributes/annotations/RuntimeAnnotationsForInnerInterfaceTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/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 generateTestCases() { + List testCases = new ArrayList<>(); + for (List 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(); + } +} diff -r 1fccc38cd6f5 -r 1ec80335c03d test/tools/javac/classfiles/attributes/annotations/RuntimeAnnotationsForTopLevelClassTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/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 generateTestCases() { + List testCases = new ArrayList<>(); + for (List 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("()"); + 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(); + } +} diff -r 1fccc38cd6f5 -r 1ec80335c03d test/tools/javac/classfiles/attributes/annotations/RuntimeAnnotationsTestBase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/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 classes) + throws IOException, ConstantPoolException, Descriptor.InvalidDescriptor { + for (Map.Entry 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 foundMethods = new HashSet<>(); + for (Method method : classFile.methods) { + String methodName = method.getName(classFile.constant_pool) + + method.descriptor.getParameterTypes(classFile.constant_pool); + if (methodName.startsWith("")) { + String constructorName = className.replaceAll(".*\\$", ""); + methodName = methodName.replace("", 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 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) + throws ConstantPoolException { + Map actualInvisible = collectAnnotations( + classFile, + member, + attributes.get(), + Attribute.RuntimeInvisibleAnnotations); + Map 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 collectAnnotations( + ClassFile classFile, + TestCase.TestMemberInfo member, + Attributes attributes, + String attribute) throws ConstantPoolException { + + RuntimeAnnotations_attribute attr = (RuntimeAnnotations_attribute) attributes.get(attribute); + Map 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; + } +} diff -r 1fccc38cd6f5 -r 1ec80335c03d test/tools/javac/classfiles/attributes/annotations/RuntimeParameterAnnotationsForGenericMethodTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/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 generateTestCases() { + List testCases = new ArrayList<>(); + for (TestAnnotationInfos annotations : getAllCombinationsOfAnnotations()) { + // generate: public class Test extends java.util.ArrayList + TestCase testCase = new TestCase(); + TestCase.TestClassInfo clazz = testCase.addClassInfo("java.util.ArrayList", 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(); + } +} diff -r 1fccc38cd6f5 -r 1ec80335c03d test/tools/javac/classfiles/attributes/annotations/RuntimeParameterAnnotationsForLambdaTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/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 generateTestCases() { + throw new UnsupportedOperationException(); + } +} diff -r 1fccc38cd6f5 -r 1ec80335c03d test/tools/javac/classfiles/attributes/annotations/RuntimeParameterAnnotationsTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/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 generateTestCases() { + List testCases = new ArrayList<>(); + for (List 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, ""); + + 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(); + } +} diff -r 1fccc38cd6f5 -r 1ec80335c03d test/tools/javac/classfiles/attributes/annotations/RuntimeParameterAnnotationsTestBase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/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 classes) + throws IOException, ConstantPoolException, Descriptor.InvalidDescriptor { + for (Map.Entry entry : classes.entrySet()) { + ClassFile classFile = readClassFile(classes.get(entry.getKey())); + Set 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("")) { + methodName = methodName.replace("", 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> actualInvisible = collectAnnotations( + classFile, + testMethod, + method, + Attribute.RuntimeInvisibleParameterAnnotations); + List> actualVisible = collectAnnotations( + classFile, + testMethod, + method, + Attribute.RuntimeVisibleParameterAnnotations); + + List 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> 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> 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 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; + } +} diff -r 1fccc38cd6f5 -r 1ec80335c03d test/tools/javac/classfiles/attributes/annotations/TestAnnotationInfo.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/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 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 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 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 diff -r 1fccc38cd6f5 -r 1ec80335c03d test/tools/javac/classfiles/attributes/annotations/TestCase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/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 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 innerClasses = current.innerClasses; + Map 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 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 mods; + public final String name; + public final Map 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 getRuntimeVisibleAnnotations() { + return getRuntimeAnnotations(RetentionPolicy.RUNTIME); + } + + public Set getRuntimeInvisibleAnnotations() { + return getRuntimeAnnotations(RetentionPolicy.CLASS); + } + + private Set 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 innerClasses; + public final Map methods; + public final Map 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(""); + if (isConstructor) { + methodName = methodName.replace("", 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 localClasses; + public final List 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); + } + } +} diff -r 1fccc38cd6f5 -r 1ec80335c03d test/tools/javac/classfiles/attributes/annotations/WorkAnnotations.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/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 diff -r 1fccc38cd6f5 -r 1ec80335c03d test/tools/javac/classfiles/attributes/lib/TestBase.java --- a/test/tools/javac/classfiles/attributes/lib/TestBase.java Thu Jul 09 16:38:16 2015 -0700 +++ b/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", ".")); } diff -r 1fccc38cd6f5 -r 1ec80335c03d test/tools/javac/classfiles/attributes/lib/TestResult.java --- a/test/tools/javac/classfiles/attributes/lib/TestResult.java Thu Jul 09 16:38:16 2015 -0700 +++ b/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 testCases; + private final List 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 asserts; - private final List 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 list) { - return list.stream() - .map(message -> String.format("[ASSERT] : %s", message)) - .collect(Collectors.joining("\n")); - } - - public String getErrorMessages(List list) { - return list.stream() - .map(throwable -> String.format("[ERROR] : %s", getStackTrace(throwable))) - .collect(Collectors.joining("\n")); + return writer.toString(); } public String getStackTrace(Throwable throwable) {