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);

Reply via email to