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 89047990d Recurse into nested annotation arrays in
AnnotationUtils.hashCode (#1814)
89047990d is described below
commit 89047990d0c1cb947fc8092fc1ba42881b611837
Author: alhuda <[email protected]>
AuthorDate: Mon Oct 12 23:48:27 2026 +0530
Recurse into nested annotation arrays in AnnotationUtils.hashCode (#1814)
* recurse into nested annotation arrays in AnnotationUtils.hashCode
* use the annotation interface's class loader for the test proxies
---
.../org/apache/commons/lang3/AnnotationUtils.java | 17 ++++++++++++++
.../apache/commons/lang3/AnnotationUtilsTest.java | 27 ++++++++++++++++++++++
2 files changed, 44 insertions(+)
diff --git a/src/main/java/org/apache/commons/lang3/AnnotationUtils.java
b/src/main/java/org/apache/commons/lang3/AnnotationUtils.java
index bf6cd4756..0554e5529 100644
--- a/src/main/java/org/apache/commons/lang3/AnnotationUtils.java
+++ b/src/main/java/org/apache/commons/lang3/AnnotationUtils.java
@@ -117,6 +117,20 @@ private static boolean annotationArrayMemberEquals(final
Annotation[] a1, final
return true;
}
+ /**
+ * Helper method for generating a hash code for an array of annotations.
+ *
+ * @param annotations The array
+ * @return A hash code for the specified array
+ */
+ private static int annotationArrayMemberHash(final Annotation[]
annotations) {
+ int result = 1;
+ for (final Annotation annotation : annotations) {
+ result = 31 * result + (annotation == null ? 0 :
hashCode(annotation));
+ }
+ return result;
+ }
+
/**
* Helper method for comparing two objects of an array type.
*
@@ -164,6 +178,9 @@ private static boolean arrayMemberEquals(final Class<?>
componentType, final Obj
* @return A hash code for the specified array
*/
private static int arrayMemberHash(final Class<?> componentType, final
Object o) {
+ if (componentType.isAnnotation()) {
+ return annotationArrayMemberHash((Annotation[]) o);
+ }
if (componentType.equals(Byte.TYPE)) {
return Arrays.hashCode((byte[]) o);
}
diff --git a/src/test/java/org/apache/commons/lang3/AnnotationUtilsTest.java
b/src/test/java/org/apache/commons/lang3/AnnotationUtilsTest.java
index 9c6dca93d..bddf44f46 100644
--- a/src/test/java/org/apache/commons/lang3/AnnotationUtilsTest.java
+++ b/src/test/java/org/apache/commons/lang3/AnnotationUtilsTest.java
@@ -526,6 +526,33 @@ void testHashCode() {
});
}
+ @Test
+ void testHashCodeOfNestedAnnotationArray() {
+ assertTimeoutPreemptively(Duration.ofSeconds(666L), () -> {
+ final TestAnnotation real =
field1.getAnnotation(TestAnnotation.class);
+ // A nested annotation whose own hashCode() does not follow
Annotation#hashCode().
+ final InvocationHandler nestHandler = (proxy, method, args) -> {
+ if ("hashCode".equals(method.getName()) &&
method.getParameterTypes().length == 0) {
+ return Integer.valueOf(System.identityHashCode(proxy));
+ }
+ return method.invoke(real.nests()[0], args);
+ };
+ final NestAnnotation[] nests = { (NestAnnotation)
Proxy.newProxyInstance(
+ NestAnnotation.class.getClassLoader(), new Class[] {
NestAnnotation.class }, nestHandler) };
+ final InvocationHandler testHandler = (proxy, method, args) -> {
+ if ("nests".equals(method.getName()) &&
method.getParameterTypes().length == 0) {
+ return nests;
+ }
+ return method.invoke(real, args);
+ };
+ final TestAnnotation generated = (TestAnnotation)
Proxy.newProxyInstance(
+ TestAnnotation.class.getClassLoader(), new Class[] {
TestAnnotation.class }, testHandler);
+ assertTrue(AnnotationUtils.equals(real, generated));
+ assertTrue(AnnotationUtils.equals(generated, real));
+ assertEquals(AnnotationUtils.hashCode(real),
AnnotationUtils.hashCode(generated));
+ });
+ }
+
@Test
void testHashCodeWithFunction() {
final FunctionAnnotation annotation =
AnnotatedClass.class.getAnnotation(FunctionAnnotation.class);