This is an automated email from the ASF dual-hosted git repository.

garydgregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-bcel.git


The following commit(s) were added to refs/heads/master by this push:
     new 67fca5a6 Sort members
67fca5a6 is described below

commit 67fca5a65b9a69cf0fe1aae696e539120e3bcff0
Author: Gary Gregory <[email protected]>
AuthorDate: Fri Oct 30 08:06:23 2026 -0400

    Sort members
---
 .../apache/bcel/classfile/DescendingVisitor.java   |  18 +-
 .../org/apache/bcel/classfile/EmptyVisitor.java    |  10 +-
 .../apache/bcel/classfile/TypeAnnotationEntry.java | 112 ++++-----
 .../org/apache/bcel/classfile/TypeAnnotations.java |  32 +--
 .../java/org/apache/bcel/classfile/Visitor.java    |  20 +-
 .../verifier/statics/StringRepresentation.java     |  20 +-
 .../classfile/TypeAnnotationAttributesTest.java    |  46 ++--
 .../bcel/classfile/TypeAnnotationEntryTest.java    | 178 +++++++-------
 .../apache/bcel/classfile/TypeAnnotationsTest.java | 266 ++++++++++-----------
 9 files changed, 351 insertions(+), 351 deletions(-)

diff --git a/src/main/java/org/apache/bcel/classfile/DescendingVisitor.java 
b/src/main/java/org/apache/bcel/classfile/DescendingVisitor.java
index 6fadac04..be2a7b23 100644
--- a/src/main/java/org/apache/bcel/classfile/DescendingVisitor.java
+++ b/src/main/java/org/apache/bcel/classfile/DescendingVisitor.java
@@ -537,15 +537,6 @@ public class DescendingVisitor implements Visitor {
         stack.pop();
     }
 
