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 667e888d Propagate runtime-visible flag when parsing parameter
annotations (#509)
667e888d is described below
commit 667e888d3d3468045f13549a6161b674f6bdba36
Author: Dexter.k <[email protected]>
AuthorDate: Thu Jun 25 19:38:43 2026 +0000
Propagate runtime-visible flag when parsing parameter annotations (#509)
parameter annotations and nested annotation values were read with a
hardcoded isRuntimeVisible=false, so a RuntimeVisibleParameterAnnotations
attribute parsed as invisible and a MethodGen round-trip rewrote it as
RuntimeInvisibleParameterAnnotations. Thread the flag from the attribute
through ParameterAnnotationEntry and AnnotationEntry.read, matching Annotations.
---
.../org/apache/bcel/classfile/AnnotationEntry.java | 2 +-
.../org/apache/bcel/classfile/ElementValue.java | 11 ++-
.../bcel/classfile/ParameterAnnotationEntry.java | 6 +-
.../bcel/classfile/ParameterAnnotations.java | 7 +-
.../RuntimeInvisibleParameterAnnotations.java | 2 +-
.../RuntimeVisibleParameterAnnotations.java | 2 +-
.../generic/ParameterAnnotationVisibilityTest.java | 105 +++++++++++++++++++++
7 files changed, 122 insertions(+), 13 deletions(-)
diff --git a/src/main/java/org/apache/bcel/classfile/AnnotationEntry.java
b/src/main/java/org/apache/bcel/classfile/AnnotationEntry.java
index afe09d29..4bd0e8d3 100644
--- a/src/main/java/org/apache/bcel/classfile/AnnotationEntry.java
+++ b/src/main/java/org/apache/bcel/classfile/AnnotationEntry.java
@@ -65,7 +65,7 @@ public class AnnotationEntry implements Node {
final int numElementValuePairs = input.readUnsignedShort();
for (int i = 0; i < numElementValuePairs; i++) {
annotationEntry.elementValuePairs
- .add(new ElementValuePair(input.readUnsignedShort(),
ElementValue.readElementValue(input, constantPool), constantPool));
+ .add(new ElementValuePair(input.readUnsignedShort(),
ElementValue.readElementValue(input, constantPool, isRuntimeVisible, 0),
constantPool));
}
return annotationEntry;
}
diff --git a/src/main/java/org/apache/bcel/classfile/ElementValue.java
b/src/main/java/org/apache/bcel/classfile/ElementValue.java
index 69e3522b..40e83ea8 100644
--- a/src/main/java/org/apache/bcel/classfile/ElementValue.java
+++ b/src/main/java/org/apache/bcel/classfile/ElementValue.java
@@ -117,7 +117,11 @@ public abstract class ElementValue {
* @throws IOException if an I/O error occurs.
* @since 6.7.0
*/
- public static ElementValue readElementValue(final DataInput input, final
ConstantPool cpool, int arrayNesting)
+ public static ElementValue readElementValue(final DataInput input, final
ConstantPool cpool, final int arrayNesting) throws IOException {
+ return readElementValue(input, cpool, false, arrayNesting);
+ }
+
+ static ElementValue readElementValue(final DataInput input, final
ConstantPool cpool, final boolean isRuntimeVisible, int arrayNesting)
throws IOException {
final byte tag = input.readByte();
switch (tag) {
@@ -139,8 +143,7 @@ public abstract class ElementValue {
return new ClassElementValue(CLASS, input.readUnsignedShort(),
cpool);
case ANNOTATION:
- // TODO isRuntimeVisible
- return new AnnotationElementValue(ANNOTATION,
AnnotationEntry.read(input, cpool, false), cpool);
+ return new AnnotationElementValue(ANNOTATION,
AnnotationEntry.read(input, cpool, isRuntimeVisible), cpool);
case ARRAY:
arrayNesting++;
@@ -151,7 +154,7 @@ public abstract class ElementValue {
final int numArrayVals = input.readUnsignedShort();
final ElementValue[] evalues = new ElementValue[numArrayVals];
for (int j = 0; j < numArrayVals; j++) {
- evalues[j] = readElementValue(input, cpool, arrayNesting);
+ evalues[j] = readElementValue(input, cpool, isRuntimeVisible,
arrayNesting);
}
return new ArrayElementValue(ARRAY, evalues, cpool);
diff --git
a/src/main/java/org/apache/bcel/classfile/ParameterAnnotationEntry.java
b/src/main/java/org/apache/bcel/classfile/ParameterAnnotationEntry.java
index fce2cc75..4cfb5bd1 100644
--- a/src/main/java/org/apache/bcel/classfile/ParameterAnnotationEntry.java
+++ b/src/main/java/org/apache/bcel/classfile/ParameterAnnotationEntry.java
@@ -65,14 +65,14 @@ public class ParameterAnnotationEntry implements Node {
*
* @param input Input stream.
* @param constantPool the constant pool.
+ * @param isRuntimeVisible whether the contained annotations are runtime
visible.
* @throws IOException if an I/O error occurs.
*/
- ParameterAnnotationEntry(final DataInput input, final ConstantPool
constantPool) throws IOException {
+ ParameterAnnotationEntry(final DataInput input, final ConstantPool
constantPool, final boolean isRuntimeVisible) throws IOException {
final int annotationTableLength = input.readUnsignedShort();
annotationTable = new AnnotationEntry[annotationTableLength];
for (int i = 0; i < annotationTableLength; i++) {
- // TODO isRuntimeVisible
- annotationTable[i] = AnnotationEntry.read(input, constantPool,
false);
+ annotationTable[i] = AnnotationEntry.read(input, constantPool,
isRuntimeVisible);
}
}
diff --git a/src/main/java/org/apache/bcel/classfile/ParameterAnnotations.java
b/src/main/java/org/apache/bcel/classfile/ParameterAnnotations.java
index 48cbd764..bbbd9f72 100644
--- a/src/main/java/org/apache/bcel/classfile/ParameterAnnotations.java
+++ b/src/main/java/org/apache/bcel/classfile/ParameterAnnotations.java
@@ -44,14 +44,15 @@ public abstract class ParameterAnnotations extends
Attribute implements Iterable
* @param length Content length in bytes.
* @param input Input stream.
* @param constantPool Array of constants.
+ * @param isRuntimeVisible whether these parameter annotations are runtime
visible.
*/
- ParameterAnnotations(final byte parameterAnnotationType, final int
nameIndex, final int length, final DataInput input, final ConstantPool
constantPool)
- throws IOException {
+ ParameterAnnotations(final byte parameterAnnotationType, final int
nameIndex, final int length, final DataInput input, final ConstantPool
constantPool,
+ final boolean isRuntimeVisible) throws IOException {
this(parameterAnnotationType, nameIndex, length,
(ParameterAnnotationEntry[]) null, constantPool);
final int numParameters = input.readUnsignedByte();
parameterAnnotationTable = new ParameterAnnotationEntry[numParameters];
for (int i = 0; i < numParameters; i++) {
- parameterAnnotationTable[i] = new ParameterAnnotationEntry(input,
constantPool);
+ parameterAnnotationTable[i] = new ParameterAnnotationEntry(input,
constantPool, isRuntimeVisible);
}
}
diff --git
a/src/main/java/org/apache/bcel/classfile/RuntimeInvisibleParameterAnnotations.java
b/src/main/java/org/apache/bcel/classfile/RuntimeInvisibleParameterAnnotations.java
index 2a8518a2..27a18f59 100644
---
a/src/main/java/org/apache/bcel/classfile/RuntimeInvisibleParameterAnnotations.java
+++
b/src/main/java/org/apache/bcel/classfile/RuntimeInvisibleParameterAnnotations.java
@@ -41,6 +41,6 @@ public class RuntimeInvisibleParameterAnnotations extends
ParameterAnnotations {
*/
public RuntimeInvisibleParameterAnnotations(final int nameIndex, final int
length, final DataInput input, final ConstantPool constantPool)
throws IOException {
- super(Const.ATTR_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS, nameIndex,
length, input, constantPool);
+ super(Const.ATTR_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS, nameIndex,
length, input, constantPool, false);
}
}
diff --git
a/src/main/java/org/apache/bcel/classfile/RuntimeVisibleParameterAnnotations.java
b/src/main/java/org/apache/bcel/classfile/RuntimeVisibleParameterAnnotations.java
index 167ee53c..51d8491d 100644
---
a/src/main/java/org/apache/bcel/classfile/RuntimeVisibleParameterAnnotations.java
+++
b/src/main/java/org/apache/bcel/classfile/RuntimeVisibleParameterAnnotations.java
@@ -41,6 +41,6 @@ public class RuntimeVisibleParameterAnnotations extends
ParameterAnnotations {
*/
public RuntimeVisibleParameterAnnotations(final int nameIndex, final int
length, final DataInput input, final ConstantPool constantPool)
throws IOException {
- super(Const.ATTR_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS, nameIndex,
length, input, constantPool);
+ super(Const.ATTR_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS, nameIndex,
length, input, constantPool, true);
}
}
diff --git
a/src/test/java/org/apache/bcel/generic/ParameterAnnotationVisibilityTest.java
b/src/test/java/org/apache/bcel/generic/ParameterAnnotationVisibilityTest.java
new file mode 100644
index 00000000..f4ddce12
--- /dev/null
+++
b/src/test/java/org/apache/bcel/generic/ParameterAnnotationVisibilityTest.java
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.bcel.generic;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.apache.bcel.AbstractTest;
+import org.apache.bcel.Const;
+import org.apache.bcel.classfile.AnnotationElementValue;
+import org.apache.bcel.classfile.AnnotationEntry;
+import org.apache.bcel.classfile.ArrayElementValue;
+import org.apache.bcel.classfile.ElementValue;
+import org.apache.bcel.classfile.ElementValuePair;
+import org.apache.bcel.classfile.JavaClass;
+import org.apache.bcel.classfile.Method;
+import org.apache.bcel.classfile.ParameterAnnotationEntry;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Checks that the runtime-visible flag is propagated when parameter
annotations and nested annotation values are parsed
+ * from a class file.
+ */
+class ParameterAnnotationVisibilityTest extends AbstractTest {
+
+ private JavaClass loadTestClass() throws ClassNotFoundException {
+ return getTestJavaClass(PACKAGE_BASE_NAME +
".data.AnnotatedWithCombinedAnnotation");
+ }
+
+ private Method getConstructor(final JavaClass jc) {
+ for (final Method method : jc.getMethods()) {
+ if (Const.CONSTRUCTOR_NAME.equals(method.getName())) {
+ return method;
+ }
+ }
+ return null;
+ }
+
+ @Test
+ void testNestedAnnotationValueIsRuntimeVisible() throws
ClassNotFoundException {
+ final JavaClass jc = loadTestClass();
+ boolean found = false;
+ for (final AnnotationEntry outer : jc.getAnnotationEntries()) {
+ for (final ElementValuePair pair : outer.getElementValuePairs()) {
+ final ElementValue value = pair.getValue();
+ if (value instanceof ArrayElementValue) {
+ for (final ElementValue inner : ((ArrayElementValue)
value).getElementValuesArray()) {
+ if (inner instanceof AnnotationElementValue) {
+ found = true;
+ assertTrue(((AnnotationElementValue)
inner).getAnnotationEntry().isRuntimeVisible(),
+ "nested annotation value parsed from a
runtime-visible annotation reported as invisible");
+ }
+ }
+ }
+ }
+ }
+ assertTrue(found, "no nested annotation values found in test data");
+ }
+
+ @Test
+ void testParsedParameterAnnotationIsRuntimeVisible() throws
ClassNotFoundException {
+ final JavaClass jc = loadTestClass();
+ final Method init = getConstructor(jc);
+ assertNotNull(init);
+ boolean found = false;
+ for (final ParameterAnnotationEntry pae :
init.getParameterAnnotationEntries()) {
+ for (final AnnotationEntry ae : pae.getAnnotationEntries()) {
+ found = true;
+ assertTrue(ae.isRuntimeVisible(), "runtime-visible parameter
annotation parsed as invisible");
+ }
+ }
+ assertTrue(found, "no parameter annotations found in test data");
+ }
+
+ @Test
+ void testParameterAnnotationVisibilitySurvivesMethodGen() throws
ClassNotFoundException {
+ final JavaClass jc = loadTestClass();
+ final Method init = getConstructor(jc);
+ final ConstantPoolGen cp = new ConstantPoolGen(jc.getConstantPool());
+ final MethodGen mg = new MethodGen(init, jc.getClassName(), cp);
+ mg.getAnnotationsOnParameter(1); // unpack the existing parameter
annotations before rebuilding
+ final Method out = mg.getMethod();
+
assertNotNull(out.getAttribute(Const.ATTR_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS),
+ "runtime-visible parameter annotation dropped on MethodGen
round-trip");
+
assertNull(out.getAttribute(Const.ATTR_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS),
+ "runtime-visible parameter annotation downgraded to invisible on
MethodGen round-trip");
+ }
+}