Browse Source

Fix race condition in AnntationMethodHER

Issues: SPR-9138
pull/63/head
Rossen Stoyanchev 13 years ago
parent
commit
0b02933938
  1. 34
      spring-webmvc-portlet/src/main/java/org/springframework/web/portlet/mvc/annotation/AnnotationMethodHandlerExceptionResolver.java
  2. 36
      spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerExceptionResolver.java

34
spring-webmvc-portlet/src/main/java/org/springframework/web/portlet/mvc/annotation/AnnotationMethodHandlerExceptionResolver.java

@ -75,8 +75,7 @@ import org.springframework.web.servlet.View;
public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExceptionResolver { public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExceptionResolver {
// dummy method placeholder // dummy method placeholder
private static final Method NO_METHOD_FOUND = ClassUtils private static final Method NO_METHOD_FOUND = ClassUtils.getMethodIfAvailable(System.class, "currentTimeMillis", (Class<?>[]) null);
.getMethodIfAvailable(System.class, "currentTimeMillis", null);
private WebArgumentResolver[] customArgumentResolvers; private WebArgumentResolver[] customArgumentResolvers;
@ -134,10 +133,9 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc
private Method findBestExceptionHandlerMethod(Object handler, final Exception thrownException) { private Method findBestExceptionHandlerMethod(Object handler, final Exception thrownException) {
final Class<?> handlerType = handler.getClass(); final Class<?> handlerType = handler.getClass();
final Class<? extends Throwable> thrownExceptionType = thrownException.getClass(); final Class<? extends Throwable> thrownExceptionType = thrownException.getClass();
Method handlerMethod = null; Method handlerMethod = null;
Map<Class<? extends Throwable>, Method> handlers = exceptionHandlerCache
.get(handlerType); Map<Class<? extends Throwable>, Method> handlers = exceptionHandlerCache.get(handlerType);
if (handlers != null) { if (handlers != null) {
handlerMethod = handlers.get(thrownExceptionType); handlerMethod = handlers.get(thrownExceptionType);
@ -173,7 +171,9 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc
} }
}); });
return getBestMatchingMethod(resolverMethods, thrownException); handlerMethod = getBestMatchingMethod(resolverMethods, thrownException);
handlers.put(thrownExceptionType, (handlerMethod == null ? NO_METHOD_FOUND : handlerMethod));
return handlerMethod;
} }
/** /**
@ -204,19 +204,19 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc
} }
/** /**
* Returns the best matching method. Uses the {@link DepthComparator}. * Uses the {@link DepthComparator} to find the best matching method
* @return the best matching method or {@code null}.
*/ */
private Method getBestMatchingMethod( private Method getBestMatchingMethod(
Map<Class<? extends Throwable>, Method> resolverMethods, Exception thrownException) { Map<Class<? extends Throwable>, Method> resolverMethods, Exception thrownException) {
if (!resolverMethods.isEmpty()) { if (resolverMethods.isEmpty()) {
Class<? extends Throwable> closestMatch =
ExceptionDepthComparator.findClosestMatch(resolverMethods.keySet(), thrownException);
return resolverMethods.get(closestMatch);
}
else {
return null; return null;
} }
Class<? extends Throwable> closestMatch =
ExceptionDepthComparator.findClosestMatch(resolverMethods.keySet(), thrownException);
Method method = resolverMethods.get(closestMatch);
return ((method == null) || (NO_METHOD_FOUND == method)) ? null : method;
} }
/** /**
@ -225,13 +225,13 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc
private Object[] resolveHandlerArguments(Method handlerMethod, Object handler, private Object[] resolveHandlerArguments(Method handlerMethod, Object handler,
NativeWebRequest webRequest, Exception thrownException) throws Exception { NativeWebRequest webRequest, Exception thrownException) throws Exception {
Class[] paramTypes = handlerMethod.getParameterTypes(); Class<?>[] paramTypes = handlerMethod.getParameterTypes();
Object[] args = new Object[paramTypes.length]; Object[] args = new Object[paramTypes.length];
Class<?> handlerType = handler.getClass(); Class<?> handlerType = handler.getClass();
for (int i = 0; i < args.length; i++) { for (int i = 0; i < args.length; i++) {
MethodParameter methodParam = new MethodParameter(handlerMethod, i); MethodParameter methodParam = new MethodParameter(handlerMethod, i);
GenericTypeResolver.resolveParameterType(methodParam, handlerType); GenericTypeResolver.resolveParameterType(methodParam, handlerType);
Class paramType = methodParam.getParameterType(); Class<?> paramType = methodParam.getParameterType();
Object argValue = resolveCommonArgument(methodParam, webRequest, thrownException); Object argValue = resolveCommonArgument(methodParam, webRequest, thrownException);
if (argValue != WebArgumentResolver.UNRESOLVED) { if (argValue != WebArgumentResolver.UNRESOLVED) {
args[i] = argValue; args[i] = argValue;
@ -267,7 +267,7 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc
} }
// Resolution of standard parameter types... // Resolution of standard parameter types...
Class paramType = methodParameter.getParameterType(); Class<?> paramType = methodParameter.getParameterType();
Object value = resolveStandardArgument(paramType, webRequest, thrownException); Object value = resolveStandardArgument(paramType, webRequest, thrownException);
if (value != WebArgumentResolver.UNRESOLVED && !ClassUtils.isAssignableValue(paramType, value)) { if (value != WebArgumentResolver.UNRESOLVED && !ClassUtils.isAssignableValue(paramType, value)) {
throw new IllegalStateException("Standard argument type [" + paramType.getName() + throw new IllegalStateException("Standard argument type [" + paramType.getName() +
@ -287,7 +287,7 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc
* @param thrownException the exception thrown * @param thrownException the exception thrown
* @return the argument value, or {@link org.springframework.web.bind.support.WebArgumentResolver#UNRESOLVED} * @return the argument value, or {@link org.springframework.web.bind.support.WebArgumentResolver#UNRESOLVED}
*/ */
protected Object resolveStandardArgument(Class parameterType, NativeWebRequest webRequest, protected Object resolveStandardArgument(Class<?> parameterType, NativeWebRequest webRequest,
Exception thrownException) throws Exception { Exception thrownException) throws Exception {
if (parameterType.isInstance(thrownException)) { if (parameterType.isInstance(thrownException)) {

36
spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerExceptionResolver.java

@ -84,10 +84,10 @@ import org.springframework.web.servlet.support.RequestContextUtils;
public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExceptionResolver { public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExceptionResolver {
// dummy method placeholder // dummy method placeholder
private static final Method NO_METHOD_FOUND = ClassUtils.getMethodIfAvailable(System.class, "currentTimeMillis", null); private static final Method NO_METHOD_FOUND = ClassUtils.getMethodIfAvailable(System.class, "currentTimeMillis", (Class<?>[]) null);
private final Map<Class<?>, Map<Class<? extends Throwable>, Method>> exceptionHandlerCache = private final Map<Class<?>, Map<Class<? extends Throwable>, Method>> exceptionHandlerCache =
new ConcurrentHashMap<Class<?>, Map<Class<? extends Throwable>, Method>>(); new ConcurrentHashMap<Class<?>, Map<Class<? extends Throwable>, Method>>();
private WebArgumentResolver[] customArgumentResolvers; private WebArgumentResolver[] customArgumentResolvers;
@ -157,7 +157,7 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc
final Class<?> handlerType = ClassUtils.getUserClass(handler); final Class<?> handlerType = ClassUtils.getUserClass(handler);
final Class<? extends Throwable> thrownExceptionType = thrownException.getClass(); final Class<? extends Throwable> thrownExceptionType = thrownException.getClass();
Method handlerMethod = null; Method handlerMethod = null;
Map<Class<? extends Throwable>, Method> handlers = exceptionHandlerCache.get(handlerType); Map<Class<? extends Throwable>, Method> handlers = exceptionHandlerCache.get(handlerType);
if (handlers != null) { if (handlers != null) {
@ -170,7 +170,7 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc
handlers = new ConcurrentHashMap<Class<? extends Throwable>, Method>(); handlers = new ConcurrentHashMap<Class<? extends Throwable>, Method>();
exceptionHandlerCache.put(handlerType, handlers); exceptionHandlerCache.put(handlerType, handlers);
} }
final Map<Class<? extends Throwable>, Method> resolverMethods = handlers; final Map<Class<? extends Throwable>, Method> resolverMethods = handlers;
ReflectionUtils.doWithMethods(handlerType, new ReflectionUtils.MethodCallback() { ReflectionUtils.doWithMethods(handlerType, new ReflectionUtils.MethodCallback() {
@ -228,19 +228,19 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc
} }
/** /**
* Returns the best matching method. Uses the {@link DepthComparator}. * Uses the {@link DepthComparator} to find the best matching method
* @return the best matching method or {@code null}.
*/ */
private Method getBestMatchingMethod( private Method getBestMatchingMethod(
Map<Class<? extends Throwable>, Method> resolverMethods, Exception thrownException) { Map<Class<? extends Throwable>, Method> resolverMethods, Exception thrownException) {
if (!resolverMethods.isEmpty()) { if (resolverMethods.isEmpty()) {
Class<? extends Throwable> closestMatch =
ExceptionDepthComparator.findClosestMatch(resolverMethods.keySet(), thrownException);
return resolverMethods.get(closestMatch);
}
else {
return null; return null;
} }
Class<? extends Throwable> closestMatch =
ExceptionDepthComparator.findClosestMatch(resolverMethods.keySet(), thrownException);
Method method = resolverMethods.get(closestMatch);
return ((method == null) || (NO_METHOD_FOUND == method)) ? null : method;
} }
/** /**
@ -249,13 +249,13 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc
private Object[] resolveHandlerArguments(Method handlerMethod, Object handler, private Object[] resolveHandlerArguments(Method handlerMethod, Object handler,
NativeWebRequest webRequest, Exception thrownException) throws Exception { NativeWebRequest webRequest, Exception thrownException) throws Exception {
Class[] paramTypes = handlerMethod.getParameterTypes(); Class<?>[] paramTypes = handlerMethod.getParameterTypes();
Object[] args = new Object[paramTypes.length]; Object[] args = new Object[paramTypes.length];
Class<?> handlerType = handler.getClass(); Class<?> handlerType = handler.getClass();
for (int i = 0; i < args.length; i++) { for (int i = 0; i < args.length; i++) {
MethodParameter methodParam = new MethodParameter(handlerMethod, i); MethodParameter methodParam = new MethodParameter(handlerMethod, i);
GenericTypeResolver.resolveParameterType(methodParam, handlerType); GenericTypeResolver.resolveParameterType(methodParam, handlerType);
Class paramType = methodParam.getParameterType(); Class<?> paramType = methodParam.getParameterType();
Object argValue = resolveCommonArgument(methodParam, webRequest, thrownException); Object argValue = resolveCommonArgument(methodParam, webRequest, thrownException);
if (argValue != WebArgumentResolver.UNRESOLVED) { if (argValue != WebArgumentResolver.UNRESOLVED) {
args[i] = argValue; args[i] = argValue;
@ -290,7 +290,7 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc
} }
// Resolution of standard parameter types... // Resolution of standard parameter types...
Class paramType = methodParameter.getParameterType(); Class<?> paramType = methodParameter.getParameterType();
Object value = resolveStandardArgument(paramType, webRequest, thrownException); Object value = resolveStandardArgument(paramType, webRequest, thrownException);
if (value != WebArgumentResolver.UNRESOLVED && !ClassUtils.isAssignableValue(paramType, value)) { if (value != WebArgumentResolver.UNRESOLVED && !ClassUtils.isAssignableValue(paramType, value)) {
throw new IllegalStateException( throw new IllegalStateException(
@ -311,7 +311,7 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc
* @param thrownException the exception thrown * @param thrownException the exception thrown
* @return the argument value, or {@link WebArgumentResolver#UNRESOLVED} * @return the argument value, or {@link WebArgumentResolver#UNRESOLVED}
*/ */
protected Object resolveStandardArgument(Class parameterType, NativeWebRequest webRequest, protected Object resolveStandardArgument(Class<?> parameterType, NativeWebRequest webRequest,
Exception thrownException) throws Exception { Exception thrownException) throws Exception {
if (parameterType.isInstance(thrownException)) { if (parameterType.isInstance(thrownException)) {
@ -395,7 +395,7 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc
return new ModelAndView().addAllObjects(((Model) returnValue).asMap()); return new ModelAndView().addAllObjects(((Model) returnValue).asMap());
} }
else if (returnValue instanceof Map) { else if (returnValue instanceof Map) {
return new ModelAndView().addAllObjects((Map) returnValue); return new ModelAndView().addAllObjects((Map<String, Object>) returnValue);
} }
else if (returnValue instanceof View) { else if (returnValue instanceof View) {
return new ModelAndView((View) returnValue); return new ModelAndView((View) returnValue);

Loading…
Cancel
Save