[ 
https://issues.apache.org/jira/browse/LANG-1815?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18054401#comment-18054401
 ] 

Gary D. Gregory commented on LANG-1815:
---------------------------------------

There might be some interesting parallels here with 
[https://github.com/apache/commons-lang/pull/1558]

 

> AnnotationUtils.equals(..) returns false for equal package-private 
> annotations due to reflective access failure
> ---------------------------------------------------------------------------------------------------------------
>
>                 Key: LANG-1815
>                 URL: https://issues.apache.org/jira/browse/LANG-1815
>             Project: Commons Lang
>          Issue Type: Bug
>          Components: lang.*
>            Reporter: Ivan Ponomarev
>            Priority: Minor
>
> h3. Description
> {{AnnotationUtils.equals(Annotation a1, Annotation a2)}} is intended to 
> implement the equality rules described by {{Annotation.equals(Object)}} (as 
> stated in its Javadoc). However, the current implementation can incorrectly 
> return false for equal annotations when the annotation type is not 
> reflectively accessible from the caller’s package.
> The issue is caused by handling reflective failures via:
> {code:java}
> } catch (final ReflectiveOperationException ex) {
>     return false;
> }
> {code}
> This is problematic because reflective access errors are not a “not equal” 
> condition; they indicate that the implementation failed to read an annotation 
> member value. Returning {{false}} silently violates the expected semantics 
> and makes the method’s result depend on the caller’s package/module access 
> rather than annotation content.
> A concrete case is a package-private annotation type accessed from outside 
> {{org.apache.commons.lang3}}: invoking its member method reflectively can 
> throw an access-related reflective exception, which is currently swallowed 
> and converted to {{false}}.
> (!) To reproduce, the test class must be *outside* the 
> {{org.apache.commons.lang3}} package.
> {code:java}
> package org.apache.commons.lang3.external;
> import org.apache.commons.lang3.AnnotationUtils;
> import org.junit.jupiter.api.Assertions;
> import org.junit.jupiter.api.Test;
> import java.lang.annotation.Retention;
> import java.lang.annotation.RetentionPolicy;
> // CAUTION: in order to reproduce the ReflectiveOperationException bug, this 
> test
> // MUST be located OUTSIDE org.apache.commons.lang3 package.
> // Do NOT move it to the org.apache.commons.lang3 package!
> public class AnnotationEqualsTest {
>     @Retention(RetentionPolicy.RUNTIME)
>     @interface Tag {
>         String value();
>     }
>     @Tag("value")
>     private final Object a = new Object();
>     @Tag("value")
>     private final Object b = new Object();
>     @Test
>     void equalsWorksOnPackagePrivateAnnotations() throws Exception {
>         Tag tagA = getClass().getDeclaredField("a").getAnnotation(Tag.class);
>         Tag tagB = getClass().getDeclaredField("b").getAnnotation(Tag.class);
>         // Expected true; currently returns false because a reflective access 
> exception is swallowed.
>         Assertions.assertTrue(AnnotationUtils.equals(tagA, tagB));
>     }
> }
> {code}
> h3.Proposed fix
> # Ensure member methods are accessible before invocation via 
> {{m.setAccessible(true);}} This change makes the reproducer test "green".
> # Do not silently convert reflective failures into {{false}}, wrap and 
> rethrow into {{IllegalStateException}} instead. This makes failures visible 
> and prevents incorrect “false” results caused by reflective access issues.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to