/* * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ import com.sun.tools.classfile.Annotation; import com.sun.tools.classfile.ClassFile; import com.sun.tools.classfile.ConstantPool; import com.sun.tools.classfile.ConstantPoolException; import java.lang.annotation.RetentionPolicy; import java.util.*; import java.util.stream.Collectors; public class TestAnnotationInfo { public final String annotationName; public final RetentionPolicy policy; public final boolean isContainer; public final List<Pair> elementValues; public TestAnnotationInfo(String typeIndexName, RetentionPolicy policy, Pair... values) { this(typeIndexName, policy, false, values); } public TestAnnotationInfo(String typeIndexName, RetentionPolicy policy, boolean isRepeatable, Pair... values) { this.annotationName = typeIndexName; this.policy = policy; this.isContainer = isRepeatable; elementValues = Arrays.asList(values); } public void testAnnotation(TestResult testResult, ClassFile classFile, Annotation annotation) throws ConstantPoolException { testResult.checkEquals(classFile.constant_pool.getUTF8Value(annotation.type_index), String.format("L%s;", annotationName), "Testing annotation name : " + annotationName); testResult.checkEquals(annotation.num_element_value_pairs, elementValues.size(), "Number of element values"); if (!testResult.checkEquals(annotation.num_element_value_pairs, elementValues.size(), "Number of element value pairs")) { return; } for (int i = 0; i < annotation.num_element_value_pairs; ++i) { Annotation.element_value_pair pair = annotation.element_value_pairs[i]; testResult.checkEquals(classFile.constant_pool.getUTF8Value(pair.element_name_index), elementValues.get(i).elementName, "element_name_index : " + elementValues.get(i).elementName); elementValues.get(i).elementValue.testElementValue(testResult, classFile, pair.value); } } @Override public String toString() { return String.format("@%s(%s)", annotationName, elementValues.stream() .map(Pair::toString) .filter(s -> !s.isEmpty()) .collect(Collectors.joining(", "))); } public static class Pair { public final String elementName; public final TestElementValue elementValue; public Pair(String elementName, TestElementValue elementValue) { this.elementName = elementName; this.elementValue = elementValue; } @Override public String toString() { return elementName + "=" + elementValue; } } public static abstract class TestElementValue { private final int tag; public TestElementValue(int tag) { this.tag = tag; } public void testTag(TestResult testCase, int actualTag) { testCase.checkEquals(actualTag, tag, "tag " + (char) tag); } public abstract void testElementValue(TestResult testResult, ClassFile classFile, Annotation.element_value element_value) throws ConstantPoolException; } public static class TestIntegerElementValue extends TestElementValue { private final int value; public TestIntegerElementValue(int tag, int value) { super(tag); this.value = value; } @Override public void testElementValue(TestResult testResult, ClassFile classFile, Annotation.element_value element_value) throws ConstantPoolException { testTag(testResult, element_value.tag); Annotation.Primitive_element_value ev = (Annotation.Primitive_element_value) element_value; ConstantPool.CONSTANT_Integer_info info = (ConstantPool.CONSTANT_Integer_info) classFile.constant_pool.get(ev.const_value_index); testResult.checkEquals(info.value, value, "const_value_index : " + value); } @Override public String toString() { return String.valueOf(value); } } public static class TestBooleanElementValue extends TestElementValue { private final boolean value; public TestBooleanElementValue(boolean value) { super('Z'); this.value = value; } @Override public void testElementValue(TestResult testResult, ClassFile classFile, Annotation.element_value element_value) throws ConstantPoolException { testTag(testResult, element_value.tag); Annotation.Primitive_element_value ev = (Annotation.Primitive_element_value) element_value; ConstantPool.CONSTANT_Integer_info info = (ConstantPool.CONSTANT_Integer_info) classFile.constant_pool.get(ev.const_value_index); testResult.checkEquals(info.value, value ? 1 : 0, "const_value_index : " + value); } @Override public String toString() { return String.valueOf(value); } } public static class TestCharElementValue extends TestElementValue { private final char value; public TestCharElementValue(char value) { super('C'); this.value = value; } @Override public void testElementValue(TestResult testResult, ClassFile classFile, Annotation.element_value element_value) throws ConstantPoolException { testTag(testResult, element_value.tag); Annotation.Primitive_element_value ev = (Annotation.Primitive_element_value) element_value; ConstantPool.CONSTANT_Integer_info info = (ConstantPool.CONSTANT_Integer_info) classFile.constant_pool.get(ev.const_value_index); testResult.checkEquals(info.value, (int) value, "const_value_index : " + value); } @Override public String toString() { return String.format("\'%c\'", value); } } public static class TestLongElementValue extends TestElementValue { private final long value; public TestLongElementValue(long value) { super('J'); this.value = value; } @Override public void testElementValue(TestResult testResult, ClassFile classFile, Annotation.element_value element_value) throws ConstantPool.InvalidIndex { testTag(testResult, element_value.tag); Annotation.Primitive_element_value ev = (Annotation.Primitive_element_value) element_value; ConstantPool.CONSTANT_Long_info info = (ConstantPool.CONSTANT_Long_info) classFile.constant_pool.get(ev.const_value_index); testResult.checkEquals(info.value, value, "const_value_index"); } @Override public String toString() { return String.valueOf(value); } } public static class TestFloatElementValue extends TestElementValue { private final float value; public TestFloatElementValue(float value) { super('F'); this.value = value; } @Override public void testElementValue(TestResult testResult, ClassFile classFile, Annotation.element_value element_value) throws ConstantPool.InvalidIndex { testTag(testResult, element_value.tag); Annotation.Primitive_element_value ev = (Annotation.Primitive_element_value) element_value; ConstantPool.CONSTANT_Float_info info = (ConstantPool.CONSTANT_Float_info) classFile.constant_pool.get(ev.const_value_index); testResult.checkEquals(info.value, value, "const_value_index"); } @Override public String toString() { return String.valueOf(value) + "f"; } } public static class TestDoubleElementValue extends TestElementValue { private final double value; public TestDoubleElementValue(double value) { super('D'); this.value = value; } @Override public void testElementValue(TestResult testResult, ClassFile classFile, Annotation.element_value element_value) throws ConstantPoolException { testTag(testResult, element_value.tag); Annotation.Primitive_element_value ev = (Annotation.Primitive_element_value) element_value; ConstantPool.CONSTANT_Double_info info = (ConstantPool.CONSTANT_Double_info) classFile.constant_pool.get(ev.const_value_index); testResult.checkEquals(info.value, value, "const_value_index"); } @Override public String toString() { return String.valueOf(value); } } public static class TestStringElementValue extends TestElementValue { private final String value; public TestStringElementValue(String value) { super('s'); this.value = value; } @Override public void testElementValue(TestResult testResult, ClassFile classFile, Annotation.element_value element_value) throws ConstantPoolException { testTag(testResult, element_value.tag); Annotation.Primitive_element_value ev = (Annotation.Primitive_element_value) element_value; ConstantPool.CONSTANT_Utf8_info info = (ConstantPool.CONSTANT_Utf8_info) classFile.constant_pool.get(ev.const_value_index); testResult.checkEquals(info.value, value, "const_value_index"); } @Override public String toString() { return String.format("\"%s\"", value); } } public static class TestEnumElementValue extends TestElementValue { private final String typeName; private final String constName; public TestEnumElementValue(String typeName, String constName) { super('e'); this.typeName = typeName; this.constName = constName; } @Override public void testElementValue( TestResult testResult, ClassFile classFile, Annotation.element_value element_value) throws ConstantPoolException { testTag(testResult, element_value.tag); Annotation.Enum_element_value ev = (Annotation.Enum_element_value) element_value; testResult.checkEquals(classFile.constant_pool.getUTF8Info(ev.type_name_index).value, String.format("L%s;", typeName), "type_name_index"); testResult.checkEquals(classFile.constant_pool.getUTF8Info(ev.const_name_index).value, constName, "const_name_index"); } @Override public String toString() { return typeName + "." + constName; } } public static class TestClassElementValue extends TestElementValue { private final String className; private final static Map<String, String> mappedClassName; static { mappedClassName = new HashMap<>(); mappedClassName.put("void", "V"); mappedClassName.put("char", "C"); mappedClassName.put("byte", "B"); mappedClassName.put("short", "S"); mappedClassName.put("int", "I"); mappedClassName.put("long", "J"); mappedClassName.put("float", "F"); mappedClassName.put("double", "D"); } public TestClassElementValue(String className) { super('c'); this.className = className; } @Override public void testElementValue( TestResult testResult, ClassFile classFile, Annotation.element_value element_value) throws ConstantPoolException { testTag(testResult, element_value.tag); Annotation.Class_element_value ev = (Annotation.Class_element_value) element_value; String expectedClassName = className.replace(".class", ""); expectedClassName = mappedClassName.getOrDefault(expectedClassName, String.format("Ljava/lang/%s;", expectedClassName)); testResult.checkEquals( classFile.constant_pool.getUTF8Info(ev.class_info_index).value, expectedClassName, "class_info_index : " + expectedClassName); } @Override public String toString() { return className; } } public static class TestArrayElementValue extends TestElementValue { public final List<TestElementValue> values; public TestArrayElementValue(TestElementValue...values) { super('['); this.values = new ArrayList<>(Arrays.asList(values)); } @Override public void testElementValue( TestResult testResult, ClassFile classFile, Annotation.element_value element_value) throws ConstantPoolException { testTag(testResult, element_value.tag); Annotation.Array_element_value ev = (Annotation.Array_element_value) element_value; for (int i = 0; i < values.size(); ++i) { values.get(i).testElementValue(testResult, classFile, ev.values[i]); } } @Override public String toString() { return values.stream() .map(TestElementValue::toString) .collect(Collectors.joining(", ", "{", "}")); } } public static class TestAnnotationElementValue extends TestElementValue { private final String annotationName; private final TestAnnotationInfo annotation; public TestAnnotationElementValue(String className, TestAnnotationInfo annotation) { super('@'); this.annotationName = className; this.annotation = annotation; } @Override public void testElementValue( TestResult testResult, ClassFile classFile, Annotation.element_value element_value) throws ConstantPoolException { testTag(testResult, element_value.tag); Annotation ev = ((Annotation.Annotation_element_value) element_value).annotation_value; testResult.checkEquals( classFile.constant_pool.getUTF8Info(ev.type_index).value, String.format("L%s;", annotationName), "type_index"); for (int i = 0; i < ev.num_element_value_pairs; ++i) { Annotation.element_value_pair pair = ev.element_value_pairs[i]; Pair expectedPair = annotation.elementValues.get(i); expectedPair.elementValue.testElementValue(testResult, classFile, pair.value); testResult.checkEquals( classFile.constant_pool.getUTF8Info(pair.element_name_index).value, expectedPair.elementName, "element_name_index"); } } @Override public String toString() { return annotation.toString(); } } }