Skip to content

Commit 72fe7eb

Browse files
committed
Objects with multi-threaded access should not lazily populate a hash field
Issue. SPR-11428
1 parent 6fba829 commit 72fe7eb

File tree

4 files changed

+75
-116
lines changed

4 files changed

+75
-116
lines changed

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

Lines changed: 3 additions & 21 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.
@@ -64,8 +64,6 @@ public class MethodParameter {
6464
/** Map from Integer level to Integer type index */
6565
Map<Integer, Integer> typeIndexesPerLevel;
6666

67-
private int hash = 0;
68-
6967

7068
/**
7169
* Create a new MethodParameter for the given method, with nesting level 1.
@@ -137,7 +135,6 @@ public MethodParameter(MethodParameter original) {
137135
this.parameterName = original.parameterName;
138136
this.nestingLevel = original.nestingLevel;
139137
this.typeIndexesPerLevel = original.typeIndexesPerLevel;
140-
this.hash = original.hash;
141138
}
142139

143140

@@ -450,29 +447,14 @@ public boolean equals(Object obj) {
450447
}
451448
if (obj != null && obj instanceof MethodParameter) {
452449
MethodParameter other = (MethodParameter) obj;
453-
454-
if (this.parameterIndex != other.parameterIndex) {
455-
return false;
456-
}
457-
else if (this.getMember().equals(other.getMember())) {
458-
return true;
459-
}
460-
else {
461-
return false;
462-
}
450+
return (this.parameterIndex == other.parameterIndex && getMember().equals(other.getMember()));
463451
}
464452
return false;
465453
}
466454

467455
@Override
468456
public int hashCode() {
469-
int result = this.hash;
470-
if (result == 0) {
471-
result = getMember().hashCode();
472-
result = 31 * result + this.parameterIndex;
473-
this.hash = result;
474-
}
475-
return result;
457+
return (getMember().hashCode() * 31 + this.parameterIndex);
476458
}
477459

478460

spring-messaging/src/main/java/org/springframework/messaging/simp/SimpMessageMappingInfo.java

Lines changed: 4 additions & 14 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.
@@ -36,8 +36,6 @@ public class SimpMessageMappingInfo implements MessageCondition<SimpMessageMappi
3636

3737
private final DestinationPatternsMessageCondition destinationConditions;
3838

39-
private int hash;
40-
4139

4240
public SimpMessageMappingInfo(SimpMessageTypeMessageCondition messageTypeMessageCondition,
4341
DestinationPatternsMessageCondition destinationConditions) {
@@ -58,13 +56,10 @@ public DestinationPatternsMessageCondition getDestinationConditions() {
5856

5957
@Override
6058
public SimpMessageMappingInfo combine(SimpMessageMappingInfo other) {
61-
6259
SimpMessageTypeMessageCondition typeCond =
6360
this.getMessageTypeMessageCondition().combine(other.getMessageTypeMessageCondition());
64-
6561
DestinationPatternsMessageCondition destCond =
6662
this.destinationConditions.combine(other.getDestinationConditions());
67-
6863
return new SimpMessageMappingInfo(typeCond, destCond);
6964
}
7065

@@ -102,20 +97,15 @@ public boolean equals(Object obj) {
10297
}
10398
if (obj != null && obj instanceof SimpMessageMappingInfo) {
10499
SimpMessageMappingInfo other = (SimpMessageMappingInfo) obj;
105-
return this.destinationConditions.equals(other.destinationConditions);
100+
return (this.destinationConditions.equals(other.destinationConditions) &&
101+
this.messageTypeMessageCondition.equals(other.messageTypeMessageCondition));
106102
}
107103
return false;
108104
}
109105

110106
@Override
111107
public int hashCode() {
112-
int result = hash;
113-
if (result == 0) {
114-
result = destinationConditions.hashCode();
115-
result = 31 * result + messageTypeMessageCondition.hashCode();
116-
hash = result;
117-
}
118-
return result;
108+
return (this.destinationConditions.hashCode() * 31 + this.messageTypeMessageCondition.hashCode());
119109
}
120110

121111
@Override

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.
@@ -170,62 +168,63 @@ public RequestMappingInfo combine(RequestMappingInfo other) {
170168
*/
171169
@Override
172170
public RequestMappingInfo getMatchingCondition(HttpServletRequest request) {
173-
RequestMethodsRequestCondition methods = methodsCondition.getMatchingCondition(request);
174-
ParamsRequestCondition params = paramsCondition.getMatchingCondition(request);
175-
HeadersRequestCondition headers = headersCondition.getMatchingCondition(request);
176-
ConsumesRequestCondition consumes = consumesCondition.getMatchingCondition(request);
177-
ProducesRequestCondition produces = producesCondition.getMatchingCondition(request);
171+
RequestMethodsRequestCondition methods = this.methodsCondition.getMatchingCondition(request);
172+
ParamsRequestCondition params = this.paramsCondition.getMatchingCondition(request);
173+
HeadersRequestCondition headers = this.headersCondition.getMatchingCondition(request);
174+
ConsumesRequestCondition consumes = this.consumesCondition.getMatchingCondition(request);
175+
ProducesRequestCondition produces = this.producesCondition.getMatchingCondition(request);
178176

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

183-
PatternsRequestCondition patterns = patternsCondition.getMatchingCondition(request);
181+
PatternsRequestCondition patterns = this.patternsCondition.getMatchingCondition(request);
184182
if (patterns == null) {
185183
return null;
186184
}
187185

188-
RequestConditionHolder custom = customConditionHolder.getMatchingCondition(request);
186+
RequestConditionHolder custom = this.customConditionHolder.getMatchingCondition(request);
189187
if (custom == null) {
190188
return null;
191189
}
192190

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

194+
196195
/**
197196
* Compares "this" info (i.e. the current instance) with another info in the context of a request.
198-
* <p>Note: it is assumed both instances have been obtained via
197+
* <p>Note: It is assumed both instances have been obtained via
199198
* {@link #getMatchingCondition(HttpServletRequest)} to ensure they have conditions with
200199
* content relevant to current request.
201200
*/
202201
@Override
203202
public int compareTo(RequestMappingInfo other, HttpServletRequest request) {
204-
int result = patternsCondition.compareTo(other.getPatternsCondition(), request);
203+
int result = this.patternsCondition.compareTo(other.getPatternsCondition(), request);
205204
if (result != 0) {
206205
return result;
207206
}
208-
result = paramsCondition.compareTo(other.getParamsCondition(), request);
207+
result = this.paramsCondition.compareTo(other.getParamsCondition(), request);
209208
if (result != 0) {
210209
return result;
211210
}
212-
result = headersCondition.compareTo(other.getHeadersCondition(), request);
211+
result = this.headersCondition.compareTo(other.getHeadersCondition(), request);
213212
if (result != 0) {
214213
return result;
215214
}
216-
result = consumesCondition.compareTo(other.getConsumesCondition(), request);
215+
result = this.consumesCondition.compareTo(other.getConsumesCondition(), request);
217216
if (result != 0) {
218217
return result;
219218
}
220-
result = producesCondition.compareTo(other.getProducesCondition(), request);
219+
result = this.producesCondition.compareTo(other.getProducesCondition(), request);
221220
if (result != 0) {
222221
return result;
223222
}
224-
result = methodsCondition.compareTo(other.getMethodsCondition(), request);
223+
result = this.methodsCondition.compareTo(other.getMethodsCondition(), request);
225224
if (result != 0) {
226225
return result;
227226
}
228-
result = customConditionHolder.compareTo(other.customConditionHolder, request);
227+
result = this.customConditionHolder.compareTo(other.customConditionHolder, request);
229228
if (result != 0) {
230229
return result;
231230
}
@@ -252,30 +251,22 @@ public boolean equals(Object obj) {
252251

253252
@Override
254253
public int hashCode() {
255-
int result = hash;
256-
if (result == 0) {
257-
result = patternsCondition.hashCode();
258-
result = 31 * result + methodsCondition.hashCode();
259-
result = 31 * result + paramsCondition.hashCode();
260-
result = 31 * result + headersCondition.hashCode();
261-
result = 31 * result + consumesCondition.hashCode();
262-
result = 31 * result + producesCondition.hashCode();
263-
result = 31 * result + customConditionHolder.hashCode();
264-
hash = result;
265-
}
266-
return result;
254+
return (this.patternsCondition.hashCode() * 31 + // primary differentiation
255+
this.methodsCondition.hashCode() + this.paramsCondition.hashCode() +
256+
this.headersCondition.hashCode() + this.consumesCondition.hashCode() +
257+
this.producesCondition.hashCode() + this.customConditionHolder.hashCode());
267258
}
268259

269260
@Override
270261
public String toString() {
271262
StringBuilder builder = new StringBuilder("{");
272-
builder.append(patternsCondition);
273-
builder.append(",methods=").append(methodsCondition);
274-
builder.append(",params=").append(paramsCondition);
275-
builder.append(",headers=").append(headersCondition);
276-
builder.append(",consumes=").append(consumesCondition);
277-
builder.append(",produces=").append(producesCondition);
278-
builder.append(",custom=").append(customConditionHolder);
263+
builder.append(this.patternsCondition);
264+
builder.append(",methods=").append(this.methodsCondition);
265+
builder.append(",params=").append(this.paramsCondition);
266+
builder.append(",headers=").append(this.headersCondition);
267+
builder.append(",consumes=").append(this.consumesCondition);
268+
builder.append(",produces=").append(this.producesCondition);
269+
builder.append(",custom=").append(this.customConditionHolder);
279270
builder.append('}');
280271
return builder.toString();
281272
}

0 commit comments

Comments
 (0)