From 7e3c72214680695bb75a3c24e870935fc359194e Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Fri, 14 Feb 2014 20:46:34 +0100 Subject: [PATCH] Objects with multi-threaded access should not lazily populate a hash field Issue. SPR-11428 (cherry picked from commit 72fe7eb) --- .../springframework/core/MethodParameter.java | 46 +++---- .../mvc/method/RequestMappingInfo.java | 119 ++++++++---------- .../mvc/method/RequestMappingInfoTests.java | 30 ++--- 3 files changed, 82 insertions(+), 113 deletions(-) diff --git a/spring-core/src/main/java/org/springframework/core/MethodParameter.java b/spring-core/src/main/java/org/springframework/core/MethodParameter.java index d2f497d814..1325db2ad7 100644 --- a/spring-core/src/main/java/org/springframework/core/MethodParameter.java +++ b/spring-core/src/main/java/org/springframework/core/MethodParameter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2014 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -44,7 +44,7 @@ public class MethodParameter { private final Method method; - private final Constructor constructor; + private final Constructor constructor; private final int parameterIndex; @@ -65,8 +65,6 @@ public class MethodParameter { Map typeVariableMap; - private int hash = 0; - /** * Create a new MethodParameter for the given method, with nesting level 1. @@ -100,7 +98,7 @@ public class MethodParameter { * @param constructor the Constructor to specify a parameter for * @param parameterIndex the index of the parameter */ - public MethodParameter(Constructor constructor, int parameterIndex) { + public MethodParameter(Constructor constructor, int parameterIndex) { this(constructor, parameterIndex, 1); } @@ -112,7 +110,7 @@ public class MethodParameter { * (typically 1; e.g. in case of a List of Lists, 1 would indicate the * nested List, whereas 2 would indicate the element of the nested List) */ - public MethodParameter(Constructor constructor, int parameterIndex, int nestingLevel) { + public MethodParameter(Constructor constructor, int parameterIndex, int nestingLevel) { Assert.notNull(constructor, "Constructor must not be null"); this.constructor = constructor; this.parameterIndex = parameterIndex; @@ -138,7 +136,6 @@ public class MethodParameter { this.nestingLevel = original.nestingLevel; this.typeIndexesPerLevel = original.typeIndexesPerLevel; this.typeVariableMap = original.typeVariableMap; - this.hash = original.hash; } @@ -156,24 +153,24 @@ public class MethodParameter { *

Note: Either Method or Constructor is available. * @return the Constructor, or {@code null} if none */ - public Constructor getConstructor() { + public Constructor getConstructor() { return this.constructor; } /** * Returns the wrapped member. - * @return the member + * @return the Method or Constructor as Member */ private Member getMember() { - return this.method != null ? this.method : this.constructor; + return (this.method != null ? this.method : this.constructor); } /** * Returns the wrapped annotated element. - * @return the annotated element + * @return the Method or Constructor as AnnotatedElement */ private AnnotatedElement getAnnotatedElement() { - return this.method != null ? this.method : this.constructor; + return (this.method != null ? this.method : this.constructor); } /** @@ -241,12 +238,12 @@ public class MethodParameter { Integer index = getTypeIndexForCurrentLevel(); Type arg = ((ParameterizedType) type).getActualTypeArguments()[index != null ? index : 0]; if (arg instanceof Class) { - return (Class) arg; + return (Class) arg; } else if (arg instanceof ParameterizedType) { arg = ((ParameterizedType) arg).getRawType(); if (arg instanceof Class) { - return (Class) arg; + return (Class) arg; } } } @@ -423,29 +420,14 @@ public class MethodParameter { } if (obj != null && obj instanceof MethodParameter) { MethodParameter other = (MethodParameter) obj; - - if (this.parameterIndex != other.parameterIndex) { - return false; - } - else if (this.getMember().equals(other.getMember())) { - return true; - } - else { - return false; - } + return (this.parameterIndex == other.parameterIndex && getMember().equals(other.getMember())); } return false; } @Override public int hashCode() { - int result = this.hash; - if (result == 0) { - result = getMember().hashCode(); - result = 31 * result + this.parameterIndex; - this.hash = result; - } - return result; + return (getMember().hashCode() * 31 + this.parameterIndex); } @@ -462,7 +444,7 @@ public class MethodParameter { return new MethodParameter((Method) methodOrConstructor, parameterIndex); } else if (methodOrConstructor instanceof Constructor) { - return new MethodParameter((Constructor) methodOrConstructor, parameterIndex); + return new MethodParameter((Constructor) methodOrConstructor, parameterIndex); } else { throw new IllegalArgumentException( diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/RequestMappingInfo.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/RequestMappingInfo.java index 6d0e3941e6..b517e79c7a 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/RequestMappingInfo.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/RequestMappingInfo.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2014 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,7 +36,7 @@ import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondit *

  • {@link HeadersRequestCondition} *
  • {@link ConsumesRequestCondition} *
  • {@link ProducesRequestCondition} - *
  • {@code RequestCondition} (optional, custom request condition) + *
  • {@code RequestCondition} (optional, custom request condition) * * * @author Arjen Poutsma @@ -59,24 +59,20 @@ public final class RequestMappingInfo implements RequestCondition custom) { - this.patternsCondition = patterns != null ? patterns : new PatternsRequestCondition(); - this.methodsCondition = methods != null ? methods : new RequestMethodsRequestCondition(); - this.paramsCondition = params != null ? params : new ParamsRequestCondition(); - this.headersCondition = headers != null ? headers : new HeadersRequestCondition(); - this.consumesCondition = consumes != null ? consumes : new ConsumesRequestCondition(); - this.producesCondition = produces != null ? produces : new ProducesRequestCondition(); + public RequestMappingInfo(PatternsRequestCondition patterns, RequestMethodsRequestCondition methods, + ParamsRequestCondition params, HeadersRequestCondition headers, ConsumesRequestCondition consumes, + ProducesRequestCondition produces, RequestCondition custom) { + + this.patternsCondition = (patterns != null ? patterns : new PatternsRequestCondition()); + this.methodsCondition = (methods != null ? methods : new RequestMethodsRequestCondition()); + this.paramsCondition = (params != null ? params : new ParamsRequestCondition()); + this.headersCondition = (headers != null ? headers : new HeadersRequestCondition()); + this.consumesCondition = (consumes != null ? consumes : new ConsumesRequestCondition()); + this.producesCondition = (produces != null ? produces : new ProducesRequestCondition()); this.customConditionHolder = new RequestConditionHolder(custom); } @@ -88,61 +84,63 @@ public final class RequestMappingInfo implements RequestCondition getCustomCondition() { - return customConditionHolder.getCondition(); + return this.customConditionHolder.getCondition(); } + /** * Combines "this" request mapping info (i.e. the current instance) with another request mapping info instance. *

    Example: combine type- and method-level request mappings. @@ -168,22 +166,22 @@ public final class RequestMappingInfo implements RequestConditionNote: it is assumed both instances have been obtained via + *

    Note: It is assumed both instances have been obtained via * {@link #getMatchingCondition(HttpServletRequest)} to ensure they have conditions with * content relevant to current request. */ public int compareTo(RequestMappingInfo other, HttpServletRequest request) { - int result = patternsCondition.compareTo(other.getPatternsCondition(), request); + int result = this.patternsCondition.compareTo(other.getPatternsCondition(), request); if (result != 0) { return result; } - result = paramsCondition.compareTo(other.getParamsCondition(), request); + result = this.paramsCondition.compareTo(other.getParamsCondition(), request); if (result != 0) { return result; } - result = headersCondition.compareTo(other.getHeadersCondition(), request); + result = this.headersCondition.compareTo(other.getHeadersCondition(), request); if (result != 0) { return result; } - result = consumesCondition.compareTo(other.getConsumesCondition(), request); + result = this.consumesCondition.compareTo(other.getConsumesCondition(), request); if (result != 0) { return result; } - result = producesCondition.compareTo(other.getProducesCondition(), request); + result = this.producesCondition.compareTo(other.getProducesCondition(), request); if (result != 0) { return result; } - result = methodsCondition.compareTo(other.getMethodsCondition(), request); + result = this.methodsCondition.compareTo(other.getMethodsCondition(), request); if (result != 0) { return result; } - result = customConditionHolder.compareTo(other.customConditionHolder, request); + result = this.customConditionHolder.compareTo(other.customConditionHolder, request); if (result != 0) { return result; } @@ -249,30 +248,22 @@ public final class RequestMappingInfo implements RequestCondition