Repository: quarkusio/quarkus
Issue: ArC AnnotationStore - AnnotationTarget is incorrectly used as a key in a Map

`ClassInfo`  and `FieldInfo` do not override `equals()`/`hashCode()`. Moreover, new `FieldInfo` objects are created for each `ClassInfo.fields()` invocation.

Changed files:
independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/AnnotationStore.java

diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/AnnotationStore.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/AnnotationStore.java
index 925782fe8c5..583c5d52a03 100644
--- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/AnnotationStore.java
+++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/AnnotationStore.java
@@ -7,12 +7,15 @@
 import java.util.Collections;
 import java.util.EnumMap;
 import java.util.List;
+import java.util.Objects;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import org.jboss.jandex.AnnotationInstance;
 import org.jboss.jandex.AnnotationTarget;
 import org.jboss.jandex.AnnotationTarget.Kind;
 import org.jboss.jandex.DotName;
+import org.jboss.jandex.FieldInfo;
+import org.jboss.jandex.MethodInfo;
 
 /**
  * Applies {@link AnnotationsTransformer}s and caches the results of transformations.
@@ -22,7 +25,7 @@
  */
 public final class AnnotationStore {
 
-    private final ConcurrentMap<AnnotationTarget, Collection<AnnotationInstance>> transformed;
+    private final ConcurrentMap<AnnotationTargetKey, Collection<AnnotationInstance>> transformed;
 
     private final EnumMap<Kind, List<AnnotationsTransformer>> transformersMap;
 
@@ -50,7 +53,7 @@ public final class AnnotationStore {
      */
     public Collection<AnnotationInstance> getAnnotations(AnnotationTarget target) {
         if (transformed != null) {
-            return transformed.computeIfAbsent(target, this::transform);
+            return transformed.computeIfAbsent(new AnnotationTargetKey(target), this::transform);
         }
         return getOriginalAnnotations(target);
     }
@@ -88,7 +91,8 @@ public boolean hasAnyAnnotation(AnnotationTarget target, Iterable<DotName> names
         return Annotations.containsAny(getAnnotations(target), names);
     }
 
-    private Collection<AnnotationInstance> transform(AnnotationTarget target) {
+    private Collection<AnnotationInstance> transform(AnnotationTargetKey key) {
+        AnnotationTarget target = key.target;
         Collection<AnnotationInstance> annotations = getOriginalAnnotations(target);
         List<AnnotationsTransformer> transformers = transformersMap.get(target.kind());
         if (transformers.isEmpty()) {
@@ -144,4 +148,65 @@ public Transformation transform() {
 
     }
 
+    /**
+     * We cannot use annotation target directly as a key in a Map. Only {@link MethodInfo} overrides equals/hashCode.
+     */
+    static final class AnnotationTargetKey {
+
+        final AnnotationTarget target;
+
+        public AnnotationTargetKey(AnnotationTarget target) {
+            this.target = target;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            AnnotationTargetKey other = (AnnotationTargetKey) obj;
+            if (target.kind() != other.target.kind()) {
+                return false;
+            }
+            switch (target.kind()) {
+                case METHOD:
+                    return target.asMethod().equals(other.target);
+                case FIELD:
+                    FieldInfo field = target.asField();
+                    FieldInfo otherField = other.target.asField();
+                    return Objects.equals(field.name(), otherField.name())
+                            && Objects.equals(field.declaringClass().name(), otherField.declaringClass().name());
+                case CLASS:
+                    return target.asClass().name().equals(other.target.asClass().name());
+                default:
+                    throw unsupportedAnnotationTarget(target);
+            }
+        }
+
+        @Override
+        public int hashCode() {
+            switch (target.kind()) {
+                case METHOD:
+                    return target.asMethod().hashCode();
+                case FIELD:
+                    return Objects.hash(target.asField().name(), target.asField().declaringClass().name());
+                case CLASS:
+                    return target.asClass().name().hashCode();
+                default:
+                    throw unsupportedAnnotationTarget(target);
+            }
+        }
+
+    }
+
+    private static IllegalArgumentException unsupportedAnnotationTarget(AnnotationTarget target) {
+        return new IllegalArgumentException("Unsupported annotation target: " + target.kind());
+    }
+
 }