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-lang.git
The following commit(s) were added to refs/heads/master by this push:
new 5dc94f6ed [LANG-1835] Ignore synthetic methods in AnnotationUtils
(#1810)
5dc94f6ed is described below
commit 5dc94f6ed328bf853af92158892aa849d63fb354
Author: Gary Gregory <[email protected]>
AuthorDate: Sat Oct 10 13:40:03 2026 -0400
[LANG-1835] Ignore synthetic methods in AnnotationUtils (#1810)
Add missing tests.
Test AnnotationUtils with forced accessibility disabled.
Verify that equals(), hashCode(), and toString() work with public
annotations and preserve access failures for package-private annotations
when AbstractReflection.forceAccessible is false.
---
src/changes/changes.xml | 1 +
.../lang3/external/AnnotationEqualsTest.java | 65 ++++++++++++++++++++++
2 files changed, 66 insertions(+)
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index f4afaf79c..dc1ae9cae 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -50,6 +50,7 @@ The <action> type attribute can be add,update,fix,remove.
<action type="fix" dev="ggregory" due-to="alhuda, Gary
Gregory">Default unbounded WildcardType upper bound to Object in TypeUtils
(#1807).</action>
<action type="fix" dev="ggregory" due-to="alhuda, Gary
Gregory">Take FastDatePrinter era names from the locale's calendar
(#1800).</action>
<action issue="LANG-1655" type="fix" dev="ggregory" due-to="Efe, Gary
Gregory">Preserve Korean text in stripAccents (#1799).</action>
+ <action issue="LANG-1835" type="fix" dev="ggregory" due-to="zemiles, Gary
Gregory">Ignore synthetic methods in AnnotationUtils (#1810).</action>
<!-- ADD -->
<!-- UPDATE -->
</release>
diff --git
a/src/test/java/org/apache/commons/lang3/external/AnnotationEqualsTest.java
b/src/test/java/org/apache/commons/lang3/external/AnnotationEqualsTest.java
index 5b6484153..a846bd23b 100644
--- a/src/test/java/org/apache/commons/lang3/external/AnnotationEqualsTest.java
+++ b/src/test/java/org/apache/commons/lang3/external/AnnotationEqualsTest.java
@@ -27,7 +27,9 @@
import java.lang.reflect.InvocationTargetException;
import org.apache.commons.lang3.AnnotationUtils;
+import org.apache.commons.lang3.exception.UncheckedException;
import org.junit.jupiter.api.Test;
+import org.junitpioneer.jupiter.SetSystemProperty;
/**
* Regression test for <a
href="https://issues.apache.org/jira/browse/LANG-1815">LANG-1815</a>.
@@ -49,6 +51,19 @@
* </p>
*/
public class AnnotationEqualsTest {
+ /**
+ * Declares an annotation accessible without suppressing reflective access
checks.
+ */
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface PublicTag {
+ /**
+ * Gets the tag value.
+ *
+ * @return the tag value
+ */
+ String value();
+ }
+
@Retention(RetentionPolicy.RUNTIME)
@interface Tag {
String value();
@@ -66,11 +81,23 @@ public String value() {
}
}
+ @PublicTag("value")
@Tag("value")
private final Object a = new Object();
+
+ @PublicTag("value")
@Tag("value")
private final Object b = new Object();
+ @Test
+ @SetSystemProperty(key = "AbstractReflection.forceAccessible", value =
"false")
+ void equalsRejectsPackagePrivateAnnotationsWithoutForcedAccess() throws
Exception {
+ final Tag tagA =
getClass().getDeclaredField("a").getAnnotation(Tag.class);
+ final Tag tagB =
getClass().getDeclaredField("b").getAnnotation(Tag.class);
+ final IllegalStateException ex =
assertThrows(IllegalStateException.class, () -> AnnotationUtils.equals(tagA,
tagB));
+ assertInstanceOf(IllegalAccessException.class, ex.getCause());
+ }
+
@Test
void equalsWorksOnPackagePrivateAnnotations() throws Exception {
final Tag tagA =
getClass().getDeclaredField("a").getAnnotation(Tag.class);
@@ -78,6 +105,14 @@ void equalsWorksOnPackagePrivateAnnotations() throws
Exception {
assertTrue(AnnotationUtils.equals(tagA, tagB));
}
+ @Test
+ @SetSystemProperty(key = "AbstractReflection.forceAccessible", value =
"false")
+ void equalsWorksOnPublicAnnotationsWithoutForcedAccess() throws Exception {
+ final PublicTag tagA =
getClass().getDeclaredField("a").getAnnotation(PublicTag.class);
+ final PublicTag tagB =
getClass().getDeclaredField("b").getAnnotation(PublicTag.class);
+ assertTrue(AnnotationUtils.equals(tagA, tagB));
+ }
+
@Test
void equalsWrapsReflectiveOperationException() throws Exception {
final Tag tagA = new ThrowingTag();
@@ -89,12 +124,35 @@ void equalsWrapsReflectiveOperationException() throws
Exception {
assertEquals("boom", ((InvocationTargetException)
ex.getCause()).getTargetException().getMessage());
}
+ @Test
+ @SetSystemProperty(key = "AbstractReflection.forceAccessible", value =
"false")
+ void hashCodeRejectsPackagePrivateAnnotationsWithoutForcedAccess() throws
Exception {
+ final Tag tag =
getClass().getDeclaredField("a").getAnnotation(Tag.class);
+ final UncheckedException ex = assertThrows(UncheckedException.class,
() -> AnnotationUtils.hashCode(tag));
+ assertInstanceOf(IllegalAccessException.class, ex.getCause());
+ }
+
@Test
void hashCodeWorksOnPackagePrivateAnnotations() throws Exception {
final Tag tag =
getClass().getDeclaredField("a").getAnnotation(Tag.class);
assertEquals(tag.hashCode(), AnnotationUtils.hashCode(tag));
}
+ @Test
+ @SetSystemProperty(key = "AbstractReflection.forceAccessible", value =
"false")
+ void hashCodeWorksOnPublicAnnotationsWithoutForcedAccess() throws
Exception {
+ final PublicTag tag =
getClass().getDeclaredField("a").getAnnotation(PublicTag.class);
+ assertEquals(tag.hashCode(), AnnotationUtils.hashCode(tag));
+ }
+
+ @Test
+ @SetSystemProperty(key = "AbstractReflection.forceAccessible", value =
"false")
+ void toStringRejectsPackagePrivateAnnotationsWithoutForcedAccess() throws
Exception {
+ final Tag tag =
getClass().getDeclaredField("a").getAnnotation(Tag.class);
+ final UncheckedException ex = assertThrows(UncheckedException.class,
() -> AnnotationUtils.toString(tag));
+ assertInstanceOf(IllegalAccessException.class, ex.getCause());
+ }
+
@Test
void toStringWorksOnPackagePrivateAnnotations() throws Exception {
final Tag tag =
getClass().getDeclaredField("a").getAnnotation(Tag.class);
@@ -102,4 +160,11 @@ void toStringWorksOnPackagePrivateAnnotations() throws
Exception {
assertTrue(text.contains("value=value"), text);
}
+ @Test
+ @SetSystemProperty(key = "AbstractReflection.forceAccessible", value =
"false")
+ void toStringWorksOnPublicAnnotationsWithoutForcedAccess() throws
Exception {
+ final PublicTag tag =
getClass().getDeclaredField("a").getAnnotation(PublicTag.class);
+ assertEquals("@" + PublicTag.class.getName() + "(value=value)",
AnnotationUtils.toString(tag));
+ }
+
}