diff --git a/spring-core/src/main/java/org/springframework/core/BridgeMethodResolver.java b/spring-core/src/main/java/org/springframework/core/BridgeMethodResolver.java index 1027d4dfc9..d0cf60aa83 100644 --- a/spring-core/src/main/java/org/springframework/core/BridgeMethodResolver.java +++ b/spring-core/src/main/java/org/springframework/core/BridgeMethodResolver.java @@ -16,14 +16,11 @@ package org.springframework.core; -import java.lang.reflect.GenericArrayType; import java.lang.reflect.Method; import java.lang.reflect.Type; -import java.lang.reflect.TypeVariable; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.Map; import org.springframework.util.ClassUtils; import org.springframework.util.ReflectionUtils; @@ -44,6 +41,7 @@ import org.springframework.util.ReflectionUtils; * * @author Rob Harrop * @author Juergen Hoeller + * @author Phillip Webb * @since 2.0 */ public abstract class BridgeMethodResolver { @@ -86,6 +84,18 @@ public abstract class BridgeMethodResolver { } } + /** + * Returns {@code true} if the supplied '{@code candidateMethod}' can be + * consider a validate candidate for the {@link Method} that is {@link Method#isBridge() bridged} + * by the supplied {@link Method bridge Method}. This method performs inexpensive + * checks and can be used quickly filter for a set of possible matches. + */ + private static boolean isBridgedCandidateFor(Method candidateMethod, Method bridgeMethod) { + return (!candidateMethod.isBridge() && !candidateMethod.equals(bridgeMethod) && + candidateMethod.getName().equals(bridgeMethod.getName()) && + candidateMethod.getParameterTypes().length == bridgeMethod.getParameterTypes().length); + } + /** * Searches for the bridged method in the given candidates. * @param candidateMethods the List of candidate Methods @@ -96,11 +106,10 @@ public abstract class BridgeMethodResolver { if (candidateMethods.isEmpty()) { return null; } - Map typeParameterMap = GenericTypeResolver.getTypeVariableMap(bridgeMethod.getDeclaringClass()); Method previousMethod = null; boolean sameSig = true; for (Method candidateMethod : candidateMethods) { - if (isBridgeMethodFor(bridgeMethod, candidateMethod, typeParameterMap)) { + if (isBridgeMethodFor(bridgeMethod, candidateMethod, bridgeMethod.getDeclaringClass())) { return candidateMethod; } else if (previousMethod != null) { @@ -112,28 +121,16 @@ public abstract class BridgeMethodResolver { return (sameSig ? candidateMethods.get(0) : null); } - /** - * Returns {@code true} if the supplied '{@code candidateMethod}' can be - * consider a validate candidate for the {@link Method} that is {@link Method#isBridge() bridged} - * by the supplied {@link Method bridge Method}. This method performs inexpensive - * checks and can be used quickly filter for a set of possible matches. - */ - private static boolean isBridgedCandidateFor(Method candidateMethod, Method bridgeMethod) { - return (!candidateMethod.isBridge() && !candidateMethod.equals(bridgeMethod) && - candidateMethod.getName().equals(bridgeMethod.getName()) && - candidateMethod.getParameterTypes().length == bridgeMethod.getParameterTypes().length); - } - /** * Determines whether or not the bridge {@link Method} is the bridge for the * supplied candidate {@link Method}. */ - static boolean isBridgeMethodFor(Method bridgeMethod, Method candidateMethod, Map typeVariableMap) { - if (isResolvedTypeMatch(candidateMethod, bridgeMethod, typeVariableMap)) { + static boolean isBridgeMethodFor(Method bridgeMethod, Method candidateMethod, Class declaringClass) { + if (isResolvedTypeMatch(candidateMethod, bridgeMethod, declaringClass)) { return true; } Method method = findGenericDeclaration(bridgeMethod); - return (method != null && isResolvedTypeMatch(method, candidateMethod, typeVariableMap)); + return (method != null && isResolvedTypeMatch(method, candidateMethod, declaringClass)); } /** @@ -167,34 +164,27 @@ public abstract class BridgeMethodResolver { /** * Returns {@code true} if the {@link Type} signature of both the supplied * {@link Method#getGenericParameterTypes() generic Method} and concrete {@link Method} - * are equal after resolving all {@link TypeVariable TypeVariables} using the supplied - * TypeVariable Map, otherwise returns {@code false}. + * are equal after resolving all types against the declaringType, otherwise + * returns {@code false}. */ private static boolean isResolvedTypeMatch( - Method genericMethod, Method candidateMethod, Map typeVariableMap) { - + Method genericMethod, Method candidateMethod, Class declaringClass) { Type[] genericParameters = genericMethod.getGenericParameterTypes(); Class[] candidateParameters = candidateMethod.getParameterTypes(); if (genericParameters.length != candidateParameters.length) { return false; } - for (int i = 0; i < genericParameters.length; i++) { - Type genericParameter = genericParameters[i]; + for (int i = 0; i < candidateParameters.length; i++) { + ResolvableType genericParameter = ResolvableType.forMethodParameter(genericMethod, i, declaringClass); Class candidateParameter = candidateParameters[i]; if (candidateParameter.isArray()) { // An array type: compare the component type. - Type rawType = GenericTypeResolver.getRawType(genericParameter, typeVariableMap); - if (rawType instanceof GenericArrayType) { - if (!candidateParameter.getComponentType().equals( - GenericTypeResolver.resolveType(((GenericArrayType) rawType).getGenericComponentType(), typeVariableMap))) { - return false; - } - break; + if (!candidateParameter.getComponentType().equals(genericParameter.getComponentType().resolve(Object.class))) { + return false; } } // A non-array type: compare the type itself. - Class resolvedParameter = GenericTypeResolver.resolveType(genericParameter, typeVariableMap); - if (!candidateParameter.equals(resolvedParameter)) { + if (!candidateParameter.equals(genericParameter.resolve(Object.class))) { return false; } } diff --git a/spring-core/src/test/java/org/springframework/core/BridgeMethodResolverTests.java b/spring-core/src/test/java/org/springframework/core/BridgeMethodResolverTests.java index dbca8b7b5b..86ebb9b791 100644 --- a/spring-core/src/test/java/org/springframework/core/BridgeMethodResolverTests.java +++ b/spring-core/src/test/java/org/springframework/core/BridgeMethodResolverTests.java @@ -31,11 +31,11 @@ import java.util.Map; import java.util.concurrent.DelayQueue; import java.util.concurrent.Delayed; -import static org.junit.Assert.*; import org.junit.Test; - import org.springframework.util.ReflectionUtils; +import static org.junit.Assert.*; + /** * @author Rob Harrop * @author Juergen Hoeller @@ -99,16 +99,16 @@ public class BridgeMethodResolverTests { @Test public void testIsBridgeMethodFor() throws Exception { - Map typeParameterMap = GenericTypeResolver.getTypeVariableMap(MyBar.class); Method bridged = MyBar.class.getDeclaredMethod("someMethod", String.class, Object.class); Method other = MyBar.class.getDeclaredMethod("someMethod", Integer.class, Object.class); Method bridge = MyBar.class.getDeclaredMethod("someMethod", Object.class, Object.class); - assertTrue("Should be bridge method", BridgeMethodResolver.isBridgeMethodFor(bridge, bridged, typeParameterMap)); - assertFalse("Should not be bridge method", BridgeMethodResolver.isBridgeMethodFor(bridge, other, typeParameterMap)); + assertTrue("Should be bridge method", BridgeMethodResolver.isBridgeMethodFor(bridge, bridged, MyBar.class)); + assertFalse("Should not be bridge method", BridgeMethodResolver.isBridgeMethodFor(bridge, other, MyBar.class)); } @Test + @Deprecated public void testCreateTypeVariableMap() throws Exception { Map typeVariableMap = GenericTypeResolver.getTypeVariableMap(MyBar.class); TypeVariable barT = findTypeVariable(InterBar.class, "T"); @@ -220,14 +220,14 @@ public class BridgeMethodResolverTests { Method otherMethod = MessageBroadcasterImpl.class.getMethod("receive", NewMessageEvent.class); assertFalse(otherMethod.isBridge()); - Map typeVariableMap = GenericTypeResolver.getTypeVariableMap(MessageBroadcasterImpl.class); - assertFalse("Match identified incorrectly", BridgeMethodResolver.isBridgeMethodFor(bridgeMethod, otherMethod, typeVariableMap)); - assertTrue("Match not found correctly", BridgeMethodResolver.isBridgeMethodFor(bridgeMethod, bridgedMethod, typeVariableMap)); + assertFalse("Match identified incorrectly", BridgeMethodResolver.isBridgeMethodFor(bridgeMethod, otherMethod, MessageBroadcasterImpl.class)); + assertTrue("Match not found correctly", BridgeMethodResolver.isBridgeMethodFor(bridgeMethod, bridgedMethod, MessageBroadcasterImpl.class)); assertEquals(bridgedMethod, BridgeMethodResolver.findBridgedMethod(bridgeMethod)); } @Test + @Deprecated public void testSPR2454() throws Exception { Map typeVariableMap = GenericTypeResolver.getTypeVariableMap(YourHomer.class); TypeVariable variable = findTypeVariable(MyHomer.class, "L"); @@ -768,6 +768,7 @@ public class BridgeMethodResolverTests { } + @SuppressWarnings({ "unused", "unchecked" }) public abstract class GenericEventBroadcasterImpl extends GenericBroadcasterImpl implements EventBroadcaster { @@ -835,6 +836,7 @@ public class BridgeMethodResolverTests { } + @SuppressWarnings("unchecked") public class MessageBroadcasterImpl extends GenericEventBroadcasterImpl implements MessageBroadcaster { @@ -889,6 +891,7 @@ public class BridgeMethodResolverTests { } + @SuppressWarnings("unchecked") public class SettableRepositoryRegistry> implements RepositoryRegistry { diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/AbstractMessageConverterMethodArgumentResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/AbstractMessageConverterMethodArgumentResolver.java index 14c74c6077..9874fb38a1 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/AbstractMessageConverterMethodArgumentResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/AbstractMessageConverterMethodArgumentResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2013 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. @@ -18,20 +18,18 @@ package org.springframework.web.servlet.mvc.method.annotation; import java.io.IOException; import java.lang.reflect.Type; -import java.lang.reflect.TypeVariable; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashSet; import java.util.List; -import java.util.Map; import java.util.Set; import javax.servlet.http.HttpServletRequest; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.springframework.core.GenericTypeResolver; import org.springframework.core.MethodParameter; +import org.springframework.core.ResolvableType; import org.springframework.http.HttpInputMessage; import org.springframework.http.MediaType; import org.springframework.http.converter.GenericHttpMessageConverter; @@ -121,8 +119,8 @@ public abstract class AbstractMessageConverterMethodArgumentResolver implements } Class contextClass = methodParam.getDeclaringClass(); - Map map = GenericTypeResolver.getTypeVariableMap(contextClass); - Class targetClass = (Class) GenericTypeResolver.resolveType(targetType, map); + Class targetClass = (Class) ResolvableType.forType(targetType, + ResolvableType.forMethodParameter(methodParam)).resolve(); for (HttpMessageConverter converter : this.messageConverters) { if (converter instanceof GenericHttpMessageConverter) {