1/* 2 * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24import com.sun.tools.classfile.*; 25 26import java.io.IOException; 27import java.lang.annotation.RetentionPolicy; 28import java.util.*; 29import java.util.function.Supplier; 30 31import javax.tools.JavaFileObject; 32 33public abstract class RuntimeAnnotationsTestBase extends AnnotationsTestBase { 34 35 @Override 36 public void test(TestCase testCase, Map<String, ? extends JavaFileObject> classes) 37 throws IOException, ConstantPoolException, Descriptor.InvalidDescriptor { 38 for (Map.Entry<String, ? extends JavaFileObject> entry : classes.entrySet()) { 39 String className = entry.getKey(); 40 TestCase.TestClassInfo clazz = testCase.getTestClassInfo(className); 41 echo("Testing class : " + className); 42 ClassFile classFile = readClassFile(entry.getValue()); 43 44 testAttributes(clazz, classFile, () -> classFile.attributes); 45 46 testMethods(clazz, classFile); 47 48 testFields(clazz, classFile); 49 } 50 } 51 52 private void testMethods(TestCase.TestClassInfo clazz, ClassFile classFile) 53 throws ConstantPoolException, Descriptor.InvalidDescriptor { 54 String className = clazz.getName(); 55 Set<String> foundMethods = new HashSet<>(); 56 for (Method method : classFile.methods) { 57 String methodName = method.getName(classFile.constant_pool) + 58 method.descriptor.getParameterTypes(classFile.constant_pool); 59 if (methodName.startsWith("<init>")) { 60 String constructorName = className.replaceAll(".*\\$", ""); 61 methodName = methodName.replace("<init>", constructorName); 62 } 63 echo("Testing method : " + methodName); 64 65 TestCase.TestMethodInfo testMethod = clazz.getTestMethodInfo(methodName); 66 foundMethods.add(methodName); 67 if (testMethod == null) { 68 continue; 69 } 70 testAttributes(testMethod, classFile, () -> method.attributes); 71 } 72 checkContains(foundMethods, clazz.methods.keySet(), "Methods in class : " + className); 73 } 74 75 private void testFields(TestCase.TestClassInfo clazz, ClassFile classFile) 76 throws ConstantPoolException { 77 Set<String> foundFields = new HashSet<>(); 78 for (Field field : classFile.fields) { 79 String fieldName = field.getName(classFile.constant_pool); 80 echo("Testing field : " + fieldName); 81 82 TestCase.TestFieldInfo testField = clazz.getTestFieldInfo(fieldName); 83 foundFields.add(fieldName); 84 if (testField == null) { 85 continue; 86 } 87 testAttributes(testField, classFile, () -> field.attributes); 88 } 89 checkContains(foundFields, clazz.fields.keySet(), "Fields in class : " + clazz.getName()); 90 } 91 92 private void testAttributes( 93 TestCase.TestMemberInfo member, 94 ClassFile classFile, 95 Supplier<Attributes> attributes) 96 throws ConstantPoolException { 97 Map<String, Annotation> actualInvisible = collectAnnotations( 98 classFile, 99 member, 100 attributes.get(), 101 Attribute.RuntimeInvisibleAnnotations); 102 Map<String, Annotation> actualVisible = collectAnnotations( 103 classFile, 104 member, 105 attributes.get(), 106 Attribute.RuntimeVisibleAnnotations); 107 108 checkEquals(actualInvisible.keySet(), 109 member.getRuntimeInvisibleAnnotations(), "RuntimeInvisibleAnnotations"); 110 checkEquals(actualVisible.keySet(), 111 member.getRuntimeVisibleAnnotations(), "RuntimeVisibleAnnotations"); 112 113 for (TestAnnotationInfo expectedAnnotation : member.annotations.values()) { 114 RetentionPolicy policy = getRetentionPolicy(expectedAnnotation.annotationName); 115 if (policy == RetentionPolicy.SOURCE) { 116 continue; 117 } 118 printf("Testing: isVisible: %s %s%n", policy.toString(), expectedAnnotation.annotationName); 119 Annotation actualAnnotation = 120 (policy == RetentionPolicy.RUNTIME ? actualVisible : actualInvisible) 121 .get(expectedAnnotation.annotationName); 122 if (checkNotNull(actualAnnotation, "Annotation is found : " 123 + expectedAnnotation.annotationName)) { 124 expectedAnnotation.testAnnotation(this, classFile, actualAnnotation); 125 } 126 } 127 } 128 129 private Map<String, Annotation> collectAnnotations( 130 ClassFile classFile, 131 TestCase.TestMemberInfo member, 132 Attributes attributes, 133 String attribute) throws ConstantPoolException { 134 135 RuntimeAnnotations_attribute attr = (RuntimeAnnotations_attribute) attributes.get(attribute); 136 Map<String, Annotation> actualAnnotations = new HashMap<>(); 137 RetentionPolicy policy = getRetentionPolicy(attribute); 138 if (member.isAnnotated(policy)) { 139 if (!checkNotNull(attr, String.format("%s should be not null value", attribute))) { 140 // test case failed, stop checking 141 return actualAnnotations; 142 } 143 for (Annotation ann : attr.annotations) { 144 String name = classFile.constant_pool.getUTF8Value(ann.type_index); 145 actualAnnotations.put(name.substring(1, name.length() - 1), ann); 146 } 147 checkEquals(countNumberOfAttributes(attributes.attrs, 148 getRetentionPolicy(attribute) == RetentionPolicy.RUNTIME 149 ? RuntimeVisibleAnnotations_attribute.class 150 : RuntimeInvisibleAnnotations_attribute.class), 151 1l, 152 String.format("Number of %s", attribute)); 153 } else { 154 checkNull(attr, String.format("%s should be null", attribute)); 155 } 156 return actualAnnotations; 157 } 158} 159