Skip to content

Commit 7e3c722

Browse files
committed
Objects with multi-threaded access should not lazily populate a hash field
Issue. SPR-11428 (cherry picked from commit 72fe7eb)
1 parent d7591c6 commit 7e3c722

File tree

3 files changed

+82
-113
lines changed

3 files changed

+82
-113
lines changed

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

Lines changed: 14 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2013 the original author or authors.
2+
* Copyright 2002-2014 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.
@@ -44,7 +44,7 @@ public class MethodParameter {
4444

4545
private final Method method;
4646

47-
private final Constructor constructor;
47+
private final Constructor<?> constructor;
4848

4949
private final int parameterIndex;
5050

@@ -65,8 +65,6 @@ public class MethodParameter {
6565

6666
Map<TypeVariable, Type> typeVariableMap;
6767

68-
private int hash = 0;
69-
7068

7169
/**
7270
* Create a new MethodParameter for the given method, with nesting level 1.
@@ -100,7 +98,7 @@ public MethodParameter(Method method, int parameterIndex, int nestingLevel) {
10098
* @param constructor the Constructor to specify a parameter for
10199
* @param parameterIndex the index of the parameter
102100
*/
103-
public MethodParameter(Constructor constructor, int parameterIndex) {
101+
public MethodParameter(Constructor<?> constructor, int parameterIndex) {
104102
this(constructor, parameterIndex, 1);
105103
}
106104

@@ -112,7 +110,7 @@ public MethodParameter(Constructor constructor, int parameterIndex) {
112110
* (typically 1; e.g. in case of a List of Lists, 1 would indicate the
113111
* nested List, whereas 2 would indicate the element of the nested List)
114112
*/
115-
public MethodParameter(Constructor constructor, int parameterIndex, int nestingLevel) {
113+
public MethodParameter(Constructor<?> constructor, int parameterIndex, int nestingLevel) {
116114
Assert.notNull(constructor, "Constructor must not be null");
117115
this.constructor = constructor;
118116
this.parameterIndex = parameterIndex;
@@ -138,7 +136,6 @@ public MethodParameter(MethodParameter original) {
138136
this.nestingLevel = original.nestingLevel;
139137
this.typeIndexesPerLevel = original.typeIndexesPerLevel;
140138
this.typeVariableMap = original.typeVariableMap;
141-
this.hash = original.hash;
142139
}
143140

144141

@@ -156,24 +153,24 @@ public Method getMethod() {
156153
* <p>Note: Either Method or Constructor is available.
157154
* @return the Constructor, or {@code null} if none
158155
*/
159-
public Constructor getConstructor() {
156+
public Constructor<?> getConstructor() {
160157
return this.constructor;
161158
}
162159

163160
/**
164161
* Returns the wrapped member.
165-
* @return the member
162+
* @return the Method or Constructor as Member
166163
*/
167164
private Member getMember() {
168-
return this.method != null ? this.method : this.constructor;
165+
return (this.method != null ? this.method : this.constructor);
169166
}
170167

171168
/**
172169
* Returns the wrapped annotated element.
173-
* @return the annotated element
170+
* @return the Method or Constructor as AnnotatedElement
174171
*/
175172
private AnnotatedElement getAnnotatedElement() {
176-
return this.method != null ? this.method : this.constructor;
173+
return (this.method != null ? this.method : this.constructor);
177174
}
178175

179176
/**
@@ -241,12 +238,12 @@ public Class<?> getNestedParameterType() {
241238
Integer index = getTypeIndexForCurrentLevel();
242239
Type arg = ((ParameterizedType) type).getActualTypeArguments()[index != null ? index : 0];
243240
if (arg instanceof Class) {
244-
return (Class) arg;
241+
return (Class<?>) arg;
245242
}
246243
else if (arg instanceof ParameterizedType) {
247244
arg = ((ParameterizedType) arg).getRawType();
248245
if (arg instanceof Class) {
249-
return (Class) arg;
246+
return (Class<?>) arg;
250247
}
251248
}
252249
}
@@ -423,29 +420,14 @@ public boolean equals(Object obj) {
423420
}
424421
if (obj != null && obj instanceof MethodParameter) {
425422
MethodParameter other = (MethodParameter) obj;
426-
427-
if (this.parameterIndex != other.parameterIndex) {
428-
return false;
429-
}
430-
else if (this.getMember().equals(other.getMember())) {
431-
return true;
432-
}
433-
else {
434-
return false;
435-
}
423+
return (this.parameterIndex == other.parameterIndex && getMember().equals(other.getMember()));
436424
}
437425
return false;
438426
}
439427

440428
@Override
441429
public int hashCode() {
442-
int result = this.hash;
443-
if (result == 0) {
444-
result = getMember().hashCode();
445-
result = 31 * result + this.parameterIndex;
446-
this.hash = result;
447-
}
448-
return result;
430+
return (getMember().hashCode() * 31 + this.parameterIndex);
449431
}
450432

451433

@@ -462,7 +444,7 @@ public static MethodParameter forMethodOrConstructor(Object methodOrConstructor,
462444
return new MethodParameter((Method) methodOrConstructor, parameterIndex);
463445
}
464446
else if (methodOrConstructor instanceof Constructor) {
465-
return new MethodParameter((Constructor) methodOrConstructor, parameterIndex);
447+
return new MethodParameter((Constructor<?>) methodOrConstructor, parameterIndex);
466448
}
467449
else {
468450
throw new IllegalArgumentException(

spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/RequestMappingInfo.java

Lines changed: 55 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2012 the original author or authors.
2+
* Copyright 2002-2014 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.
@@ -36,7 +36,7 @@
3636
* <li>{@link HeadersRequestCondition}
3737
* <li>{@link ConsumesRequestCondition}
3838
* <li>{@link ProducesRequestCondition}
39-
* <li>{@code RequestCondition<?>} (optional, custom request condition)
39+
* <li>{@code RequestCondition} (optional, custom request condition)
4040
* </ol>
4141
*
4242
* @author Arjen Poutsma
@@ -59,24 +59,20 @@ public final class RequestMappingInfo implements RequestCondition<RequestMapping
5959

6060
private final RequestConditionHolder customConditionHolder;
6161

62-
private int hash;
6362

6463
/**
6564
* Creates a new instance with the given request conditions.
6665
*/
67-
public RequestMappingInfo(PatternsRequestCondition patterns,
68-
RequestMethodsRequestCondition methods,
69-
ParamsRequestCondition params,
70-
HeadersRequestCondition headers,
71-
ConsumesRequestCondition consumes,
72-
ProducesRequestCondition produces,
73-
RequestCondition<?> custom) {
74-
this.patternsCondition = patterns != null ? patterns : new PatternsRequestCondition();
75-
this.methodsCondition = methods != null ? methods : new RequestMethodsRequestCondition();
76-
this.paramsCondition = params != null ? params : new ParamsRequestCondition();
77-
this.headersCondition = headers != null ? headers : new HeadersRequestCondition();
78-
this.consumesCondition = consumes != null ? consumes : new ConsumesRequestCondition();
79-
this.producesCondition = produces != null ? produces : new ProducesRequestCondition();
66+
public RequestMappingInfo(PatternsRequestCondition patterns, RequestMethodsRequestCondition methods,
67+
ParamsRequestCondition params, HeadersRequestCondition headers, ConsumesRequestCondition consumes,
68+
ProducesRequestCondition produces, RequestCondition<?> custom) {
69+
70+
this.patternsCondition = (patterns != null ? patterns : new PatternsRequestCondition());
71+
this.methodsCondition = (methods != null ? methods : new RequestMethodsRequestCondition());
72+
this.paramsCondition = (params != null ? params : new ParamsRequestCondition());
73+
this.headersCondition = (headers != null ? headers : new HeadersRequestCondition());
74+
this.consumesCondition = (consumes != null ? consumes : new ConsumesRequestCondition());
75+
this.producesCondition = (produces != null ? produces : new ProducesRequestCondition());
8076
this.customConditionHolder = new RequestConditionHolder(custom);
8177
}
8278

@@ -88,61 +84,63 @@ public RequestMappingInfo(RequestMappingInfo info, RequestCondition<?> customReq
8884
info.consumesCondition, info.producesCondition, customRequestCondition);
8985
}
9086

87+
9188
/**
9289
* Returns the URL patterns of this {@link RequestMappingInfo};
93-
* or instance with 0 patterns, never {@code null}
90+
* or instance with 0 patterns, never {@code null}.
9491
*/
9592
public PatternsRequestCondition getPatternsCondition() {
96-
return patternsCondition;
93+
return this.patternsCondition;
9794
}
9895

9996
/**
10097
* Returns the HTTP request methods of this {@link RequestMappingInfo};
101-
* or instance with 0 request methods, never {@code null}
98+
* or instance with 0 request methods, never {@code null}.
10299
*/
103100
public RequestMethodsRequestCondition getMethodsCondition() {
104-
return methodsCondition;
101+
return this.methodsCondition;
105102
}
106103

107104
/**
108105
* Returns the "parameters" condition of this {@link RequestMappingInfo};
109-
* or instance with 0 parameter expressions, never {@code null}
106+
* or instance with 0 parameter expressions, never {@code null}.
110107
*/
111108
public ParamsRequestCondition getParamsCondition() {
112-
return paramsCondition;
109+
return this.paramsCondition;
113110
}
114111

115112
/**
116113
* Returns the "headers" condition of this {@link RequestMappingInfo};
117-
* or instance with 0 header expressions, never {@code null}
114+
* or instance with 0 header expressions, never {@code null}.
118115
*/
119116
public HeadersRequestCondition getHeadersCondition() {
120-
return headersCondition;
117+
return this.headersCondition;
121118
}
122119

123120
/**
124121
* Returns the "consumes" condition of this {@link RequestMappingInfo};
125-
* or instance with 0 consumes expressions, never {@code null}
122+
* or instance with 0 consumes expressions, never {@code null}.
126123
*/
127124
public ConsumesRequestCondition getConsumesCondition() {
128-
return consumesCondition;
125+
return this.consumesCondition;
129126
}
130127

131128
/**
132129
* Returns the "produces" condition of this {@link RequestMappingInfo};
133-
* or instance with 0 produces expressions, never {@code null}
130+
* or instance with 0 produces expressions, never {@code null}.
134131
*/
135132
public ProducesRequestCondition getProducesCondition() {
136-
return producesCondition;
133+
return this.producesCondition;
137134
}
138135

139136
/**
140-
* Returns the "custom" condition of this {@link RequestMappingInfo}; or {@code null}
137+
* Returns the "custom" condition of this {@link RequestMappingInfo}; or {@code null}.
141138
*/
142139
public RequestCondition<?> getCustomCondition() {
143-
return customConditionHolder.getCondition();
140+
return this.customConditionHolder.getCondition();
144141
}
145142

143+
146144
/**
147145
* Combines "this" request mapping info (i.e. the current instance) with another request mapping info instance.
148146
* <p>Example: combine type- and method-level request mappings.
@@ -168,61 +166,62 @@ public RequestMappingInfo combine(RequestMappingInfo other) {
168166
* @return a new instance in case all conditions match; or {@code null} otherwise
169167
*/
170168
public RequestMappingInfo getMatchingCondition(HttpServletRequest request) {
171-
RequestMethodsRequestCondition methods = methodsCondition.getMatchingCondition(request);
172-
ParamsRequestCondition params = paramsCondition.getMatchingCondition(request);
173-
HeadersRequestCondition headers = headersCondition.getMatchingCondition(request);
174-
ConsumesRequestCondition consumes = consumesCondition.getMatchingCondition(request);
175-
ProducesRequestCondition produces = producesCondition.getMatchingCondition(request);
169+
RequestMethodsRequestCondition methods = this.methodsCondition.getMatchingCondition(request);
170+
ParamsRequestCondition params = this.paramsCondition.getMatchingCondition(request);
171+
HeadersRequestCondition headers = this.headersCondition.getMatchingCondition(request);
172+
ConsumesRequestCondition consumes = this.consumesCondition.getMatchingCondition(request);
173+
ProducesRequestCondition produces = this.producesCondition.getMatchingCondition(request);
176174

177175
if (methods == null || params == null || headers == null || consumes == null || produces == null) {
178176
return null;
179177
}
180178

181-
PatternsRequestCondition patterns = patternsCondition.getMatchingCondition(request);
179+
PatternsRequestCondition patterns = this.patternsCondition.getMatchingCondition(request);
182180
if (patterns == null) {
183181
return null;
184182
}
185183

186-
RequestConditionHolder custom = customConditionHolder.getMatchingCondition(request);
184+
RequestConditionHolder custom = this.customConditionHolder.getMatchingCondition(request);
187185
if (custom == null) {
188186
return null;
189187
}
190188

191189
return new RequestMappingInfo(patterns, methods, params, headers, consumes, produces, custom.getCondition());
192190
}
193191

192+
194193
/**
195194
* Compares "this" info (i.e. the current instance) with another info in the context of a request.
196-
* <p>Note: it is assumed both instances have been obtained via
195+
* <p>Note: It is assumed both instances have been obtained via
197196
* {@link #getMatchingCondition(HttpServletRequest)} to ensure they have conditions with
198197
* content relevant to current request.
199198
*/
200199
public int compareTo(RequestMappingInfo other, HttpServletRequest request) {
201-
int result = patternsCondition.compareTo(other.getPatternsCondition(), request);
200+
int result = this.patternsCondition.compareTo(other.getPatternsCondition(), request);
202201
if (result != 0) {
203202
return result;
204203
}
205-
result = paramsCondition.compareTo(other.getParamsCondition(), request);
204+
result = this.paramsCondition.compareTo(other.getParamsCondition(), request);
206205
if (result != 0) {
207206
return result;
208207
}
209-
result = headersCondition.compareTo(other.getHeadersCondition(), request);
208+
result = this.headersCondition.compareTo(other.getHeadersCondition(), request);
210209
if (result != 0) {
211210
return result;
212211
}
213-
result = consumesCondition.compareTo(other.getConsumesCondition(), request);
212+
result = this.consumesCondition.compareTo(other.getConsumesCondition(), request);
214213
if (result != 0) {
215214
return result;
216215
}
217-
result = producesCondition.compareTo(other.getProducesCondition(), request);
216+
result = this.producesCondition.compareTo(other.getProducesCondition(), request);
218217
if (result != 0) {
219218
return result;
220219
}
221-
result = methodsCondition.compareTo(other.getMethodsCondition(), request);
220+
result = this.methodsCondition.compareTo(other.getMethodsCondition(), request);
222221
if (result != 0) {
223222
return result;
224223
}
225-
result = customConditionHolder.compareTo(other.customConditionHolder, request);
224+
result = this.customConditionHolder.compareTo(other.customConditionHolder, request);
226225
if (result != 0) {
227226
return result;
228227
}
@@ -249,30 +248,22 @@ public boolean equals(Object obj) {
249248

250249
@Override
251250
public int hashCode() {
252-
int result = hash;
253-
if (result == 0) {
254-
result = patternsCondition.hashCode();
255-
result = 31 * result + methodsCondition.hashCode();
256-
result = 31 * result + paramsCondition.hashCode();
257-
result = 31 * result + headersCondition.hashCode();
258-
result = 31 * result + consumesCondition.hashCode();
259-
result = 31 * result + producesCondition.hashCode();
260-
result = 31 * result + customConditionHolder.hashCode();
261-
hash = result;
262-
}
263-
return result;
251+
return (this.patternsCondition.hashCode() * 31 + // primary differentiation
252+
this.methodsCondition.hashCode() + this.paramsCondition.hashCode() +
253+
this.headersCondition.hashCode() + this.consumesCondition.hashCode() +
254+
this.producesCondition.hashCode() + this.customConditionHolder.hashCode());
264255
}
265256

266257
@Override
267258
public String toString() {
268259
StringBuilder builder = new StringBuilder("{");
269-
builder.append(patternsCondition);
270-
builder.append(",methods=").append(methodsCondition);
271-
builder.append(",params=").append(paramsCondition);
272-
builder.append(",headers=").append(headersCondition);
273-
builder.append(",consumes=").append(consumesCondition);
274-
builder.append(",produces=").append(producesCondition);
275-
builder.append(",custom=").append(customConditionHolder);
260+
builder.append(this.patternsCondition);
261+
builder.append(",methods=").append(this.methodsCondition);
262+
builder.append(",params=").append(this.paramsCondition);
263+
builder.append(",headers=").append(this.headersCondition);
264+
builder.append(",consumes=").append(this.consumesCondition);
265+
builder.append(",produces=").append(this.producesCondition);
266+
builder.append(",custom=").append(this.customConditionHolder);
276267
builder.append('}');
277268
return builder.toString();
278269
}

0 commit comments

Comments
 (0)