jdk-24/test/langtools/tools/javac/classfiles/attributes/annotations/TestAnnotationInfo.java
2024-08-13 15:14:06 +00:00

416 lines
15 KiB
Java

/*
* Copyright (c) 2015, 2024, 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.classfile.*;
import java.lang.classfile.AnnotationValue;
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, ClassModel classFile, Annotation annotation) {
testResult.checkEquals(annotation.classSymbol().descriptorString(),
String.format("L%s;", annotationName), "Testing annotation name : " + annotationName);
testResult.checkEquals(annotation.elements().size(),
elementValues.size(), "Number of element values");
if (!testResult.checkEquals(annotation.elements().size(), elementValues.size(),
"Number of element value pairs")) {
return;
}
for (int i = 0; i < annotation.elements().size(); ++i) {
AnnotationElement pair = annotation.elements().get(i);
testResult.checkEquals(pair.name().stringValue(),
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,
ClassModel classFile,
AnnotationValue element_value);
}
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,
ClassModel classFile,
AnnotationValue element_value) {
testTag(testResult, element_value.tag());
switch (element_value.tag()) {
case 'B':
testResult.checkEquals((int)((AnnotationValue.OfByte) element_value).byteValue(), value, "const_value_index : " + value);
break;
case 'S':
testResult.checkEquals((int)((AnnotationValue.OfShort) element_value).shortValue(), value, "const_value_index : " + value);
break;
default:
testResult.checkEquals(((AnnotationValue.OfInt) element_value).intValue(), 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,
ClassModel classFile,
AnnotationValue element_value) {
testTag(testResult, element_value.tag());
AnnotationValue.OfBoolean ev = (AnnotationValue.OfBoolean) element_value;
testResult.checkEquals(ev.booleanValue(), value, "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,
ClassModel classFile,
AnnotationValue element_value) {
testTag(testResult, element_value.tag());
AnnotationValue.OfChar ev =
(AnnotationValue.OfChar) element_value;
testResult.checkEquals(ev.charValue(), 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,
ClassModel classFile,
AnnotationValue element_value) {
testTag(testResult, element_value.tag());
AnnotationValue.OfLong ev =
(AnnotationValue.OfLong) element_value;
testResult.checkEquals(ev.longValue(), 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,
ClassModel classFile,
AnnotationValue element_value) {
testTag(testResult, element_value.tag());
AnnotationValue.OfFloat ev =
(AnnotationValue.OfFloat) element_value;
testResult.checkEquals(ev.floatValue(), 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,
ClassModel classFile,
AnnotationValue element_value) {
testTag(testResult, element_value.tag());
AnnotationValue.OfDouble ev =
(AnnotationValue.OfDouble) element_value;
testResult.checkEquals(ev.doubleValue(), 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,
ClassModel classFile,
AnnotationValue element_value) {
testTag(testResult, element_value.tag());
AnnotationValue.OfString ev =
(AnnotationValue.OfString) element_value;
testResult.checkEquals(ev.stringValue(), 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,
ClassModel classFile,
AnnotationValue element_value) {
testTag(testResult, element_value.tag());
AnnotationValue.OfEnum ev = (AnnotationValue.OfEnum) element_value;
testResult.checkEquals(ev.classSymbol().descriptorString(),
String.format("L%s;", typeName), "type_name_index");
testResult.checkEquals(ev.constantName().stringValue(),
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,
ClassModel classFile,
AnnotationValue element_value) {
testTag(testResult, element_value.tag());
AnnotationValue.OfClass ev = (AnnotationValue.OfClass) element_value;
String expectedClassName = className.replace(".class", "");
expectedClassName = mappedClassName.getOrDefault(expectedClassName,
String.format("Ljava/lang/%s;", expectedClassName));
testResult.checkEquals(ev.classSymbol().descriptorString(),
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,
ClassModel classFile,
AnnotationValue element_value) {
testTag(testResult, element_value.tag());
AnnotationValue.OfArray ev = (AnnotationValue.OfArray) element_value;
for (int i = 0; i < values.size(); ++i) {
values.get(i).testElementValue(testResult, classFile, ev.values().get(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,
ClassModel classFile,
AnnotationValue element_value) {
testTag(testResult, element_value.tag());
Annotation ev = ((AnnotationValue.OfAnnotation) element_value).annotation();
testResult.checkEquals(
ev.classSymbol().descriptorString(),
String.format("L%s;", annotationName),
"type_index");
for (int i = 0; i < ev.elements().size(); ++i) {
AnnotationElement pair = ev.elements().get(i);
Pair expectedPair = annotation.elementValues.get(i);
expectedPair.elementValue.testElementValue(testResult, classFile, pair.value());
testResult.checkEquals(
pair.name().stringValue(),
expectedPair.elementName,
"element_name_index");
}
}
@Override
public String toString() {
return annotation.toString();
}
}
}