diff --git a/src/java.base/share/classes/java/lang/classfile/Annotation.java b/src/java.base/share/classes/java/lang/classfile/Annotation.java
index 28c3672bf91..357a7cb77ee 100644
--- a/src/java.base/share/classes/java/lang/classfile/Annotation.java
+++ b/src/java.base/share/classes/java/lang/classfile/Annotation.java
@@ -37,43 +37,60 @@ import java.util.List;
import jdk.internal.javac.PreviewFeature;
/**
- * Models an annotation on a declaration.
+ * Models an {@code annotation} structure (JVMS {@jvms 4.7.16}) or part of a {@code
+ * type_annotation} structure (JVMS {@jvms 4.7.20}). This model indicates the
+ * interface of the annotation and a set of element-value pairs.
+ *
+ * This model can reconstruct an annotation, given the location of the modeled structure
+ * in the class file and the definition of the annotation interface.
+ *
+ * Two {@code Annotation} objects should be compared using the {@link
+ * Object#equals(Object) equals} method.
+ *
+ * @apiNote
+ * For Java programs, the location of the modeled structure indicates the source code
+ * element or type (JLS {@jls 9.7.4}) on which the reconstructed annotation appears,
+ * and the annotation interface definition determines whether the reconstructed annotation has
+ * elements with default values (JLS {@jls 9.6.2}), and whether the reconstructed annotation
+ * is a container annotation for multiple annotations (JLS {@jls 9.7.5}).
*
* @see AnnotationElement
* @see AnnotationValue
+ * @see TypeAnnotation
* @see RuntimeVisibleAnnotationsAttribute
* @see RuntimeInvisibleAnnotationsAttribute
* @see RuntimeVisibleParameterAnnotationsAttribute
* @see RuntimeInvisibleParameterAnnotationsAttribute
*
- * @sealedGraph
* @since 22
*/
@PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API)
public sealed interface Annotation
- permits TypeAnnotation, AnnotationImpl {
+ permits AnnotationImpl {
/**
- * {@return the class of the annotation}
+ * {@return the constant pool entry holding the {@linkplain Class#descriptorString
+ * descriptor string} of the annotation interface}
*/
Utf8Entry className();
/**
- * {@return the class of the annotation, as a symbolic descriptor}
+ * {@return the annotation interface, as a symbolic descriptor}
*/
default ClassDesc classSymbol() {
return ClassDesc.ofDescriptor(className().stringValue());
}
/**
- * {@return the elements of the annotation}
+ * {@return the element-value pairs of the annotation}
*/
List elements();
/**
* {@return an annotation}
- * @param annotationClass the class of the annotation
- * @param elements the elements of the annotation
+ * @param annotationClass the constant pool entry holding the descriptor string
+ * of the annotation interface
+ * @param elements the element-value pairs of the annotation
*/
static Annotation of(Utf8Entry annotationClass,
List elements) {
@@ -82,8 +99,9 @@ public sealed interface Annotation
/**
* {@return an annotation}
- * @param annotationClass the class of the annotation
- * @param elements the elements of the annotation
+ * @param annotationClass the constant pool entry holding the descriptor string
+ * of the annotation interface
+ * @param elements the element-value pairs of the annotation
*/
static Annotation of(Utf8Entry annotationClass,
AnnotationElement... elements) {
@@ -92,8 +110,8 @@ public sealed interface Annotation
/**
* {@return an annotation}
- * @param annotationClass the class of the annotation
- * @param elements the elements of the annotation
+ * @param annotationClass the descriptor of the annotation interface
+ * @param elements the element-value pairs of the annotation
*/
static Annotation of(ClassDesc annotationClass,
List elements) {
@@ -102,8 +120,8 @@ public sealed interface Annotation
/**
* {@return an annotation}
- * @param annotationClass the class of the annotation
- * @param elements the elements of the annotation
+ * @param annotationClass the descriptor of the annotation interface
+ * @param elements the element-value pairs of the annotation
*/
static Annotation of(ClassDesc annotationClass,
AnnotationElement... elements) {
diff --git a/src/java.base/share/classes/java/lang/classfile/AnnotationElement.java b/src/java.base/share/classes/java/lang/classfile/AnnotationElement.java
index 80adb07ec4b..33bd410e78d 100644
--- a/src/java.base/share/classes/java/lang/classfile/AnnotationElement.java
+++ b/src/java.base/share/classes/java/lang/classfile/AnnotationElement.java
@@ -32,7 +32,13 @@ import jdk.internal.classfile.impl.TemporaryConstantPool;
import jdk.internal.javac.PreviewFeature;
/**
- * Models a key-value pair of an annotation.
+ * Models an element-value pair in the {@code element_value_pairs}
+ * table in the {@code annotation} structure defined in JVMS
+ * {@jvms 4.7.16} or the {@code type_annotation} structure defined
+ * in JVMS {@jvms 4.7.20}.
+ *
+ * Two {@code AnnotationElement} objects should be compared using the
+ * {@link Object#equals(Object) equals} method.
*
* @see Annotation
* @see AnnotationValue
@@ -45,6 +51,12 @@ public sealed interface AnnotationElement
/**
* {@return the element name}
+ *
+ * @apiNote
+ * In Java source code, by convention, the name of the sole element in a
+ * single-element annotation interface is {@code value}. (JLS {@jls 9.6.1})
+ * This is the case for single-element annotations (JLS {@jls 9.7.3}) and
+ * container annotations for multiple annotations (JLS {@jls 9.6.3}).
*/
Utf8Entry name();
@@ -54,7 +66,7 @@ public sealed interface AnnotationElement
AnnotationValue value();
/**
- * {@return an annotation key-value pair}
+ * {@return an element-value pair}
* @param name the name of the key
* @param value the associated value
*/
@@ -64,7 +76,7 @@ public sealed interface AnnotationElement
}
/**
- * {@return an annotation key-value pair}
+ * {@return an element-value pair}
* @param name the name of the key
* @param value the associated value
*/
@@ -74,9 +86,10 @@ public sealed interface AnnotationElement
}
/**
- * {@return an annotation key-value pair for a class-valued annotation}
+ * {@return an element-value pair for a class-valued element}
* @param name the name of the key
* @param value the associated value
+ * @see AnnotationValue#ofClass(ClassDesc) AnnotationValue::ofClass
*/
static AnnotationElement ofClass(String name,
ClassDesc value) {
@@ -84,9 +97,10 @@ public sealed interface AnnotationElement
}
/**
- * {@return an annotation key-value pair for a string-valued annotation}
+ * {@return an element-value pair for a string-valued element}
* @param name the name of the key
* @param value the associated value
+ * @see AnnotationValue#ofString(String) AnnotationValue::ofString
*/
static AnnotationElement ofString(String name,
String value) {
@@ -94,9 +108,10 @@ public sealed interface AnnotationElement
}
/**
- * {@return an annotation key-value pair for a long-valued annotation}
+ * {@return an element-value pair for a long-valued element}
* @param name the name of the key
* @param value the associated value
+ * @see AnnotationValue#ofLong(long) AnnotationValue::ofLong
*/
static AnnotationElement ofLong(String name,
long value) {
@@ -104,9 +119,10 @@ public sealed interface AnnotationElement
}
/**
- * {@return an annotation key-value pair for an int-valued annotation}
+ * {@return an element-value pair for an int-valued element}
* @param name the name of the key
* @param value the associated value
+ * @see AnnotationValue#ofInt(int) AnnotationValue::ofInt
*/
static AnnotationElement ofInt(String name,
int value) {
@@ -114,9 +130,10 @@ public sealed interface AnnotationElement
}
/**
- * {@return an annotation key-value pair for a char-valued annotation}
+ * {@return an element-value pair for a char-valued element}
* @param name the name of the key
* @param value the associated value
+ * @see AnnotationValue#ofChar(char) AnnotationValue::ofChar
*/
static AnnotationElement ofChar(String name,
char value) {
@@ -124,9 +141,10 @@ public sealed interface AnnotationElement
}
/**
- * {@return an annotation key-value pair for a short-valued annotation}
+ * {@return an element-value pair for a short-valued element}
* @param name the name of the key
* @param value the associated value
+ * @see AnnotationValue#ofShort(short) AnnotationValue::ofShort
*/
static AnnotationElement ofShort(String name,
short value) {
@@ -134,29 +152,32 @@ public sealed interface AnnotationElement
}
/**
- * {@return an annotation key-value pair for a byte-valued annotation}
+ * {@return an element-value pair for a byte-valued element}
* @param name the name of the key
* @param value the associated value
+ * @see AnnotationValue#ofByte(byte) AnnotationValue::ofByte
*/
static AnnotationElement ofByte(String name,
- byte value) {
+ byte value) {
return of(name, AnnotationValue.ofByte(value));
}
/**
- * {@return an annotation key-value pair for a boolean-valued annotation}
+ * {@return an element-value pair for a boolean-valued element}
* @param name the name of the key
* @param value the associated value
+ * @see AnnotationValue#ofBoolean(boolean) AnnotationValue::ofBoolean
*/
static AnnotationElement ofBoolean(String name,
- boolean value) {
+ boolean value) {
return of(name, AnnotationValue.ofBoolean(value));
}
/**
- * {@return an annotation key-value pair for a double-valued annotation}
+ * {@return an element-value pair for a double-valued element}
* @param name the name of the key
* @param value the associated value
+ * @see AnnotationValue#ofDouble(double) AnnotationValue::ofDouble
*/
static AnnotationElement ofDouble(String name,
double value) {
@@ -164,9 +185,10 @@ public sealed interface AnnotationElement
}
/**
- * {@return an annotation key-value pair for a float-valued annotation}
+ * {@return an element-value pair for a float-valued element}
* @param name the name of the key
* @param value the associated value
+ * @see AnnotationValue#ofFloat(float) AnnotationValue::ofFloat
*/
static AnnotationElement ofFloat(String name,
float value) {
@@ -174,9 +196,10 @@ public sealed interface AnnotationElement
}
/**
- * {@return an annotation key-value pair for an annotation-valued annotation}
+ * {@return an element-value pair for an annotation-valued element}
* @param name the name of the key
* @param value the associated value
+ * @see AnnotationValue#ofAnnotation AnnotationValue::ofAnnotation
*/
static AnnotationElement ofAnnotation(String name,
Annotation value) {
@@ -184,9 +207,10 @@ public sealed interface AnnotationElement
}
/**
- * {@return an annotation key-value pair for an array-valued annotation}
+ * {@return an element-value pair for an array-valued element}
* @param name the name of the key
* @param values the associated values
+ * @see AnnotationValue#ofArray(AnnotationValue...) AnnotationValue::ofArray
*/
static AnnotationElement ofArray(String name,
AnnotationValue... values) {
diff --git a/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java b/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java
index 04bbcffb8bc..4decff86ad7 100644
--- a/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java
+++ b/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java
@@ -41,7 +41,11 @@ import java.util.List;
import jdk.internal.javac.PreviewFeature;
/**
- * Models the value of a key-value pair of an annotation.
+ * Models an {@code element_value} structure, or a value of an element-value
+ * pair of an annotation, as defined in JVMS {@jvms 4.7.16.1}.
+ *
+ * Two {@code AnnotationValue} objects should be compared using the {@link
+ * Object#equals(Object) equals} method.
*
* @see Annotation
* @see AnnotationElement
@@ -53,8 +57,8 @@ import jdk.internal.javac.PreviewFeature;
public sealed interface AnnotationValue {
/**
- * Models an annotation-valued element.
- * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_ANNOTATION}.
+ * Models an annotation value of an element-value pair.
+ * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_ANNOTATION}.
*
* @since 22
*/
@@ -66,8 +70,8 @@ public sealed interface AnnotationValue {
}
/**
- * Models an array-valued element.
- * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_ARRAY}.
+ * Models an array value of an element-value pair.
+ * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_ARRAY}.
*
* @since 22
*/
@@ -79,13 +83,15 @@ public sealed interface AnnotationValue {
*
* @apiNote
* All array elements derived from Java source code have the same type,
- * which must not be an array type. ({@jls 9.6.1})
+ * which must not be an array type. (JLS {@jls 9.6.1}) If such elements are
+ * annotations, they have the same annotation interface; if such elements
+ * are enum, they belong to the same enum class.
*/
List values();
}
/**
- * Models a constant-valued element.
+ * Models a constant value of an element-value pair.
*
* @sealedGraph
* @since 22
@@ -123,8 +129,8 @@ public sealed interface AnnotationValue {
}
/**
- * Models a string-valued element.
- * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_STRING}.
+ * Models a string value of an element-value pair.
+ * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_STRING}.
*
* @since 22
*/
@@ -151,8 +157,8 @@ public sealed interface AnnotationValue {
}
/**
- * Models a double-valued element.
- * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_DOUBLE}.
+ * Models a double value of an element-value pair.
+ * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_DOUBLE}.
*
* @since 22
*/
@@ -179,8 +185,8 @@ public sealed interface AnnotationValue {
}
/**
- * Models a float-valued element.
- * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_FLOAT}.
+ * Models a float value of an element-value pair.
+ * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_FLOAT}.
*
* @since 22
*/
@@ -207,8 +213,8 @@ public sealed interface AnnotationValue {
}
/**
- * Models a long-valued element.
- * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_LONG}.
+ * Models a long value of an element-value pair.
+ * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_LONG}.
*
* @since 22
*/
@@ -235,8 +241,8 @@ public sealed interface AnnotationValue {
}
/**
- * Models an int-valued element.
- * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_INT}.
+ * Models an int value of an element-value pair.
+ * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_INT}.
*
* @since 22
*/
@@ -263,8 +269,8 @@ public sealed interface AnnotationValue {
}
/**
- * Models a short-valued element.
- * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_SHORT}.
+ * Models a short value of an element-value pair.
+ * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_SHORT}.
*
* @since 22
*/
@@ -294,8 +300,8 @@ public sealed interface AnnotationValue {
}
/**
- * Models a char-valued element.
- * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_CHAR}.
+ * Models a char value of an element-value pair.
+ * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_CHAR}.
*
* @since 22
*/
@@ -325,8 +331,8 @@ public sealed interface AnnotationValue {
}
/**
- * Models a byte-valued element.
- * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_BYTE}.
+ * Models a byte value of an element-value pair.
+ * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_BYTE}.
*
* @since 22
*/
@@ -356,8 +362,8 @@ public sealed interface AnnotationValue {
}
/**
- * Models a boolean-valued element.
- * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_BOOLEAN}.
+ * Models a boolean value of an element-value pair.
+ * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_BOOLEAN}.
*
* @since 22
*/
@@ -387,8 +393,8 @@ public sealed interface AnnotationValue {
}
/**
- * Models a class-valued element.
- * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_CLASS}.
+ * Models a class value of an element-value pair.
+ * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_CLASS}.
*
* @since 22
*/
@@ -405,8 +411,8 @@ public sealed interface AnnotationValue {
}
/**
- * Models an enum-valued element.
- * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_ENUM}.
+ * Models an enum value of an element-value pair.
+ * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_ENUM}.
*
* @since 22
*/
@@ -426,12 +432,13 @@ public sealed interface AnnotationValue {
}
/**
- * {@return the tag character for this type as per JVMS {@jvms 4.7.16.1}}
+ * {@return the tag character for this value as per JVMS {@jvms 4.7.16.1}}
+ * The tag characters have a one-to-one mapping to the types of annotation element values.
*/
char tag();
/**
- * {@return an annotation element for a enum-valued element}
+ * {@return an enum value for an element-value pair}
* @param className the descriptor string of the enum class
* @param constantName the name of the enum constant
*/
@@ -441,7 +448,7 @@ public sealed interface AnnotationValue {
}
/**
- * {@return an annotation element for a enum-valued element}
+ * {@return an enum value for an element-value pair}
* @param className the descriptor of the enum class
* @param constantName the name of the enum constant
*/
@@ -451,7 +458,7 @@ public sealed interface AnnotationValue {
}
/**
- * {@return an annotation element for a class-valued element}
+ * {@return a class value for an element-value pair}
* @param className the descriptor string of the class
*/
static OfClass ofClass(Utf8Entry className) {
@@ -459,7 +466,7 @@ public sealed interface AnnotationValue {
}
/**
- * {@return an annotation element for a class-valued element}
+ * {@return a class value for an element-value pair}
* @param className the descriptor of the class
*/
static OfClass ofClass(ClassDesc className) {
@@ -467,7 +474,7 @@ public sealed interface AnnotationValue {
}
/**
- * {@return an annotation element for a string-valued element}
+ * {@return a string value for an element-value pair}
* @param value the string
*/
static OfString ofString(Utf8Entry value) {
@@ -475,7 +482,7 @@ public sealed interface AnnotationValue {
}
/**
- * {@return an annotation element for a string-valued element}
+ * {@return a string value for an element-value pair}
* @param value the string
*/
static OfString ofString(String value) {
@@ -483,7 +490,7 @@ public sealed interface AnnotationValue {
}
/**
- * {@return an annotation element for a double-valued element}
+ * {@return a double value for an element-value pair}
* @param value the double value
*/
static OfDouble ofDouble(DoubleEntry value) {
@@ -491,7 +498,7 @@ public sealed interface AnnotationValue {
}
/**
- * {@return an annotation element for a double-valued element}
+ * {@return a double value for an element-value pair}
* @param value the double value
*/
static OfDouble ofDouble(double value) {
@@ -499,7 +506,7 @@ public sealed interface AnnotationValue {
}
/**
- * {@return an annotation element for a float-valued element}
+ * {@return a float value for an element-value pair}
* @param value the float value
*/
static OfFloat ofFloat(FloatEntry value) {
@@ -507,7 +514,7 @@ public sealed interface AnnotationValue {
}
/**
- * {@return an annotation element for a float-valued element}
+ * {@return a float value for an element-value pair}
* @param value the float value
*/
static OfFloat ofFloat(float value) {
@@ -515,7 +522,7 @@ public sealed interface AnnotationValue {
}
/**
- * {@return an annotation element for a long-valued element}
+ * {@return a long value for an element-value pair}
* @param value the long value
*/
static OfLong ofLong(LongEntry value) {
@@ -523,7 +530,7 @@ public sealed interface AnnotationValue {
}
/**
- * {@return an annotation element for a long-valued element}
+ * {@return a long value for an element-value pair}
* @param value the long value
*/
static OfLong ofLong(long value) {
@@ -531,7 +538,7 @@ public sealed interface AnnotationValue {
}
/**
- * {@return an annotation element for an int-valued element}
+ * {@return an int value for an element-value pair}
* @param value the int value
*/
static OfInt ofInt(IntegerEntry value) {
@@ -539,7 +546,7 @@ public sealed interface AnnotationValue {
}
/**
- * {@return an annotation element for an int-valued element}
+ * {@return an int value for an element-value pair}
* @param value the int value
*/
static OfInt ofInt(int value) {
@@ -547,7 +554,7 @@ public sealed interface AnnotationValue {
}
/**
- * {@return an annotation element for a short-valued element}
+ * {@return a short value for an element-value pair}
* @param value the short value
*/
static OfShort ofShort(IntegerEntry value) {
@@ -555,7 +562,7 @@ public sealed interface AnnotationValue {
}
/**
- * {@return an annotation element for a short-valued element}
+ * {@return a short value for an element-value pair}
* @param value the short value
*/
static OfShort ofShort(short value) {
@@ -563,7 +570,7 @@ public sealed interface AnnotationValue {
}
/**
- * {@return an annotation element for a char-valued element}
+ * {@return a char value for an element-value pair}
* @param value the char value
*/
static OfChar ofChar(IntegerEntry value) {
@@ -571,7 +578,7 @@ public sealed interface AnnotationValue {
}
/**
- * {@return an annotation element for a char-valued element}
+ * {@return a char value for an element-value pair}
* @param value the char value
*/
static OfChar ofChar(char value) {
@@ -579,7 +586,7 @@ public sealed interface AnnotationValue {
}
/**
- * {@return an annotation element for a byte-valued element}
+ * {@return a byte value for an element-value pair}
* @param value the byte value
*/
static OfByte ofByte(IntegerEntry value) {
@@ -587,7 +594,7 @@ public sealed interface AnnotationValue {
}
/**
- * {@return an annotation element for a byte-valued element}
+ * {@return a byte value for an element-value pair}
* @param value the byte value
*/
static OfByte ofByte(byte value) {
@@ -595,7 +602,7 @@ public sealed interface AnnotationValue {
}
/**
- * {@return an annotation element for a boolean-valued element}
+ * {@return a boolean value for an element-value pair}
* @param value the boolean value
*/
static OfBoolean ofBoolean(IntegerEntry value) {
@@ -603,7 +610,7 @@ public sealed interface AnnotationValue {
}
/**
- * {@return an annotation element for a boolean-valued element}
+ * {@return a boolean value for an element-value pair}
* @param value the boolean value
*/
static OfBoolean ofBoolean(boolean value) {
@@ -612,7 +619,7 @@ public sealed interface AnnotationValue {
}
/**
- * {@return an annotation element for an annotation-valued element}
+ * {@return an annotation value for an element-value pair}
* @param value the annotation
*/
static OfAnnotation ofAnnotation(Annotation value) {
@@ -620,7 +627,12 @@ public sealed interface AnnotationValue {
}
/**
- * {@return an annotation element for an array-valued element}
+ * {@return an array value for an element-value pair}
+ *
+ * @apiNote
+ * See {@link AnnotationValue.OfArray#values() values()} for conventions
+ * on array values derived from Java source code.
+ *
* @param values the array elements
*/
static OfArray ofArray(List values) {
@@ -628,7 +640,12 @@ public sealed interface AnnotationValue {
}
/**
- * {@return an annotation element for an array-valued element}
+ * {@return an array value for an element-value pair}
+ *
+ * @apiNote
+ * See {@link AnnotationValue.OfArray#values() values()} for conventions
+ * on array values derived from Java source code.
+ *
* @param values the array elements
*/
static OfArray ofArray(AnnotationValue... values) {
diff --git a/src/java.base/share/classes/java/lang/classfile/TypeAnnotation.java b/src/java.base/share/classes/java/lang/classfile/TypeAnnotation.java
index 01a2f5fc696..b6c9aec76a1 100644
--- a/src/java.base/share/classes/java/lang/classfile/TypeAnnotation.java
+++ b/src/java.base/share/classes/java/lang/classfile/TypeAnnotation.java
@@ -25,12 +25,10 @@
package java.lang.classfile;
-import java.lang.constant.ClassDesc;
import java.util.List;
import java.lang.classfile.attribute.RuntimeInvisibleTypeAnnotationsAttribute;
import java.lang.classfile.attribute.RuntimeVisibleTypeAnnotationsAttribute;
-import java.lang.classfile.constantpool.Utf8Entry;
import jdk.internal.classfile.impl.TargetInfoImpl;
import jdk.internal.classfile.impl.UnboundAttribute;
@@ -56,12 +54,22 @@ import static java.lang.classfile.ClassFile.TAT_METHOD_TYPE_PARAMETER_BOUND;
import static java.lang.classfile.ClassFile.TAT_NEW;
import static java.lang.classfile.ClassFile.TAT_RESOURCE_VARIABLE;
import static java.lang.classfile.ClassFile.TAT_THROWS;
-import jdk.internal.classfile.impl.TemporaryConstantPool;
import jdk.internal.javac.PreviewFeature;
/**
- * Models an annotation on a type use, as defined in JVMS {@jvms 4.7.19} and {@jvms 4.7.20}.
+ * Models a {@code type_annotation} structure (JVMS {@jvms 4.7.20}). This model
+ * indicates the annotated type within a declaration or expression and the part
+ * of the indicated type that is annotated, in addition to what is {@linkplain
+ * #annotation() available} in an {@code Annotation}.
+ *
+ * This model can reconstruct an annotation on a type or a part of a type, given
+ * the location of the {@code type_annotation} structure in the class file and
+ * the definition of the annotation interface.
+ *
+ * Two {@code TypeAnnotation} objects should be compared using the {@link
+ * Object#equals(Object) equals} method.
*
+ * @see Annotation
* @see RuntimeVisibleTypeAnnotationsAttribute
* @see RuntimeInvisibleTypeAnnotationsAttribute
*
@@ -69,7 +77,6 @@ import jdk.internal.javac.PreviewFeature;
*/
@PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API)
public sealed interface TypeAnnotation
- extends Annotation
permits UnboundAttribute.UnboundTypeAnnotation {
/**
@@ -170,7 +177,7 @@ public sealed interface TypeAnnotation
/**
* {@return information describing precisely which type in a declaration or expression
- * is annotated}
+ * is annotated} This models the {@code target_type} and {@code target_info} items.
*/
TargetInfo targetInfo();
@@ -180,57 +187,22 @@ public sealed interface TypeAnnotation
List targetPath();
/**
- * {@return a type annotation}
- * @param targetInfo which type in a declaration or expression is annotated
- * @param targetPath which part of the type is annotated
- * @param annotationClassUtf8Entry the annotation class
- * @param annotationElements the annotation elements
+ * {@return the annotation applied to the part indicated by {@link #targetPath()}}
+ * This models the interface of the annotation and the set of element-value pairs,
+ * the subset of the {@code type_annotation} structure that is identical to the
+ * {@code annotation} structure.
*/
- static TypeAnnotation of(TargetInfo targetInfo, List targetPath,
- Utf8Entry annotationClassUtf8Entry,
- List annotationElements) {
- return new UnboundAttribute.UnboundTypeAnnotation(targetInfo, targetPath,
- annotationClassUtf8Entry, annotationElements);
- }
+ Annotation annotation();
/**
- * {@return a type annotation}
+ * {@return a {@code type_annotation} structure}
* @param targetInfo which type in a declaration or expression is annotated
* @param targetPath which part of the type is annotated
- * @param annotationClass the annotation class
- * @param annotationElements the annotation elements
+ * @param annotation the annotation
*/
static TypeAnnotation of(TargetInfo targetInfo, List targetPath,
- ClassDesc annotationClass,
- AnnotationElement... annotationElements) {
- return of(targetInfo, targetPath, annotationClass, List.of(annotationElements));
- }
-
- /**
- * {@return a type annotation}
- * @param targetInfo which type in a declaration or expression is annotated
- * @param targetPath which part of the type is annotated
- * @param annotationClass the annotation class
- * @param annotationElements the annotation elements
- */
- static TypeAnnotation of(TargetInfo targetInfo, List targetPath,
- ClassDesc annotationClass,
- List annotationElements) {
- return of(targetInfo, targetPath,
- TemporaryConstantPool.INSTANCE.utf8Entry(annotationClass.descriptorString()), annotationElements);
- }
-
- /**
- * {@return a type annotation}
- * @param targetInfo which type in a declaration or expression is annotated
- * @param targetPath which part of the type is annotated
- * @param annotationClassUtf8Entry the annotation class
- * @param annotationElements the annotation elements
- */
- static TypeAnnotation of(TargetInfo targetInfo, List targetPath,
- Utf8Entry annotationClassUtf8Entry,
- AnnotationElement... annotationElements) {
- return of(targetInfo, targetPath, annotationClassUtf8Entry, List.of(annotationElements));
+ Annotation annotation) {
+ return new UnboundAttribute.UnboundTypeAnnotation(targetInfo, targetPath, annotation);
}
/**
diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractAttributeMapper.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractAttributeMapper.java
index 0029b503d7a..8be167cd119 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractAttributeMapper.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractAttributeMapper.java
@@ -657,7 +657,7 @@ public sealed abstract class AbstractAttributeMapper>
@Override
protected void writeBody(BufWriter buf, RuntimeInvisibleTypeAnnotationsAttribute attr) {
- AnnotationReader.writeAnnotations(buf, attr.annotations());
+ AnnotationReader.writeTypeAnnotations(buf, attr.annotations());
}
}
@@ -714,7 +714,7 @@ public sealed abstract class AbstractAttributeMapper>
@Override
protected void writeBody(BufWriter buf, RuntimeVisibleTypeAnnotationsAttribute attr) {
- AnnotationReader.writeAnnotations(buf, attr.annotations());
+ AnnotationReader.writeTypeAnnotations(buf, attr.annotations());
}
}
diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java
index e21938bbc0c..6802d6e75aa 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java
@@ -241,10 +241,8 @@ public final class AnnotationReader {
};
}
// the annotation info for this annotation
- Utf8Entry type = classReader.readEntry(p, Utf8Entry.class);
- p += 2;
- return TypeAnnotation.of(targetInfo, List.of(typePath), type,
- readAnnotationElementValuePairs(classReader, p));
+ var anno = readAnnotation(classReader, p);
+ return TypeAnnotation.of(targetInfo, List.of(typePath), anno);
}
private static List readLocalVarEntries(ClassReader classReader, int p, LabelContext lc, int targetType) {
@@ -283,13 +281,11 @@ public final class AnnotationReader {
}
public static void writeAnnotation(BufWriterImpl buf, Annotation annotation) {
- // handles annotations and type annotations
// TODO annotation cleanup later
((Util.Writable) annotation).writeTo(buf);
}
- public static void writeAnnotations(BufWriter buf, List extends Annotation> list) {
- // handles annotations and type annotations
+ public static void writeAnnotations(BufWriter buf, List list) {
var internalBuf = (BufWriterImpl) buf;
internalBuf.writeU2(list.size());
for (var e : list) {
@@ -297,6 +293,66 @@ public final class AnnotationReader {
}
}
+ private static int labelToBci(LabelContext lr, Label label, TypeAnnotation ta) {
+ //helper method to avoid NPE
+ if (lr == null) throw new IllegalArgumentException("Illegal targetType '%s' in TypeAnnotation outside of Code attribute".formatted(ta.targetInfo().targetType()));
+ return lr.labelToBci(label);
+ }
+
+ public static void writeTypeAnnotation(BufWriterImpl buf, TypeAnnotation ta) {
+ LabelContext lr = buf.labelContext();
+ // target_type
+ buf.writeU1(ta.targetInfo().targetType().targetTypeValue());
+
+ // target_info
+ switch (ta.targetInfo()) {
+ case TypeAnnotation.TypeParameterTarget tpt -> buf.writeU1(tpt.typeParameterIndex());
+ case TypeAnnotation.SupertypeTarget st -> buf.writeU2(st.supertypeIndex());
+ case TypeAnnotation.TypeParameterBoundTarget tpbt -> {
+ buf.writeU1(tpbt.typeParameterIndex());
+ buf.writeU1(tpbt.boundIndex());
+ }
+ case TypeAnnotation.EmptyTarget _ -> {
+ // nothing to write
+ }
+ case TypeAnnotation.FormalParameterTarget fpt -> buf.writeU1(fpt.formalParameterIndex());
+ case TypeAnnotation.ThrowsTarget tt -> buf.writeU2(tt.throwsTargetIndex());
+ case TypeAnnotation.LocalVarTarget lvt -> {
+ buf.writeU2(lvt.table().size());
+ for (var e : lvt.table()) {
+ int startPc = labelToBci(lr, e.startLabel(), ta);
+ buf.writeU2(startPc);
+ buf.writeU2(labelToBci(lr, e.endLabel(), ta) - startPc);
+ buf.writeU2(e.index());
+ }
+ }
+ case TypeAnnotation.CatchTarget ct -> buf.writeU2(ct.exceptionTableIndex());
+ case TypeAnnotation.OffsetTarget ot -> buf.writeU2(labelToBci(lr, ot.target(), ta));
+ case TypeAnnotation.TypeArgumentTarget tat -> {
+ buf.writeU2(labelToBci(lr, tat.target(), ta));
+ buf.writeU1(tat.typeArgumentIndex());
+ }
+ }
+
+ // target_path
+ buf.writeU1(ta.targetPath().size());
+ for (TypeAnnotation.TypePathComponent component : ta.targetPath()) {
+ buf.writeU1(component.typePathKind().tag());
+ buf.writeU1(component.typeArgumentIndex());
+ }
+
+ // annotation data
+ writeAnnotation(buf, ta.annotation());
+ }
+
+ public static void writeTypeAnnotations(BufWriter buf, List list) {
+ var internalBuf = (BufWriterImpl) buf;
+ internalBuf.writeU2(list.size());
+ for (var e : list) {
+ writeTypeAnnotation(internalBuf, e);
+ }
+ }
+
public static void writeAnnotationValue(BufWriterImpl buf, AnnotationValue value) {
// TODO annotation cleanup later
((Util.Writable) value).writeTo(buf);
diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassPrinterImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassPrinterImpl.java
index 75346dd5998..2a648e27568 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassPrinterImpl.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassPrinterImpl.java
@@ -1038,9 +1038,9 @@ public final class ClassPrinterImpl {
private static Node typeAnnotationsToTree(Style style, String name, List annos) {
return new ListNodeImpl(style, name, annos.stream().map(a ->
new MapNodeImpl(FLOW, "anno")
- .with(leaf("annotation class", a.className().stringValue()),
+ .with(leaf("annotation class", a.annotation().className().stringValue()),
leaf("target info", a.targetInfo().targetType().name()))
- .with(elementValuePairsToTree(a.elements()))));
+ .with(elementValuePairsToTree(a.annotation().elements()))));
}
diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassRemapperImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassRemapperImpl.java
index e3f701b2e2a..9b5e7639fa2 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassRemapperImpl.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassRemapperImpl.java
@@ -401,9 +401,7 @@ public record ClassRemapperImpl(Function mapFunction) impl
List mapTypeAnnotations(List typeAnnotations) {
return typeAnnotations.stream().map(a -> TypeAnnotation.of(a.targetInfo(),
- a.targetPath(), map(a.classSymbol()),
- a.elements().stream().map(el -> AnnotationElement.of(el.name(),
- mapAnnotationValue(el.value()))).toList())).toList();
+ a.targetPath(), mapAnnotation(a.annotation()))).toList();
}
List mapTypeParams(List typeParams) {
diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java
index 6b64511fd5a..5ee3759bba3 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java
@@ -29,14 +29,12 @@ import java.util.List;
import java.util.Optional;
import java.lang.classfile.Annotation;
-import java.lang.classfile.AnnotationElement;
import java.lang.classfile.AnnotationValue;
import java.lang.classfile.Attribute;
import java.lang.classfile.AttributeMapper;
import java.lang.classfile.Attributes;
import java.lang.classfile.BootstrapMethodEntry;
import java.lang.classfile.constantpool.ClassEntry;
-import java.lang.classfile.Label;
import java.lang.classfile.TypeAnnotation;
import java.lang.classfile.attribute.AnnotationDefaultAttribute;
import java.lang.classfile.attribute.BootstrapMethodsAttribute;
@@ -758,75 +756,10 @@ public abstract sealed class UnboundAttribute>
public record UnboundTypeAnnotation(TargetInfo targetInfo,
List targetPath,
- Utf8Entry className,
- List elements) implements TypeAnnotation, Util.Writable {
+ Annotation annotation) implements TypeAnnotation {
- public UnboundTypeAnnotation(TargetInfo targetInfo, List targetPath,
- Utf8Entry className, List elements) {
- this.targetInfo = targetInfo;
- this.targetPath = List.copyOf(targetPath);
- this.className = className;
- this.elements = List.copyOf(elements);
- }
-
- private int labelToBci(LabelContext lr, Label label) {
- //helper method to avoid NPE
- if (lr == null) throw new IllegalArgumentException("Illegal targetType '%s' in TypeAnnotation outside of Code attribute".formatted(targetInfo.targetType()));
- return lr.labelToBci(label);
- }
-
- @Override
- public void writeTo(BufWriterImpl buf) {
- LabelContext lr = buf.labelContext();
- // target_type
- buf.writeU1(targetInfo.targetType().targetTypeValue());
-
- // target_info
- switch (targetInfo) {
- case TypeParameterTarget tpt -> buf.writeU1(tpt.typeParameterIndex());
- case SupertypeTarget st -> buf.writeU2(st.supertypeIndex());
- case TypeParameterBoundTarget tpbt -> {
- buf.writeU1(tpbt.typeParameterIndex());
- buf.writeU1(tpbt.boundIndex());
- }
- case EmptyTarget et -> {
- // nothing to write
- }
- case FormalParameterTarget fpt -> buf.writeU1(fpt.formalParameterIndex());
- case ThrowsTarget tt -> buf.writeU2(tt.throwsTargetIndex());
- case LocalVarTarget lvt -> {
- buf.writeU2(lvt.table().size());
- for (var e : lvt.table()) {
- int startPc = labelToBci(lr, e.startLabel());
- buf.writeU2(startPc);
- buf.writeU2(labelToBci(lr, e.endLabel()) - startPc);
- buf.writeU2(e.index());
- }
- }
- case CatchTarget ct -> buf.writeU2(ct.exceptionTableIndex());
- case OffsetTarget ot -> buf.writeU2(labelToBci(lr, ot.target()));
- case TypeArgumentTarget tat -> {
- buf.writeU2(labelToBci(lr, tat.target()));
- buf.writeU1(tat.typeArgumentIndex());
- }
- }
-
- // target_path
- buf.writeU1(targetPath().size());
- for (TypePathComponent component : targetPath()) {
- buf.writeU1(component.typePathKind().tag());
- buf.writeU1(component.typeArgumentIndex());
- }
-
- // type_index
- buf.writeIndex(className);
-
- // element_value_pairs
- buf.writeU2(elements.size());
- for (AnnotationElement pair : elements()) {
- buf.writeIndex(pair.name());
- AnnotationReader.writeAnnotationValue(buf, pair.value());
- }
+ public UnboundTypeAnnotation {
+ targetPath = List.copyOf(targetPath);
}
}
diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/ParserVerifier.java b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/ParserVerifier.java
index 4a2ffd3f25d..77f56b322dd 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/ParserVerifier.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/ParserVerifier.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2023, 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
@@ -393,7 +393,7 @@ public record ParserVerifier(ClassModel classModel) {
private static int typeAnnotationsSize(List ans) {
int l = 2;
for (var an : ans) {
- l += 2 + an.targetInfo().size() + 2 * an.targetPath().size() + annotationSize(an);
+ l += 2 + an.targetInfo().size() + 2 * an.targetPath().size() + annotationSize(an.annotation());
}
return l;
}
diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/javap/AnnotationWriter.java b/src/jdk.jdeps/share/classes/com/sun/tools/javap/AnnotationWriter.java
index ae5cd2df024..66b978f252c 100644
--- a/src/jdk.jdeps/share/classes/com/sun/tools/javap/AnnotationWriter.java
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/javap/AnnotationWriter.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 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
@@ -95,13 +95,13 @@ public class AnnotationWriter extends BasicWriter {
write(annot, true, false, lr);
println();
indent(+1);
- write(annot, true);
+ write(annot.annotation(), true);
indent(-1);
}
public void write(TypeAnnotation annot, boolean showOffsets,
boolean resolveIndices, CodeAttribute lr) {
- write(annot, resolveIndices);
+ write(annot.annotation(), resolveIndices);
print(": ");
write(annot.targetInfo(), annot.targetPath(), showOffsets, lr);
}
diff --git a/test/jdk/jdk/classfile/ClassPrinterTest.java b/test/jdk/jdk/classfile/ClassPrinterTest.java
index 7668648f829..bd95075a08e 100644
--- a/test/jdk/jdk/classfile/ClassPrinterTest.java
+++ b/test/jdk/jdk/classfile/ClassPrinterTest.java
@@ -66,7 +66,7 @@ class ClassPrinterTest {
RuntimeInvisibleTypeAnnotationsAttribute.of(
TypeAnnotation.of(TypeAnnotation.TargetInfo.ofField(),
List.of(TypeAnnotation.TypePathComponent.WILDCARD),
- ClassDesc.of("Boo"), List.of()))))))
+ Annotation.of(ClassDesc.of("Boo"), List.of())))))))
.with(RuntimeInvisibleAnnotationsAttribute.of(Annotation.of(ClassDesc.of("Phoo"), AnnotationElement.ofFloat("flfl", 2), AnnotationElement.ofFloat("frfl", 3))))
.with(PermittedSubclassesAttribute.ofSymbols(ClassDesc.of("Boo"), ClassDesc.of("Phoo")))
.withField("f", ConstantDescs.CD_String, fb -> fb
@@ -101,7 +101,7 @@ class ClassPrinterTest {
tryb.with(RuntimeInvisibleTypeAnnotationsAttribute.of(
TypeAnnotation.of(TypeAnnotation.TargetInfo.ofField(),
List.of(TypeAnnotation.TypePathComponent.WILDCARD),
- ClassDesc.of("Boo"), List.of())));
+ Annotation.of(ClassDesc.of("Boo"), List.of()))));
tryb.invokedynamic(DynamicCallSiteDesc.of(
MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.STATIC, ClassDesc.of("Phoo"), "phee", MethodTypeDesc.of(ClassDesc.of("Boo"))),
"intfMethod",
@@ -116,7 +116,7 @@ class ClassPrinterTest {
.with(RuntimeVisibleTypeAnnotationsAttribute.of(
TypeAnnotation.of(TypeAnnotation.TargetInfo.ofField(),
List.of(TypeAnnotation.TypePathComponent.ARRAY),
- ClassDesc.of("Fee"), List.of(AnnotationElement.ofBoolean("yes", false)))))
+ Annotation.of(ClassDesc.of("Fee"), List.of(AnnotationElement.ofBoolean("yes", false))))))
))));
}
diff --git a/test/jdk/jdk/classfile/TransformTests.java b/test/jdk/jdk/classfile/TransformTests.java
index fb9f72ba3aa..b78da8b4311 100644
--- a/test/jdk/jdk/classfile/TransformTests.java
+++ b/test/jdk/jdk/classfile/TransformTests.java
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 8336010 8336588
+ * @bug 8335935 8336588
* @summary Testing ClassFile transformations.
* @run junit TransformTests
*/
diff --git a/test/jdk/jdk/classfile/helpers/ClassRecord.java b/test/jdk/jdk/classfile/helpers/ClassRecord.java
index a62ef172367..ce22037ccda 100644
--- a/test/jdk/jdk/classfile/helpers/ClassRecord.java
+++ b/test/jdk/jdk/classfile/helpers/ClassRecord.java
@@ -828,7 +828,7 @@ public record ClassRecord(
ann.targetInfo().targetType().targetTypeValue(),
TargetInfoRecord.ofTargetInfo(ann.targetInfo(), lr, code),
ann.targetPath().stream().map(tpc -> TypePathRecord.ofTypePathComponent(tpc)).collect(toSet()),
- AnnotationRecord.ofAnnotation(ann));
+ AnnotationRecord.ofAnnotation(ann.annotation()));
}
public interface TargetInfoRecord {
diff --git a/test/jdk/jdk/classfile/helpers/RebuildingTransformation.java b/test/jdk/jdk/classfile/helpers/RebuildingTransformation.java
index 7667403aaab..b769898d785 100644
--- a/test/jdk/jdk/classfile/helpers/RebuildingTransformation.java
+++ b/test/jdk/jdk/classfile/helpers/RebuildingTransformation.java
@@ -179,8 +179,7 @@ class RebuildingTransformation {
return annotations.stream().map(ta -> TypeAnnotation.of(
transformTargetInfo(ta.targetInfo(), cob, labels),
ta.targetPath().stream().map(tpc -> TypeAnnotation.TypePathComponent.of(tpc.typePathKind(), tpc.typeArgumentIndex())).toList(),
- ta.classSymbol(),
- ta.elements().stream().map(ae -> AnnotationElement.of(ae.name().stringValue(), transformAnnotationValue(ae.value()))).toList())).toArray(TypeAnnotation[]::new);
+ transformAnnotation(ta.annotation()))).toArray(TypeAnnotation[]::new);
}
static TypeAnnotation.TargetInfo transformTargetInfo(TypeAnnotation.TargetInfo ti, CodeBuilder cob, HashMap