Skip to content

Commit 9a36027

Browse files
committed
MethodParameter.equals checks nesting level and containing class
Closes gh-23352
1 parent 6cb4b8b commit 9a36027

File tree

2 files changed

+58
-5
lines changed

2 files changed

+58
-5
lines changed

spring-core/src/main/java/org/springframework/core/MethodParameter.java

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -39,6 +39,7 @@
3939
import org.springframework.lang.Nullable;
4040
import org.springframework.util.Assert;
4141
import org.springframework.util.ClassUtils;
42+
import org.springframework.util.ObjectUtils;
4243

4344
/**
4445
* Helper class that encapsulates the specification of a method parameter, i.e. a {@link Method}
@@ -61,14 +62,15 @@ public class MethodParameter {
6162

6263
private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0];
6364

65+
6466
private final Executable executable;
6567

6668
private final int parameterIndex;
6769

6870
@Nullable
6971
private volatile Parameter parameter;
7072

71-
private int nestingLevel = 1;
73+
private int nestingLevel;
7274

7375
/** Map from Integer level to Integer type index. */
7476
@Nullable
@@ -658,12 +660,16 @@ public boolean equals(Object other) {
658660
return false;
659661
}
660662
MethodParameter otherParam = (MethodParameter) other;
661-
return (this.parameterIndex == otherParam.parameterIndex && getExecutable().equals(otherParam.getExecutable()));
663+
return (this.containingClass == otherParam.containingClass &&
664+
ObjectUtils.nullSafeEquals(this.typeIndexesPerLevel, otherParam.typeIndexesPerLevel) &&
665+
this.nestingLevel == otherParam.nestingLevel &&
666+
this.parameterIndex == otherParam.parameterIndex &&
667+
this.executable.equals(otherParam.executable));
662668
}
663669

664670
@Override
665671
public int hashCode() {
666-
return (getExecutable().hashCode() * 31 + this.parameterIndex);
672+
return (31 * this.executable.hashCode() + this.parameterIndex);
667673
}
668674

669675
@Override

spring-core/src/test/java/org/springframework/core/MethodParameterTests.java

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -22,6 +22,7 @@
2222
import java.lang.annotation.Target;
2323
import java.lang.reflect.Constructor;
2424
import java.lang.reflect.Method;
25+
import java.util.ArrayList;
2526
import java.util.concurrent.Callable;
2627

2728
import org.junit.Before;
@@ -148,6 +149,44 @@ public void genericConstructorParameterInInnerClass() throws Exception {
148149
methodParameter.getGenericParameterType());
149150
}
150151

152+
@Test
153+
public void multipleResolveParameterTypeCalls() throws Exception {
154+
Method method = ArrayList.class.getMethod("get", int.class);
155+
MethodParameter methodParameter = MethodParameter.forExecutable(method, -1);
156+
assertEquals(Object.class, methodParameter.getParameterType());
157+
GenericTypeResolver.resolveParameterType(methodParameter, StringList.class);
158+
assertEquals(String.class, methodParameter.getParameterType());
159+
GenericTypeResolver.resolveParameterType(methodParameter, IntegerList.class);
160+
assertEquals(Integer.class, methodParameter.getParameterType());
161+
}
162+
163+
@Test
164+
public void equalsAndHashCodeConsidersContainingClass() throws Exception {
165+
Method method = ArrayList.class.getMethod("get", int.class);
166+
MethodParameter m1 = MethodParameter.forExecutable(method, -1);
167+
MethodParameter m2 = MethodParameter.forExecutable(method, -1);
168+
MethodParameter m3 = MethodParameter.forExecutable(method, -1).nested();
169+
assertEquals(m1, m2);
170+
assertNotEquals(m1, m3);
171+
assertEquals(m1.hashCode(), m2.hashCode());
172+
}
173+
174+
@Test
175+
public void equalsAndHashCodeConsidersNesting() throws Exception {
176+
Method method = ArrayList.class.getMethod("get", int.class);
177+
MethodParameter m1 = MethodParameter.forExecutable(method, -1);
178+
GenericTypeResolver.resolveParameterType(m1, StringList.class);
179+
MethodParameter m2 = MethodParameter.forExecutable(method, -1);
180+
GenericTypeResolver.resolveParameterType(m2, StringList.class);
181+
MethodParameter m3 = MethodParameter.forExecutable(method, -1);
182+
GenericTypeResolver.resolveParameterType(m3, IntegerList.class);
183+
MethodParameter m4 = MethodParameter.forExecutable(method, -1);
184+
assertEquals(m1, m2);
185+
assertNotEquals(m1, m3);
186+
assertNotEquals(m1, m4);
187+
assertEquals(m1.hashCode(), m2.hashCode());
188+
}
189+
151190

152191
public int method(String p1, long p2) {
153192
return 42;
@@ -172,4 +211,12 @@ public InnerClass(@Param String s, Callable<Integer> i) {
172211
private @interface Param {
173212
}
174213

214+
@SuppressWarnings("serial")
215+
private static class StringList extends ArrayList<String> {
216+
}
217+
218+
@SuppressWarnings("serial")
219+
private static class IntegerList extends ArrayList<Integer> {
220+
}
221+
175222
}

0 commit comments

Comments
 (0)