-    /** @since 6.14.0 */
-    @Override
-    public void visitTypeAnnotations(final TypeAnnotations obj) {
-        stack.push(obj);
-        obj.accept(visitor);
-        
accept(Stream.of(obj.getTypeAnnotationEntries()).map(TypeAnnotationEntry::getAnnotationEntry).toArray(AnnotationEntry[]::new));
-        stack.pop();
-    }
-
     @Override
     public void visitSignature(final Signature attribute) {
         stack.push(attribute);
@@ -597,6 +588,15 @@ public class DescendingVisitor implements Visitor {
         stack.pop();
     }
 
+    /** @since 6.14.0 */
+    @Override
+    public void visitTypeAnnotations(final TypeAnnotations obj) {
+        stack.push(obj);
+        obj.accept(visitor);
+        
accept(Stream.of(obj.getTypeAnnotationEntries()).map(TypeAnnotationEntry::getAnnotationEntry).toArray(AnnotationEntry[]::new));
+        stack.pop();
+    }
+
     @Override
     public void visitUnknown(final Unknown attribute) {
         stack.push(attribute);
diff --git a/src/main/java/org/apache/bcel/classfile/EmptyVisitor.java 
b/src/main/java/org/apache/bcel/classfile/EmptyVisitor.java
index a34449e3..a230fb0f 100644
--- a/src/main/java/org/apache/bcel/classfile/EmptyVisitor.java
+++ b/src/main/java/org/apache/bcel/classfile/EmptyVisitor.java
@@ -303,11 +303,6 @@ public class EmptyVisitor implements Visitor {
     public void visitPermittedSubclasses(final PermittedSubclasses obj) {
     }
 
-    /** @since 6.14.0 */
-    @Override
-    public void visitTypeAnnotations(final TypeAnnotations obj) {
-    }
-
     @Override
     public void visitSignature(final Signature obj) {
     }
@@ -338,6 +333,11 @@ public class EmptyVisitor implements Visitor {
     public void visitSynthetic(final Synthetic obj) {
     }
 
+    /** @since 6.14.0 */
+    @Override
+    public void visitTypeAnnotations(final TypeAnnotations obj) {
+    }
+
     @Override
     public void visitUnknown(final Unknown obj) {
     }
diff --git a/src/main/java/org/apache/bcel/classfile/TypeAnnotationEntry.java 
b/src/main/java/org/apache/bcel/classfile/TypeAnnotationEntry.java
index 5c7caf61..1a41f499 100644
--- a/src/main/java/org/apache/bcel/classfile/TypeAnnotationEntry.java
+++ b/src/main/java/org/apache/bcel/classfile/TypeAnnotationEntry.java
@@ -115,47 +115,6 @@ public class TypeAnnotationEntry {
     /** Number of bytes of a {@code localvar_target} entry: start_pc, length 
and index. */
     private static final int LOCAL_VARIABLE_RANGE_SIZE = 6;
 
-    /**
-     * Gets the number of bytes of the target info that follows a target type.
-     *
-     * @param targetType The target type.
-     * @return the size of the target info, or -1 if it depends on its content 
(the table of a {@code localvar_target}).
-     * @throws ClassFormatException Thrown if the target type is not defined.
-     */
-    private static int targetInfoSize(final int targetType) {
-        switch (targetType) {
-        case TARGET_CLASS_TYPE_PARAMETER:
-        case TARGET_METHOD_TYPE_PARAMETER:
-        case TARGET_METHOD_FORMAL_PARAMETER:
-            return 1;
-        case TARGET_CLASS_EXTENDS:
-        case TARGET_CLASS_TYPE_PARAMETER_BOUND:
-        case TARGET_METHOD_TYPE_PARAMETER_BOUND:
-        case TARGET_THROWS:
-        case TARGET_EXCEPTION_PARAMETER:
-        case TARGET_INSTANCEOF:
-        case TARGET_NEW:
-        case TARGET_CONSTRUCTOR_REFERENCE:
-        case TARGET_METHOD_REFERENCE:
-            return 2;
-        case TARGET_FIELD:
-        case TARGET_METHOD_RETURN:
-        case TARGET_METHOD_RECEIVER:
-            return 0;
-        case TARGET_LOCAL_VARIABLE:
-        case TARGET_RESOURCE_VARIABLE:
-            return -1;
-        case TARGET_CAST:
-        case TARGET_CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
-        case TARGET_METHOD_INVOCATION_TYPE_ARGUMENT:
-        case TARGET_CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
-        case TARGET_METHOD_REFERENCE_TYPE_ARGUMENT:
-            return 3;
-        default:
-            throw new ClassFormatException("Invalid type annotation target 
type: 0x" + Integer.toHexString(targetType));
-        }
-    }
-
     private static void checkTargetInfo(final int targetType, final byte[] 
targetInfo) {
         final int size = targetInfoSize(targetType);
         if (size >= 0) {
@@ -197,6 +156,47 @@ public class TypeAnnotationEntry {
         return new TypeAnnotationEntry(targetType, targetInfo, typePath, 
AnnotationEntry.read(input, constantPool, isRuntimeVisible));
     }
 
+    /**
+     * Gets the number of bytes of the target info that follows a target type.
+     *
+     * @param targetType The target type.
+     * @return the size of the target info, or -1 if it depends on its content 
(the table of a {@code localvar_target}).
+     * @throws ClassFormatException Thrown if the target type is not defined.
+     */
+    private static int targetInfoSize(final int targetType) {
+        switch (targetType) {
+        case TARGET_CLASS_TYPE_PARAMETER:
+        case TARGET_METHOD_TYPE_PARAMETER:
+        case TARGET_METHOD_FORMAL_PARAMETER:
+            return 1;
+        case TARGET_CLASS_EXTENDS:
+        case TARGET_CLASS_TYPE_PARAMETER_BOUND:
+        case TARGET_METHOD_TYPE_PARAMETER_BOUND:
+        case TARGET_THROWS:
+        case TARGET_EXCEPTION_PARAMETER:
+        case TARGET_INSTANCEOF:
+        case TARGET_NEW:
+        case TARGET_CONSTRUCTOR_REFERENCE:
+        case TARGET_METHOD_REFERENCE:
+            return 2;
+        case TARGET_FIELD:
+        case TARGET_METHOD_RETURN:
+        case TARGET_METHOD_RECEIVER:
+            return 0;
+        case TARGET_LOCAL_VARIABLE:
+        case TARGET_RESOURCE_VARIABLE:
+            return -1;
+        case TARGET_CAST:
+        case TARGET_CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
+        case TARGET_METHOD_INVOCATION_TYPE_ARGUMENT:
+        case TARGET_CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
+        case TARGET_METHOD_REFERENCE_TYPE_ARGUMENT:
+            return 3;
+        default:
+            throw new ClassFormatException("Invalid type annotation target 
type: 0x" + Integer.toHexString(targetType));
+        }
+    }
+
     private final int targetType;
 
     private final byte[] targetInfo;
@@ -291,18 +291,13 @@ public class TypeAnnotationEntry {
     }
 
     /**
-     * Gets the number of steps in the type path.
-     *
-     * <p>
-     * The path leads from the type of the target to the part of it that is 
annotated. An empty path identifies the outermost part of the type where an
-     * annotation is allowed. For a non-static inner class, {@code @A 
Outer.Inner} has an empty path, while {@code Outer.@A Inner} requires one step.
-     * For a static nested class, {@code Outer.@A Nested} has an empty path.
-     * </p>
+     * Gets the index of the type argument for a step of the type path of kind 
3, else 0.
      *
-     * @return The number of steps of the type path.
+     * @param step Index of the step, from 0 to {@link #getTypePathLength()} 
excluded.
+     * @return The index of the type argument.
      */
-    public int getTypePathLength() {
-        return typePath.length / 2;
+    public int getTypePathArgumentIndex(final int step) {
+        return typePath[step * 2 + 1] & 0xFF;
     }
 
     /**
@@ -317,13 +312,18 @@ public class TypeAnnotationEntry {
     }
 
     /**
-     * Gets the index of the type argument for a step of the type path of kind 
3, else 0.
+     * Gets the number of steps in the type path.
      *
-     * @param step Index of the step, from 0 to {@link #getTypePathLength()} 
excluded.
-     * @return The index of the type argument.
+     * <p>
+     * The path leads from the type of the target to the part of it that is 
annotated. An empty path identifies the outermost part of the type where an
+     * annotation is allowed. For a non-static inner class, {@code @A 
Outer.Inner} has an empty path, while {@code Outer.@A Inner} requires one step.
+     * For a static nested class, {@code Outer.@A Nested} has an empty path.
+     * </p>
+     *
+     * @return The number of steps of the type path.
      */
-    public int getTypePathArgumentIndex(final int step) {
-        return typePath[step * 2 + 1] & 0xFF;
+    public int getTypePathLength() {
+        return typePath.length / 2;
     }
 
     @Override
diff --git a/src/main/java/org/apache/bcel/classfile/TypeAnnotations.java 
b/src/main/java/org/apache/bcel/classfile/TypeAnnotations.java
index aa13deaf..4ffc4aaa 100644
--- a/src/main/java/org/apache/bcel/classfile/TypeAnnotations.java
+++ b/src/main/java/org/apache/bcel/classfile/TypeAnnotations.java
@@ -48,15 +48,19 @@ public abstract class TypeAnnotations extends Attribute 
implements Iterable<Type
      * @param annotationType The subclass type of the attribute.
      * @param nameIndex Index pointing to the name of the attribute.
      * @param length Content length in bytes.
-     * @param typeAnnotationTable The actual type annotations.
+     * @param input Input stream.
      * @param constantPool Array of constants.
      * @param isRuntimeVisible whether the annotations are visible at runtime.
+     * @throws IOException Thrown if an I/O error occurs.
      */
-    public TypeAnnotations(final byte annotationType, final int nameIndex, 
final int length, final TypeAnnotationEntry[] typeAnnotationTable,
-            final ConstantPool constantPool, final boolean isRuntimeVisible) {
-        super(annotationType, nameIndex, length, constantPool);
-        setTypeAnnotationTable(typeAnnotationTable);
-        this.isRuntimeVisible = isRuntimeVisible;
+    TypeAnnotations(final byte annotationType, final int nameIndex, final int 
length, final DataInput input, final ConstantPool constantPool,
+            final boolean isRuntimeVisible) throws IOException {
+        this(annotationType, nameIndex, length, (TypeAnnotationEntry[]) null, 
constantPool, isRuntimeVisible);
+        final int tableLength = input.readUnsignedShort();
+        typeAnnotationTable = new TypeAnnotationEntry[tableLength];
+        for (int i = 0; i < tableLength; i++) {
+            typeAnnotationTable[i] = TypeAnnotationEntry.read(input, 
constantPool, isRuntimeVisible);
+        }
     }
 
     /**
@@ -65,19 +69,15 @@ public abstract class TypeAnnotations extends Attribute 
implements Iterable<Type
      * @param annotationType The subclass type of the attribute.
      * @param nameIndex Index pointing to the name of the attribute.
      * @param length Content length in bytes.
-     * @param input Input stream.
+     * @param typeAnnotationTable The actual type annotations.
      * @param constantPool Array of constants.
      * @param isRuntimeVisible whether the annotations are visible at runtime.
-     * @throws IOException Thrown if an I/O error occurs.
      */
-    TypeAnnotations(final byte annotationType, final int nameIndex, final int 
length, final DataInput input, final ConstantPool constantPool,
-            final boolean isRuntimeVisible) throws IOException {
-        this(annotationType, nameIndex, length, (TypeAnnotationEntry[]) null, 
constantPool, isRuntimeVisible);
-        final int tableLength = input.readUnsignedShort();
-        typeAnnotationTable = new TypeAnnotationEntry[tableLength];
-        for (int i = 0; i < tableLength; i++) {
-            typeAnnotationTable[i] = TypeAnnotationEntry.read(input, 
constantPool, isRuntimeVisible);
-        }
+    public TypeAnnotations(final byte annotationType, final int nameIndex, 
final int length, final TypeAnnotationEntry[] typeAnnotationTable,
+            final ConstantPool constantPool, final boolean isRuntimeVisible) {
+        super(annotationType, nameIndex, length, constantPool);
+        setTypeAnnotationTable(typeAnnotationTable);
+        this.isRuntimeVisible = isRuntimeVisible;
     }
 
     @Override
diff --git a/src/main/java/org/apache/bcel/classfile/Visitor.java 
b/src/main/java/org/apache/bcel/classfile/Visitor.java
index 6c8608af..b49aadb5 100644
--- a/src/main/java/org/apache/bcel/classfile/Visitor.java
+++ b/src/main/java/org/apache/bcel/classfile/Visitor.java
@@ -437,16 +437,6 @@ public interface Visitor {
         // empty
     }
 
-    /**
-     * Visits a RuntimeVisibleTypeAnnotations or 
RuntimeInvisibleTypeAnnotations attribute.
-     *
-     * @param obj The attribute.
-     * @since 6.14.0
-     */
-    default void visitTypeAnnotations(final TypeAnnotations obj) {
-        // empty
-    }
-
     /**
      * Visits a {@link Record} object.
      *
@@ -512,6 +502,16 @@ public interface Visitor {
      */
     void visitSynthetic(Synthetic obj);
 
+    /**
+     * Visits a RuntimeVisibleTypeAnnotations or 
RuntimeInvisibleTypeAnnotations attribute.
+     *
+     * @param obj The attribute.
+     * @since 6.14.0
+     */
+    default void visitTypeAnnotations(final TypeAnnotations obj) {
+        // empty
+    }
+
     /**
      * Visits an Unknown attribute.
      *
diff --git 
a/src/main/java/org/apache/bcel/verifier/statics/StringRepresentation.java 
b/src/main/java/org/apache/bcel/verifier/statics/StringRepresentation.java
index 8819b4f0..8ded2ae5 100644
--- a/src/main/java/org/apache/bcel/verifier/statics/StringRepresentation.java
+++ b/src/main/java/org/apache/bcel/verifier/statics/StringRepresentation.java
@@ -413,16 +413,6 @@ public class StringRepresentation extends 
org.apache.bcel.classfile.EmptyVisitor
         tostring = toString(obj);
     }
 
-    /**
-     * Visits RuntimeVisibleTypeAnnotations and 
RuntimeInvisibleTypeAnnotations attributes.
-     *
-     * @since 6.14.0
-     */
-    @Override
-    public void visitTypeAnnotations(final TypeAnnotations obj) {
-        tostring = toString(obj);
-    }
-
     @Override
     public void visitRecord(final Record obj) {
         tostring = toString(obj);
@@ -461,6 +451,16 @@ public class StringRepresentation extends 
org.apache.bcel.classfile.EmptyVisitor
         tostring = toString(obj);
     }
 
+    /**
+     * Visits RuntimeVisibleTypeAnnotations and 
RuntimeInvisibleTypeAnnotations attributes.
+     *
+     * @since 6.14.0
+     */
+    @Override
+    public void visitTypeAnnotations(final TypeAnnotations obj) {
+        tostring = toString(obj);
+    }
+
     @Override
     public void visitUnknown(final Unknown obj) {
         tostring = toString(obj);
diff --git 
a/src/test/java/org/apache/bcel/classfile/TypeAnnotationAttributesTest.java 
b/src/test/java/org/apache/bcel/classfile/TypeAnnotationAttributesTest.java
index 8dfad67b..301d4477 100644
--- a/src/test/java/org/apache/bcel/classfile/TypeAnnotationAttributesTest.java
+++ b/src/test/java/org/apache/bcel/classfile/TypeAnnotationAttributesTest.java
@@ -151,29 +151,6 @@ class TypeAnnotationAttributesTest {
         assertEquals(2, original.getNumTypeAnnotations());
     }
 
-    @ParameterizedTest
-    @ValueSource(booleans = {false, true})
-    void readsEmptyAttributes(final boolean visible) throws IOException {
-        final Fixture fixture = new Fixture(visible);
-        final byte[] encoded = fixture.annotationAttribute(0x13, new byte[0], 
0);
-        final TypeAnnotations annotations = (TypeAnnotations) parse(encoded, 
fixture.pool);
-        assertEquals(0, annotations.getNumTypeAnnotations());
-        assertFalse(annotations.iterator().hasNext());
-        assertArrayEquals(encoded, dump(annotations));
-        assertArrayEquals(encoded, 
dump(annotations.copy(fixture.pool.copy())));
-    }
-
-    @ParameterizedTest
-    @ValueSource(booleans = {false, true})
-    void rejectsTruncatedAttributes(final boolean visible) throws IOException {
-        final Fixture fixture = new Fixture(visible);
-        final byte[] encoded = fixture.annotationAttribute(0x13, new byte[0], 
2);
-        for (int length = 0; length < encoded.length; length++) {
-            final byte[] truncated = Arrays.copyOf(encoded, length);
-            assertThrows(EOFException.class, () -> parse(truncated, 
fixture.pool), "length " + length);
-        }
-    }
-
     @ParameterizedTest
     @ValueSource(booleans = {false, true})
     void enforcesTheUnsignedAnnotationCount(final boolean visible) throws 
IOException {
@@ -191,6 +168,18 @@ class TypeAnnotationAttributesTest {
         assertThrows(ClassFormatException.class, () -> dump(annotations));
     }
 
+    @ParameterizedTest
+    @ValueSource(booleans = {false, true})
+    void readsEmptyAttributes(final boolean visible) throws IOException {
+        final Fixture fixture = new Fixture(visible);
+        final byte[] encoded = fixture.annotationAttribute(0x13, new byte[0], 
0);
+        final TypeAnnotations annotations = (TypeAnnotations) parse(encoded, 
fixture.pool);
+        assertEquals(0, annotations.getNumTypeAnnotations());
+        assertFalse(annotations.iterator().hasNext());
+        assertArrayEquals(encoded, dump(annotations));
+        assertArrayEquals(encoded, 
dump(annotations.copy(fixture.pool.copy())));
+    }
+
     @ParameterizedTest
     @ValueSource(booleans = {false, true})
     void readsTypeAnnotationsInsideCode(final boolean visible) throws 
IOException {
@@ -242,4 +231,15 @@ class TypeAnnotationAttributesTest {
         assertEquals(0x13, 
annotations.getTypeAnnotationEntries()[0].getTargetType());
         assertArrayEquals(encoded, dump(record));
     }
+
+    @ParameterizedTest
+    @ValueSource(booleans = {false, true})
+    void rejectsTruncatedAttributes(final boolean visible) throws IOException {
+        final Fixture fixture = new Fixture(visible);
+        final byte[] encoded = fixture.annotationAttribute(0x13, new byte[0], 
2);
+        for (int length = 0; length < encoded.length; length++) {
+            final byte[] truncated = Arrays.copyOf(encoded, length);
+            assertThrows(EOFException.class, () -> parse(truncated, 
fixture.pool), "length " + length);
+        }
+    }
 }
diff --git 
a/src/test/java/org/apache/bcel/classfile/TypeAnnotationEntryTest.java 
b/src/test/java/org/apache/bcel/classfile/TypeAnnotationEntryTest.java
index a938e597..76bf2100 100644
--- a/src/test/java/org/apache/bcel/classfile/TypeAnnotationEntryTest.java
+++ b/src/test/java/org/apache/bcel/classfile/TypeAnnotationEntryTest.java
@@ -108,6 +108,67 @@ class TypeAnnotationEntryTest {
                 
Arguments.of(TypeAnnotationEntry.TARGET_METHOD_REFERENCE_TYPE_ARGUMENT, 0x4B, 
new byte[] {19, 20, (byte) 255}));
     }
 
+    @ParameterizedTest
+    @ValueSource(booleans = {false, true})
+    void deeplyCopiesNestedAnnotationValues(final boolean visible) throws 
IOException {
+        final ConstantPoolGen gen = new ConstantPoolGen();
+        final int type = gen.addUtf8("Lexample/Annotation;");
+        final int nestedType = gen.addUtf8("Lexample/Nested;");
+        final int arrayName = gen.addUtf8("items");
+        final int nestedName = gen.addUtf8("nested");
+        final int valueName = gen.addUtf8("value");
+        final int first = gen.addUtf8("first");
+        final int second = gen.addUtf8("second");
+        final ConstantPool pool = gen.getFinalConstantPool();
+        final AnnotationEntry nested = new AnnotationEntry(nestedType, pool, 
visible);
+        nested.addElementNameValuePair(new ElementValuePair(valueName, new 
SimpleElementValue(ElementValue.STRING, first, pool), pool));
+        final AnnotationEntry annotation = new AnnotationEntry(type, pool, 
visible);
+        annotation.addElementNameValuePair(new ElementValuePair(arrayName, new 
ArrayElementValue(ElementValue.ARRAY,
+                new ElementValue[] {new 
SimpleElementValue(ElementValue.STRING, first, pool)}, pool), pool));
+        annotation.addElementNameValuePair(new ElementValuePair(nestedName, 
new AnnotationElementValue(ElementValue.ANNOTATION, nested, pool), pool));
+        final TypeAnnotationEntry original = new TypeAnnotationEntry(0x13, new 
byte[0], TYPE_PATH, annotation);
+        final byte[] expected = dump(original);
+        final ConstantPool otherPool = pool.copy();
+        final TypeAnnotationEntry copy = original.copy(otherPool);
+        assertArrayEquals(expected, dump(copy));
+        assertNotSame(original, copy);
+        assertNotSame(annotation, copy.getAnnotationEntry());
+        assertSame(otherPool, copy.getAnnotationEntry().getConstantPool());
+        assertEquals(visible, copy.getAnnotationEntry().isRuntimeVisible());
+        final ElementValuePair[] copiedPairs = 
copy.getAnnotationEntry().getElementValuePairs();
+        final ArrayElementValue array = (ArrayElementValue) 
copiedPairs[0].getValue();
+        final AnnotationEntry copiedNested = ((AnnotationElementValue) 
copiedPairs[1].getValue()).getAnnotationEntry();
+        assertNotSame(annotation.getElementValuePairs()[0], copiedPairs[0]);
+        assertNotSame(((ArrayElementValue) 
annotation.getElementValuePairs()[0].getValue()).getElementValuesArray(), 
array.getElementValuesArray());
+        assertNotSame(nested, copiedNested);
+        assertSame(otherPool, array.getConstantPool());
+        assertSame(otherPool, 
array.getElementValuesArray()[0].getConstantPool());
+        assertSame(otherPool, copiedNested.getConstantPool());
+        assertSame(otherPool, 
copiedNested.getElementValuePairs()[0].getValue().getConstantPool());
+        assertEquals(visible, copiedNested.isRuntimeVisible());
+        ((SimpleElementValue) 
array.getElementValuesArray()[0]).setIndex(second);
+        ((SimpleElementValue) 
copiedNested.getElementValuePairs()[0].getValue()).setIndex(second);
+        assertEquals("second", 
array.getElementValuesArray()[0].stringifyValue());
+        assertEquals("second", 
copiedNested.getElementValuePairs()[0].getValue().stringifyValue());
+        assertArrayEquals(expected, dump(original), "Mutating nested copied 
values must not change the original");
+    }
+
+    @Test
+    void protectsTargetInfoAndPathFromCallerMutation() throws IOException {
+        final byte[] info = {0, 2};
+        final byte[] path = {3, 1};
+        final TypeAnnotationEntry entry = new TypeAnnotationEntry(0x10, info, 
path, new AnnotationEntry(1, constantPool(), true));
+        info[0] = 99;
+        path[0] = 99;
+        path[1] = 99;
+        final byte[] returnedInfo = entry.getTargetInfo();
+        returnedInfo[0] = 88;
+        assertArrayEquals(new byte[] {0, 2}, entry.getTargetInfo());
+        assertEquals(3, entry.getTypePathKind(0));
+        assertEquals(1, entry.getTypePathArgumentIndex(0));
+        assertArrayEquals(encodedEntry(0x10, new byte[] {0, 2}, new byte[] {3, 
1}), dump(entry));
+    }
+
     @ParameterizedTest
     @MethodSource("targetLayouts")
     void readsAndDumpsEveryTargetLayout(final int targetConstant, final int 
tag, final byte[] info) throws IOException {
@@ -143,29 +204,6 @@ class TypeAnnotationEntryTest {
         assertArrayEquals(expected, dump(entry));
     }
 
-    @ParameterizedTest
-    @MethodSource("targetLayouts")
-    void rejectsTruncatedEntries(final int targetConstant, final int tag, 
final byte[] info) throws IOException {
-        final byte[] bytes = encodedEntry(tag, info, TYPE_PATH);
-        for (int length = 0; length < bytes.length; length++) {
-            final byte[] truncated = Arrays.copyOf(bytes, length);
-            assertThrows(EOFException.class, () -> read(truncated, true), 
"target " + targetConstant + ", length " + length);
-        }
-    }
-
-    @ParameterizedTest
-    @MethodSource("targetLayouts")
-    void rejectsIncorrectTargetInfoLengths(final int targetConstant, final int 
tag, final byte[] info) {
-        final AnnotationEntry annotation = new AnnotationEntry(1, 
constantPool(), true);
-        assertEquals(tag, targetConstant);
-        assertThrows(IllegalArgumentException.class,
-                () -> new TypeAnnotationEntry(targetConstant, 
Arrays.copyOf(info, info.length + 1), new byte[0], annotation));
-        if (info.length > 0) {
-            assertThrows(IllegalArgumentException.class,
-                    () -> new TypeAnnotationEntry(targetConstant, 
Arrays.copyOf(info, info.length - 1), new byte[0], annotation));
-        }
-    }
-
     @ParameterizedTest
     @ValueSource(ints = {0, 1, 255, 256, 65535})
     void readsUnsignedLocalVariableTableLengths(final int ranges) throws 
IOException {
@@ -193,16 +231,16 @@ class TypeAnnotationEntryTest {
     }
 
     @ParameterizedTest
-    @ValueSource(ints = {-1, 2, 15, 24, 63, 76, 127, 255, 256})
-    void rejectsUndefinedConstructorTargets(final int target) {
-        assertThrows(ClassFormatException.class, () -> new 
TypeAnnotationEntry(target, new byte[0], new byte[0], null));
-    }
-
-    @ParameterizedTest
-    @ValueSource(ints = {2, 15, 24, 63, 76, 127, 255})
-    void rejectsUndefinedEncodedTargets(final int target) throws IOException {
-        final byte[] bytes = encodedEntry(target, new byte[0], new byte[0]);
-        assertThrows(ClassFormatException.class, () -> read(bytes, true));
+    @MethodSource("targetLayouts")
+    void rejectsIncorrectTargetInfoLengths(final int targetConstant, final int 
tag, final byte[] info) {
+        final AnnotationEntry annotation = new AnnotationEntry(1, 
constantPool(), true);
+        assertEquals(tag, targetConstant);
+        assertThrows(IllegalArgumentException.class,
+                () -> new TypeAnnotationEntry(targetConstant, 
Arrays.copyOf(info, info.length + 1), new byte[0], annotation));
+        if (info.length > 0) {
+            assertThrows(IllegalArgumentException.class,
+                    () -> new TypeAnnotationEntry(targetConstant, 
Arrays.copyOf(info, info.length - 1), new byte[0], annotation));
+        }
     }
 
     @ParameterizedTest
@@ -214,65 +252,27 @@ class TypeAnnotationEntryTest {
         }
     }
 
-    @Test
-    void protectsTargetInfoAndPathFromCallerMutation() throws IOException {
-        final byte[] info = {0, 2};
-        final byte[] path = {3, 1};
-        final TypeAnnotationEntry entry = new TypeAnnotationEntry(0x10, info, 
path, new AnnotationEntry(1, constantPool(), true));
-        info[0] = 99;
-        path[0] = 99;
-        path[1] = 99;
-        final byte[] returnedInfo = entry.getTargetInfo();
-        returnedInfo[0] = 88;
-        assertArrayEquals(new byte[] {0, 2}, entry.getTargetInfo());
-        assertEquals(3, entry.getTypePathKind(0));
-        assertEquals(1, entry.getTypePathArgumentIndex(0));
-        assertArrayEquals(encodedEntry(0x10, new byte[] {0, 2}, new byte[] {3, 
1}), dump(entry));
+    @ParameterizedTest
+    @MethodSource("targetLayouts")
+    void rejectsTruncatedEntries(final int targetConstant, final int tag, 
final byte[] info) throws IOException {
+        final byte[] bytes = encodedEntry(tag, info, TYPE_PATH);
+        for (int length = 0; length < bytes.length; length++) {
+            final byte[] truncated = Arrays.copyOf(bytes, length);
+            assertThrows(EOFException.class, () -> read(truncated, true), 
"target " + targetConstant + ", length " + length);
+        }
     }
 
     @ParameterizedTest
-    @ValueSource(booleans = {false, true})
-    void deeplyCopiesNestedAnnotationValues(final boolean visible) throws 
IOException {
-        final ConstantPoolGen gen = new ConstantPoolGen();
-        final int type = gen.addUtf8("Lexample/Annotation;");
-        final int nestedType = gen.addUtf8("Lexample/Nested;");
-        final int arrayName = gen.addUtf8("items");
-        final int nestedName = gen.addUtf8("nested");
-        final int valueName = gen.addUtf8("value");
-        final int first = gen.addUtf8("first");
-        final int second = gen.addUtf8("second");
-        final ConstantPool pool = gen.getFinalConstantPool();
-        final AnnotationEntry nested = new AnnotationEntry(nestedType, pool, 
visible);
-        nested.addElementNameValuePair(new ElementValuePair(valueName, new 
SimpleElementValue(ElementValue.STRING, first, pool), pool));
-        final AnnotationEntry annotation = new AnnotationEntry(type, pool, 
visible);
-        annotation.addElementNameValuePair(new ElementValuePair(arrayName, new 
ArrayElementValue(ElementValue.ARRAY,
-                new ElementValue[] {new 
SimpleElementValue(ElementValue.STRING, first, pool)}, pool), pool));
-        annotation.addElementNameValuePair(new ElementValuePair(nestedName, 
new AnnotationElementValue(ElementValue.ANNOTATION, nested, pool), pool));
-        final TypeAnnotationEntry original = new TypeAnnotationEntry(0x13, new 
byte[0], TYPE_PATH, annotation);
-        final byte[] expected = dump(original);
-        final ConstantPool otherPool = pool.copy();
-        final TypeAnnotationEntry copy = original.copy(otherPool);
-        assertArrayEquals(expected, dump(copy));
-        assertNotSame(original, copy);
-        assertNotSame(annotation, copy.getAnnotationEntry());
-        assertSame(otherPool, copy.getAnnotationEntry().getConstantPool());
-        assertEquals(visible, copy.getAnnotationEntry().isRuntimeVisible());
-        final ElementValuePair[] copiedPairs = 
copy.getAnnotationEntry().getElementValuePairs();
-        final ArrayElementValue array = (ArrayElementValue) 
copiedPairs[0].getValue();
-        final AnnotationEntry copiedNested = ((AnnotationElementValue) 
copiedPairs[1].getValue()).getAnnotationEntry();
-        assertNotSame(annotation.getElementValuePairs()[0], copiedPairs[0]);
-        assertNotSame(((ArrayElementValue) 
annotation.getElementValuePairs()[0].getValue()).getElementValuesArray(), 
array.getElementValuesArray());
-        assertNotSame(nested, copiedNested);
-        assertSame(otherPool, array.getConstantPool());
-        assertSame(otherPool, 
array.getElementValuesArray()[0].getConstantPool());
-        assertSame(otherPool, copiedNested.getConstantPool());
-        assertSame(otherPool, 
copiedNested.getElementValuePairs()[0].getValue().getConstantPool());
-        assertEquals(visible, copiedNested.isRuntimeVisible());
-        ((SimpleElementValue) 
array.getElementValuesArray()[0]).setIndex(second);
-        ((SimpleElementValue) 
copiedNested.getElementValuePairs()[0].getValue()).setIndex(second);
-        assertEquals("second", 
array.getElementValuesArray()[0].stringifyValue());
-        assertEquals("second", 
copiedNested.getElementValuePairs()[0].getValue().stringifyValue());
-        assertArrayEquals(expected, dump(original), "Mutating nested copied 
values must not change the original");
+    @ValueSource(ints = {-1, 2, 15, 24, 63, 76, 127, 255, 256})
+    void rejectsUndefinedConstructorTargets(final int target) {
+        assertThrows(ClassFormatException.class, () -> new 
TypeAnnotationEntry(target, new byte[0], new byte[0], null));
+    }
+
+    @ParameterizedTest
+    @ValueSource(ints = {2, 15, 24, 63, 76, 127, 255})
+    void rejectsUndefinedEncodedTargets(final int target) throws IOException {
+        final byte[] bytes = encodedEntry(target, new byte[0], new byte[0]);
+        assertThrows(ClassFormatException.class, () -> read(bytes, true));
     }
 
     @Test
diff --git a/src/test/java/org/apache/bcel/classfile/TypeAnnotationsTest.java 
b/src/test/java/org/apache/bcel/classfile/TypeAnnotationsTest.java
index bda0a3ce..c1c857ac 100644
--- a/src/test/java/org/apache/bcel/classfile/TypeAnnotationsTest.java
+++ b/src/test/java/org/apache/bcel/classfile/TypeAnnotationsTest.java
@@ -55,19 +55,6 @@ import org.junit.jupiter.api.Test;
  */
 class TypeAnnotationsTest {
 
-    @Target(ElementType.TYPE_USE)
-    @Retention(RetentionPolicy.RUNTIME)
-    @interface TypeUse {
-    }
-
-    static class Outer {
-        class Inner {
-        }
-
-        static class Nested {
-        }
-    }
-
     static class AnnotatedTypes {
         @TypeUse Outer.Inner outer;
         Outer.@TypeUse Inner inner;
@@ -80,6 +67,19 @@ class TypeAnnotationsTest {
         }
     }
 
+    static class Outer {
+        class Inner {
+        }
+
+        static class Nested {
+        }
+    }
+
+    @Target(ElementType.TYPE_USE)
+    @Retention(RetentionPolicy.RUNTIME)
+    @interface TypeUse {
+    }
+
     private static final String CLASS_FILE = 
"src/test/resources/typeannotations/TypeAnnotated.class";
 
     private static JavaClass annotatedTypes() throws IOException {
@@ -90,101 +90,20 @@ class TypeAnnotationsTest {
         }
     }
 
-    private static JavaClass parse() throws IOException {
-        return new ClassParser(CLASS_FILE).parse();
-    }
-
-    private static TypeAnnotations typeAnnotationsOf(final FieldOrMethod 
member, final byte tag) {
-        return (TypeAnnotations) Stream.of(member.getAttributes()).filter(a -> 
a.getTag() == tag).findFirst().orElse(null);
-    }
-
-    private static Method method(final JavaClass clazz, final String name) {
-        return Stream.of(clazz.getMethods()).filter(m -> 
m.getName().equals(name)).findFirst().orElseThrow(AssertionError::new);
-    }
-
     private static Field field(final JavaClass clazz, final String name) {
         return Stream.of(clazz.getFields()).filter(f -> 
f.getName().equals(name)).findFirst().orElseThrow(AssertionError::new);
     }
 
-    @Test
-    void readsTheTypeAnnotationOfAField() throws IOException {
-        final TypeAnnotations annotations = typeAnnotationsOf(field(parse(), 
"field"), Const.ATTR_RUNTIME_VISIBLE_TYPE_ANNOTATIONS);
-        assertNotNull(annotations);
-        assertTrue(annotations instanceof RuntimeVisibleTypeAnnotations);
-        assertTrue(annotations.isRuntimeVisible());
-        assertEquals(1, annotations.getNumTypeAnnotations());
-        final TypeAnnotationEntry entry = 
annotations.getTypeAnnotationEntries()[0];
-        assertEquals(TypeAnnotationEntry.TARGET_FIELD, entry.getTargetType());
-        assertEquals(0, entry.getTargetInfo().length);
-        assertEquals(0, entry.getTypePathLength());
-        assertEquals("Ltypeannotations/Visible;", 
entry.getAnnotationEntry().getAnnotationType());
-    }
-
-    @Test
-    void readsTheTypePathOfATypeArgument() throws IOException {
-        final TypeAnnotations annotations = typeAnnotationsOf(field(parse(), 
"items"), Const.ATTR_RUNTIME_VISIBLE_TYPE_ANNOTATIONS);
-        final TypeAnnotationEntry entry = 
annotations.getTypeAnnotationEntries()[0];
-        assertEquals(TypeAnnotationEntry.TARGET_FIELD, entry.getTargetType());
-        assertEquals(1, entry.getTypePathLength());
-        // a type argument of the parameterized type, the first one
-        assertEquals(3, entry.getTypePathKind(0));
-        assertEquals(0, entry.getTypePathArgumentIndex(0));
-    }
-
-    @Test
-    void readsTheInvisibleAttribute() throws IOException {
-        final Field hidden = field(parse(), "hidden");
-        assertNull(typeAnnotationsOf(hidden, 
Const.ATTR_RUNTIME_VISIBLE_TYPE_ANNOTATIONS));
-        final TypeAnnotations annotations = typeAnnotationsOf(hidden, 
Const.ATTR_RUNTIME_INVISIBLE_TYPE_ANNOTATIONS);
-        assertTrue(annotations instanceof RuntimeInvisibleTypeAnnotations);
-        assertFalse(annotations.isRuntimeVisible());
-        assertEquals("Ltypeannotations/Invisible;", 
annotations.getTypeAnnotationEntries()[0].getAnnotationEntry().getAnnotationType());
-    }
-
-    @Test
-    void readsTheTargetsOfAMethod() throws IOException {
-        final TypeAnnotations annotations = typeAnnotationsOf(method(parse(), 
"find"), Const.ATTR_RUNTIME_VISIBLE_TYPE_ANNOTATIONS);
-        final List<Integer> targets = new ArrayList<>();
-        for (final TypeAnnotationEntry entry : annotations) {
-            targets.add(entry.getTargetType());
-            if (entry.getTargetType() == 
TypeAnnotationEntry.TARGET_METHOD_FORMAL_PARAMETER) {
-                // the index of the parameter
-                assertArrayEquals(new byte[] {0}, entry.getTargetInfo());
-            }
-        }
-        assertTrue(targets.contains(TypeAnnotationEntry.TARGET_METHOD_RETURN));
-        
assertTrue(targets.contains(TypeAnnotationEntry.TARGET_METHOD_FORMAL_PARAMETER));
+    private static Method method(final JavaClass clazz, final String name) {
+        return Stream.of(clazz.getMethods()).filter(m -> 
m.getName().equals(name)).findFirst().orElseThrow(AssertionError::new);
     }
 
-    @Test
-    void readsTheBoundOfATypeParameterOfTheClass() throws IOException {
-        final JavaClass clazz = parse();
-        final TypeAnnotations annotations = (TypeAnnotations) 
Stream.of(clazz.getAttributes())
-                .filter(a -> a.getTag() == 
Const.ATTR_RUNTIME_VISIBLE_TYPE_ANNOTATIONS).findFirst().orElse(null);
-        assertNotNull(annotations);
-        final TypeAnnotationEntry entry = 
annotations.getTypeAnnotationEntries()[0];
-        assertEquals(TypeAnnotationEntry.TARGET_CLASS_TYPE_PARAMETER_BOUND, 
entry.getTargetType());
-        // the first type parameter, its first bound
-        assertArrayEquals(new byte[] {0, 0}, entry.getTargetInfo());
+    private static JavaClass parse() throws IOException {
+        return new ClassParser(CLASS_FILE).parse();
     }
 
-    @Test
-    void dumpsWhatItReads() throws IOException {
-        final JavaClass clazz = parse();
-        final ByteArrayOutputStream out = new ByteArrayOutputStream();
-        try (DataOutputStream dos = new DataOutputStream(out)) {
-            clazz.dump(dos);
-        }
-        assertArrayEquals(Files.readAllBytes(Paths.get(CLASS_FILE)), 
out.toByteArray());
-        final JavaClass reread = new ClassParser(new 
ByteArrayInputStream(out.toByteArray()), CLASS_FILE).parse();
-        for (final String name : new String[] {"field", "items", "hidden"}) {
-            final Field original = field(clazz, name);
-            final Field copy = field(reread, name);
-            assertEquals(original.getAttributes().length, 
copy.getAttributes().length);
-            for (int i = 0; i < original.getAttributes().length; i++) {
-                assertEquals(original.getAttributes()[i].toString(), 
copy.getAttributes()[i].toString());
-            }
-        }
+    private static TypeAnnotations typeAnnotationsOf(final FieldOrMethod 
member, final byte tag) {
+        return (TypeAnnotations) Stream.of(member.getAttributes()).filter(a -> 
a.getTag() == tag).findFirst().orElse(null);
     }
 
     @Test
@@ -223,6 +142,58 @@ class TypeAnnotationsTest {
         assertEquals(original.toString(), copy.toString());
     }
 
+    @Test
+    void distinguishesInnerClassesFromStaticNestedClasses() throws IOException 
{
+        final JavaClass clazz = annotatedTypes();
+        final TypeAnnotationEntry outer = typeAnnotationsOf(field(clazz, 
"outer"), 
Const.ATTR_RUNTIME_VISIBLE_TYPE_ANNOTATIONS).getTypeAnnotationEntries()[0];
+        final TypeAnnotationEntry inner = typeAnnotationsOf(field(clazz, 
"inner"), 
Const.ATTR_RUNTIME_VISIBLE_TYPE_ANNOTATIONS).getTypeAnnotationEntries()[0];
+        final TypeAnnotationEntry nested = typeAnnotationsOf(field(clazz, 
"nested"), 
Const.ATTR_RUNTIME_VISIBLE_TYPE_ANNOTATIONS).getTypeAnnotationEntries()[0];
+        assertEquals(0, outer.getTypePathLength());
+        assertEquals(1, inner.getTypePathLength());
+        assertEquals(1, inner.getTypePathKind(0));
+        assertEquals(0, inner.getTypePathArgumentIndex(0));
+        assertEquals(0, nested.getTypePathLength());
+    }
+
+    @Test
+    void dumpsWhatItReads() throws IOException {
+        final JavaClass clazz = parse();
+        final ByteArrayOutputStream out = new ByteArrayOutputStream();
+        try (DataOutputStream dos = new DataOutputStream(out)) {
+            clazz.dump(dos);
+        }
+        assertArrayEquals(Files.readAllBytes(Paths.get(CLASS_FILE)), 
out.toByteArray());
+        final JavaClass reread = new ClassParser(new 
ByteArrayInputStream(out.toByteArray()), CLASS_FILE).parse();
+        for (final String name : new String[] {"field", "items", "hidden"}) {
+            final Field original = field(clazz, name);
+            final Field copy = field(reread, name);
+            assertEquals(original.getAttributes().length, 
copy.getAttributes().length);
+            for (int i = 0; i < original.getAttributes().length; i++) {
+                assertEquals(original.getAttributes()[i].toString(), 
copy.getAttributes()[i].toString());
+            }
+        }
+    }
+
+    @Test
+    void followsTypeArgumentsWildcardBoundsAndArrayElements() throws 
IOException {
+        final TypeAnnotationEntry entry = 
typeAnnotationsOf(field(annotatedTypes(), "wildcard"), 
Const.ATTR_RUNTIME_VISIBLE_TYPE_ANNOTATIONS)
+                .getTypeAnnotationEntries()[0];
+        assertEquals(3, entry.getTypePathLength());
+        assertEquals(3, entry.getTypePathKind(0));
+        assertEquals(2, entry.getTypePathKind(1));
+        assertEquals(0, entry.getTypePathKind(2));
+        for (int step = 0; step < 3; step++) {
+            assertEquals(0, entry.getTypePathArgumentIndex(step));
+        }
+    }
+
+    @Test
+    void isRepresented() throws IOException {
+        final JavaClass clazz = parse();
+        final StringRepresentation representation = new 
StringRepresentation(typeAnnotationsOf(field(clazz, "field"), 
Const.ATTR_RUNTIME_VISIBLE_TYPE_ANNOTATIONS));
+        
assertTrue(representation.toString().contains("RuntimeVisibleTypeAnnotations"), 
representation.toString());
+    }
+
     @Test
     void isVisitedWithItsAnnotations() throws IOException {
         final JavaClass clazz = parse();
@@ -250,10 +221,25 @@ class TypeAnnotationsTest {
     }
 
     @Test
-    void isRepresented() throws IOException {
+    void readsTheBoundOfATypeParameterOfTheClass() throws IOException {
         final JavaClass clazz = parse();
-        final StringRepresentation representation = new 
StringRepresentation(typeAnnotationsOf(field(clazz, "field"), 
Const.ATTR_RUNTIME_VISIBLE_TYPE_ANNOTATIONS));
-        
assertTrue(representation.toString().contains("RuntimeVisibleTypeAnnotations"), 
representation.toString());
+        final TypeAnnotations annotations = (TypeAnnotations) 
Stream.of(clazz.getAttributes())
+                .filter(a -> a.getTag() == 
Const.ATTR_RUNTIME_VISIBLE_TYPE_ANNOTATIONS).findFirst().orElse(null);
+        assertNotNull(annotations);
+        final TypeAnnotationEntry entry = 
annotations.getTypeAnnotationEntries()[0];
+        assertEquals(TypeAnnotationEntry.TARGET_CLASS_TYPE_PARAMETER_BOUND, 
entry.getTargetType());
+        // the first type parameter, its first bound
+        assertArrayEquals(new byte[] {0, 0}, entry.getTargetInfo());
+    }
+
+    @Test
+    void readsTheInvisibleAttribute() throws IOException {
+        final Field hidden = field(parse(), "hidden");
+        assertNull(typeAnnotationsOf(hidden, 
Const.ATTR_RUNTIME_VISIBLE_TYPE_ANNOTATIONS));
+        final TypeAnnotations annotations = typeAnnotationsOf(hidden, 
Const.ATTR_RUNTIME_INVISIBLE_TYPE_ANNOTATIONS);
+        assertTrue(annotations instanceof RuntimeInvisibleTypeAnnotations);
+        assertFalse(annotations.isRuntimeVisible());
+        assertEquals("Ltypeannotations/Invisible;", 
annotations.getTypeAnnotationEntries()[0].getAnnotationEntry().getAnnotationType());
     }
 
     @Test
@@ -283,10 +269,43 @@ class TypeAnnotationsTest {
     }
 
     @Test
-    void rejectsAnUndefinedTargetType() throws IOException {
-        final ConstantPool constantPool = parse().getConstantPool();
-        final DataInputStream input = new DataInputStream(new 
ByteArrayInputStream(new byte[] {0x7F, 0, 0, 0}));
-        assertThrows(ClassFormatException.class, () -> 
TypeAnnotationEntry.read(input, constantPool, true));
+    void readsTheTargetsOfAMethod() throws IOException {
+        final TypeAnnotations annotations = typeAnnotationsOf(method(parse(), 
"find"), Const.ATTR_RUNTIME_VISIBLE_TYPE_ANNOTATIONS);
+        final List<Integer> targets = new ArrayList<>();
+        for (final TypeAnnotationEntry entry : annotations) {
+            targets.add(entry.getTargetType());
+            if (entry.getTargetType() == 
TypeAnnotationEntry.TARGET_METHOD_FORMAL_PARAMETER) {
+                // the index of the parameter
+                assertArrayEquals(new byte[] {0}, entry.getTargetInfo());
+            }
+        }
+        assertTrue(targets.contains(TypeAnnotationEntry.TARGET_METHOD_RETURN));
+        
assertTrue(targets.contains(TypeAnnotationEntry.TARGET_METHOD_FORMAL_PARAMETER));
+    }
+
+    @Test
+    void readsTheTypeAnnotationOfAField() throws IOException {
+        final TypeAnnotations annotations = typeAnnotationsOf(field(parse(), 
"field"), Const.ATTR_RUNTIME_VISIBLE_TYPE_ANNOTATIONS);
+        assertNotNull(annotations);
+        assertTrue(annotations instanceof RuntimeVisibleTypeAnnotations);
+        assertTrue(annotations.isRuntimeVisible());
+        assertEquals(1, annotations.getNumTypeAnnotations());
+        final TypeAnnotationEntry entry = 
annotations.getTypeAnnotationEntries()[0];
+        assertEquals(TypeAnnotationEntry.TARGET_FIELD, entry.getTargetType());
+        assertEquals(0, entry.getTargetInfo().length);
+        assertEquals(0, entry.getTypePathLength());
+        assertEquals("Ltypeannotations/Visible;", 
entry.getAnnotationEntry().getAnnotationType());
+    }
+
+    @Test
+    void readsTheTypePathOfATypeArgument() throws IOException {
+        final TypeAnnotations annotations = typeAnnotationsOf(field(parse(), 
"items"), Const.ATTR_RUNTIME_VISIBLE_TYPE_ANNOTATIONS);
+        final TypeAnnotationEntry entry = 
annotations.getTypeAnnotationEntries()[0];
+        assertEquals(TypeAnnotationEntry.TARGET_FIELD, entry.getTargetType());
+        assertEquals(1, entry.getTypePathLength());
+        // a type argument of the parameterized type, the first one
+        assertEquals(3, entry.getTypePathKind(0));
+        assertEquals(0, entry.getTypePathArgumentIndex(0));
     }
 
     @Test
@@ -301,6 +320,13 @@ class TypeAnnotationsTest {
         assertEquals(255, new 
TypeAnnotationEntry(TypeAnnotationEntry.TARGET_FIELD, new byte[0], new byte[255 
* 2], annotation).getTypePathLength());
     }
 
+    @Test
+    void rejectsAnUndefinedTargetType() throws IOException {
+        final ConstantPool constantPool = parse().getConstantPool();
+        final DataInputStream input = new DataInputStream(new 
ByteArrayInputStream(new byte[] {0x7F, 0, 0, 0}));
+        assertThrows(ClassFormatException.class, () -> 
TypeAnnotationEntry.read(input, constantPool, true));
+    }
+
     @Test
     void rejectsATargetInfoOfTheWrongSize() throws IOException {
         final AnnotationEntry annotation = typeAnnotationsOf(field(parse(), 
"field"), 
Const.ATTR_RUNTIME_VISIBLE_TYPE_ANNOTATIONS).getTypeAnnotationEntries()[0]
@@ -318,32 +344,6 @@ class TypeAnnotationsTest {
         assertEquals(2, new 
TypeAnnotationEntry(TypeAnnotationEntry.TARGET_LOCAL_VARIABLE, new byte[2], new 
byte[0], annotation).getTargetInfo().length);
     }
 
-    @Test
-    void distinguishesInnerClassesFromStaticNestedClasses() throws IOException 
{
-        final JavaClass clazz = annotatedTypes();
-        final TypeAnnotationEntry outer = typeAnnotationsOf(field(clazz, 
"outer"), 
Const.ATTR_RUNTIME_VISIBLE_TYPE_ANNOTATIONS).getTypeAnnotationEntries()[0];
-        final TypeAnnotationEntry inner = typeAnnotationsOf(field(clazz, 
"inner"), 
Const.ATTR_RUNTIME_VISIBLE_TYPE_ANNOTATIONS).getTypeAnnotationEntries()[0];
-        final TypeAnnotationEntry nested = typeAnnotationsOf(field(clazz, 
"nested"), 
Const.ATTR_RUNTIME_VISIBLE_TYPE_ANNOTATIONS).getTypeAnnotationEntries()[0];
-        assertEquals(0, outer.getTypePathLength());
-        assertEquals(1, inner.getTypePathLength());
-        assertEquals(1, inner.getTypePathKind(0));
-        assertEquals(0, inner.getTypePathArgumentIndex(0));
-        assertEquals(0, nested.getTypePathLength());
-    }
-
-    @Test
-    void followsTypeArgumentsWildcardBoundsAndArrayElements() throws 
IOException {
-        final TypeAnnotationEntry entry = 
typeAnnotationsOf(field(annotatedTypes(), "wildcard"), 
Const.ATTR_RUNTIME_VISIBLE_TYPE_ANNOTATIONS)
-                .getTypeAnnotationEntries()[0];
-        assertEquals(3, entry.getTypePathLength());
-        assertEquals(3, entry.getTypePathKind(0));
-        assertEquals(2, entry.getTypePathKind(1));
-        assertEquals(0, entry.getTypePathKind(2));
-        for (int step = 0; step < 3; step++) {
-            assertEquals(0, entry.getTypePathArgumentIndex(step));
-        }
-    }
-
     @Test
     void visitsCompilerGeneratedCodeAnnotations() throws IOException {
         final JavaClass clazz = annotatedTypes();

Reply via email to