From fcbd46d54723aa04a9d3dc70a269ced00e5dc1de Mon Sep 17 00:00:00 2001 From: Ladislav Thon Date: Mon, 25 Sep 2023 11:43:29 +0200 Subject: [PATCH] ArC: fix hash code of TypeAndQualifiers The `TypeAndQualifiers` compound is used as a key in hash maps, which means its equality and hash code must be consistent. Unfortunately, the implementation of `equals()` is completely custom, because it needs to ignore `AnnotationInstance.target`, yet the `hashCode()` implementation blindly delegates to `AnnotationInstance`. That used to work, because `AnnotationInstance.hashCode()` ignored the `target` before, but that has never been a stated contract. A completely custom implementation of equality should always be accompanied by a custom implementation of hash code. That's what this commit does. --- .../arc/processor/InjectionPointInfo.java | 35 +++++++++++++------ 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/InjectionPointInfo.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/InjectionPointInfo.java index f98d4bda71cd4..3174b2976989f 100644 --- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/InjectionPointInfo.java +++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/InjectionPointInfo.java @@ -388,7 +388,8 @@ public TypeAndQualifiers(Type type, Set qualifiers) { public int hashCode() { final int prime = 31; int result = 1; - result = prime * result + ((qualifiers == null) ? 0 : qualifiers.hashCode()); + // We cannot use AnnotationInstance#hashCode() as it includes the AnnotationTarget + result = prime * result + annotationSetHashCode(qualifiers); result = prime * result + ((type == null) ? 0 : type.hashCode()); return result; } @@ -409,8 +410,8 @@ public boolean equals(Object obj) { if (other.qualifiers != null) { return false; } - } else if (!qualifiersAreEqual(qualifiers, other.qualifiers)) { - // We cannot use AnnotationInstance#equals() as it requires the exact same annotationTarget instance + } else if (!annotationSetEquals(qualifiers, other.qualifiers)) { + // We cannot use AnnotationInstance#equals() as it requires the exact same AnnotationTarget instance return false; } if (type == null) { @@ -423,16 +424,16 @@ public boolean equals(Object obj) { return true; } - private boolean qualifiersAreEqual(Set q1, Set q2) { - if (q1 == q2) { + private static boolean annotationSetEquals(Set s1, Set s2) { + if (s1 == s2) { return true; } - if (q1.size() != q2.size()) { + if (s1.size() != s2.size()) { return false; } - for (AnnotationInstance a1 : q1) { - for (AnnotationInstance a2 : q2) { - if (!annotationsAreEqual(a1, a2)) { + for (AnnotationInstance a1 : s1) { + for (AnnotationInstance a2 : s2) { + if (!annotationEquals(a1, a2)) { return false; } } @@ -440,13 +441,27 @@ private boolean qualifiersAreEqual(Set q1, Set s) { + int result = 1; + for (AnnotationInstance a : s) { + result = 31 * result + annotationHashCode(a); + } + return result; + } + + private static int annotationHashCode(AnnotationInstance a) { + int result = a.name().hashCode(); + result = 31 * result + a.values().hashCode(); + return result; + } + } }