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