From e7115f2661a0339d3895c01b68a215368d2ac794 Mon Sep 17 00:00:00 2001 From: Klaas Dellschaft Date: Thu, 1 Jul 2021 11:49:03 +0200 Subject: [PATCH] Behavior of `AnnotatedMember.equals()` (#3187) --- release-notes/CREDITS-2.x | 2 +- .../introspect/AnnotatedConstructor.java | 20 +++-- .../databind/introspect/AnnotatedField.java | 12 ++- .../databind/introspect/AnnotatedMethod.java | 12 ++- .../AnnotatedMemberEqualityTest.java | 80 +++++++++++++++++++ 5 files changed, 116 insertions(+), 10 deletions(-) create mode 100644 src/test/java/com/fasterxml/jackson/databind/introspect/AnnotatedMemberEqualityTest.java diff --git a/release-notes/CREDITS-2.x b/release-notes/CREDITS-2.x index 6792eeea7e..474587c6b2 100644 --- a/release-notes/CREDITS-2.x +++ b/release-notes/CREDITS-2.x @@ -1351,7 +1351,7 @@ Morten Andersen-Gott (magott@github) * Contributed #3174: DOM `Node` serialization omits the default namespace declaration (2.13.0) -Klaas Sellschaft (klaasdellschaft@github) +Klaas Dellschaft (klaasdellschaft@github) * Contributed #3177: Support `suppressed` property when deserializing `Throwable` (2.13.0) diff --git a/src/main/java/com/fasterxml/jackson/databind/introspect/AnnotatedConstructor.java b/src/main/java/com/fasterxml/jackson/databind/introspect/AnnotatedConstructor.java index 4fc92238a9..e940b0bde9 100644 --- a/src/main/java/com/fasterxml/jackson/databind/introspect/AnnotatedConstructor.java +++ b/src/main/java/com/fasterxml/jackson/databind/introspect/AnnotatedConstructor.java @@ -1,10 +1,12 @@ package com.fasterxml.jackson.databind.introspect; -import java.lang.reflect.*; - import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.util.ClassUtil; +import java.lang.reflect.Constructor; +import java.lang.reflect.Member; +import java.lang.reflect.Type; + public final class AnnotatedConstructor extends AnnotatedWithParams { @@ -178,12 +180,20 @@ public String toString() { public int hashCode() { return _constructor.getName().hashCode(); } - + @Override public boolean equals(Object o) { if (o == this) return true; - return ClassUtil.hasClass(o, getClass()) - && (((AnnotatedConstructor) o)._constructor == _constructor); + if (!ClassUtil.hasClass(o, getClass())) { + return false; + } + + AnnotatedConstructor other = (AnnotatedConstructor) o; + if (other._constructor == null) { + return _constructor == null; + } else { + return other._constructor.equals(_constructor); + } } /* diff --git a/src/main/java/com/fasterxml/jackson/databind/introspect/AnnotatedField.java b/src/main/java/com/fasterxml/jackson/databind/introspect/AnnotatedField.java index e905f95f8d..70d05d51ce 100644 --- a/src/main/java/com/fasterxml/jackson/databind/introspect/AnnotatedField.java +++ b/src/main/java/com/fasterxml/jackson/databind/introspect/AnnotatedField.java @@ -135,8 +135,16 @@ public int hashCode() { @Override public boolean equals(Object o) { if (o == this) return true; - return ClassUtil.hasClass(o, getClass()) - && (((AnnotatedField) o)._field == _field); + if (!ClassUtil.hasClass(o, getClass())) { + return false; + } + + AnnotatedField other = (AnnotatedField) o; + if (other._field == null) { + return _field == null; + } else { + return other._field.equals(_field); + } } @Override diff --git a/src/main/java/com/fasterxml/jackson/databind/introspect/AnnotatedMethod.java b/src/main/java/com/fasterxml/jackson/databind/introspect/AnnotatedMethod.java index 94bfa61b74..003980e5e1 100644 --- a/src/main/java/com/fasterxml/jackson/databind/introspect/AnnotatedMethod.java +++ b/src/main/java/com/fasterxml/jackson/databind/introspect/AnnotatedMethod.java @@ -253,8 +253,16 @@ public int hashCode() { @Override public boolean equals(Object o) { if (o == this) return true; - return ClassUtil.hasClass(o, getClass()) - && (((AnnotatedMethod) o)._method == _method); + if (!ClassUtil.hasClass(o, getClass())) { + return false; + } + + AnnotatedMethod other = (AnnotatedMethod) o; + if (other._method == null) { + return _method == null; + } else { + return other._method.equals(_method); + } } /* diff --git a/src/test/java/com/fasterxml/jackson/databind/introspect/AnnotatedMemberEqualityTest.java b/src/test/java/com/fasterxml/jackson/databind/introspect/AnnotatedMemberEqualityTest.java new file mode 100644 index 0000000000..5a068341a1 --- /dev/null +++ b/src/test/java/com/fasterxml/jackson/databind/introspect/AnnotatedMemberEqualityTest.java @@ -0,0 +1,80 @@ +package com.fasterxml.jackson.databind.introspect; + +import com.fasterxml.jackson.databind.BaseMapTest; +import com.fasterxml.jackson.databind.DeserializationConfig; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.json.JsonMapper; + +public class AnnotatedMemberEqualityTest extends BaseMapTest { + + private static class SomeBean { + + private String value; + + public SomeBean(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + } + + public void testAnnotatedConstructorEquality() { + ObjectMapper mapper = new JsonMapper(); + DeserializationConfig context = mapper.getDeserializationConfig(); + JavaType beanType = mapper.constructType(SomeBean.class); + + AnnotatedClass instance1 = AnnotatedClassResolver.resolve(context, beanType, context); + AnnotatedClass instance2 = AnnotatedClassResolver.resolve(context, beanType, context); + + AnnotatedConstructor constructor1 = instance1.getConstructors().get(0); + AnnotatedConstructor constructor2 = instance2.getConstructors().get(0); + + assertEquals(instance1, instance2); + assertEquals(constructor1.getAnnotated(), constructor2.getAnnotated()); + assertEquals(constructor1, constructor2); + assertEquals(constructor1.getParameter(0), constructor2.getParameter(0)); + } + + public void testAnnotatedMethodEquality() { + ObjectMapper mapper = new JsonMapper(); + DeserializationConfig context = mapper.getDeserializationConfig(); + JavaType beanType = mapper.constructType(SomeBean.class); + + AnnotatedClass instance1 = AnnotatedClassResolver.resolve(context, beanType, context); + AnnotatedClass instance2 = AnnotatedClassResolver.resolve(context, beanType, context); + + String methodName = "setValue"; + Class[] paramTypes = {String.class}; + AnnotatedMethod method1 = instance1.findMethod(methodName, paramTypes); + AnnotatedMethod method2 = instance2.findMethod(methodName, paramTypes); + + assertEquals(instance1, instance2); + assertEquals(method1.getAnnotated(), method2.getAnnotated()); + assertEquals(method1, method2); + assertEquals(method1.getParameter(0), method2.getParameter(0)); + } + + public void testAnnotatedFieldEquality() { + ObjectMapper mapper = new JsonMapper(); + DeserializationConfig context = mapper.getDeserializationConfig(); + JavaType beanType = mapper.constructType(SomeBean.class); + + AnnotatedClass instance1 = AnnotatedClassResolver.resolve(context, beanType, context); + AnnotatedClass instance2 = AnnotatedClassResolver.resolve(context, beanType, context); + + AnnotatedField field1 = instance1.fields().iterator().next(); + AnnotatedField field2 = instance2.fields().iterator().next(); + + assertEquals(instance1, instance2); + assertEquals(field1.getAnnotated(), field2.getAnnotated()); + assertEquals(field1, field2); + } + +}