Refactor from deprecated GenericTypeResolver calls

Refactor AbstractMessageConverterMethodArgumentResolver and
BridgeMethodResolver to use ResolvableType in preference to deprecated
GenericTypeResolver calls.

Issue: SPR-10980
master
Phillip Webb 11 years ago
parent fdf0ef40c0
commit 501a1cbb5d
  1. 58
      spring-core/src/main/java/org/springframework/core/BridgeMethodResolver.java
  2. 19
      spring-core/src/test/java/org/springframework/core/BridgeMethodResolverTests.java
  3. 10
      spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/AbstractMessageConverterMethodArgumentResolver.java

@ -16,14 +16,11 @@
package org.springframework.core; package org.springframework.core;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map;
import org.springframework.util.ClassUtils; import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils; import org.springframework.util.ReflectionUtils;
@ -44,6 +41,7 @@ import org.springframework.util.ReflectionUtils;
* *
* @author Rob Harrop * @author Rob Harrop
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Phillip Webb
* @since 2.0 * @since 2.0
*/ */
public abstract class BridgeMethodResolver { 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. * Searches for the bridged method in the given candidates.
* @param candidateMethods the List of candidate Methods * @param candidateMethods the List of candidate Methods
@ -96,11 +106,10 @@ public abstract class BridgeMethodResolver {
if (candidateMethods.isEmpty()) { if (candidateMethods.isEmpty()) {
return null; return null;
} }
Map<TypeVariable, Type> typeParameterMap = GenericTypeResolver.getTypeVariableMap(bridgeMethod.getDeclaringClass());
Method previousMethod = null; Method previousMethod = null;
boolean sameSig = true; boolean sameSig = true;
for (Method candidateMethod : candidateMethods) { for (Method candidateMethod : candidateMethods) {
if (isBridgeMethodFor(bridgeMethod, candidateMethod, typeParameterMap)) { if (isBridgeMethodFor(bridgeMethod, candidateMethod, bridgeMethod.getDeclaringClass())) {
return candidateMethod; return candidateMethod;
} }
else if (previousMethod != null) { else if (previousMethod != null) {
@ -112,28 +121,16 @@ public abstract class BridgeMethodResolver {
return (sameSig ? candidateMethods.get(0) : null); 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 * Determines whether or not the bridge {@link Method} is the bridge for the
* supplied candidate {@link Method}. * supplied candidate {@link Method}.
*/ */
static boolean isBridgeMethodFor(Method bridgeMethod, Method candidateMethod, Map<TypeVariable, Type> typeVariableMap) { static boolean isBridgeMethodFor(Method bridgeMethod, Method candidateMethod, Class<?> declaringClass) {
if (isResolvedTypeMatch(candidateMethod, bridgeMethod, typeVariableMap)) { if (isResolvedTypeMatch(candidateMethod, bridgeMethod, declaringClass)) {
return true; return true;
} }
Method method = findGenericDeclaration(bridgeMethod); 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 * Returns {@code true} if the {@link Type} signature of both the supplied
* {@link Method#getGenericParameterTypes() generic Method} and concrete {@link Method} * {@link Method#getGenericParameterTypes() generic Method} and concrete {@link Method}
* are equal after resolving all {@link TypeVariable TypeVariables} using the supplied * are equal after resolving all types against the declaringType, otherwise
* TypeVariable Map, otherwise returns {@code false}. * returns {@code false}.
*/ */
private static boolean isResolvedTypeMatch( private static boolean isResolvedTypeMatch(
Method genericMethod, Method candidateMethod, Map<TypeVariable, Type> typeVariableMap) { Method genericMethod, Method candidateMethod, Class<?> declaringClass) {
Type[] genericParameters = genericMethod.getGenericParameterTypes(); Type[] genericParameters = genericMethod.getGenericParameterTypes();
Class[] candidateParameters = candidateMethod.getParameterTypes(); Class[] candidateParameters = candidateMethod.getParameterTypes();
if (genericParameters.length != candidateParameters.length) { if (genericParameters.length != candidateParameters.length) {
return false; return false;
} }
for (int i = 0; i < genericParameters.length; i++) { for (int i = 0; i < candidateParameters.length; i++) {
Type genericParameter = genericParameters[i]; ResolvableType genericParameter = ResolvableType.forMethodParameter(genericMethod, i, declaringClass);
Class candidateParameter = candidateParameters[i]; Class candidateParameter = candidateParameters[i];
if (candidateParameter.isArray()) { if (candidateParameter.isArray()) {
// An array type: compare the component type. // An array type: compare the component type.
Type rawType = GenericTypeResolver.getRawType(genericParameter, typeVariableMap); if (!candidateParameter.getComponentType().equals(genericParameter.getComponentType().resolve(Object.class))) {
if (rawType instanceof GenericArrayType) {
if (!candidateParameter.getComponentType().equals(
GenericTypeResolver.resolveType(((GenericArrayType) rawType).getGenericComponentType(), typeVariableMap))) {
return false; return false;
} }
break;
}
} }
// A non-array type: compare the type itself. // A non-array type: compare the type itself.
Class resolvedParameter = GenericTypeResolver.resolveType(genericParameter, typeVariableMap); if (!candidateParameter.equals(genericParameter.resolve(Object.class))) {
if (!candidateParameter.equals(resolvedParameter)) {
return false; return false;
} }
} }

@ -31,11 +31,11 @@ import java.util.Map;
import java.util.concurrent.DelayQueue; import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed; import java.util.concurrent.Delayed;
import static org.junit.Assert.*;
import org.junit.Test; import org.junit.Test;
import org.springframework.util.ReflectionUtils; import org.springframework.util.ReflectionUtils;
import static org.junit.Assert.*;
/** /**
* @author Rob Harrop * @author Rob Harrop
* @author Juergen Hoeller * @author Juergen Hoeller
@ -99,16 +99,16 @@ public class BridgeMethodResolverTests {
@Test @Test
public void testIsBridgeMethodFor() throws Exception { public void testIsBridgeMethodFor() throws Exception {
Map<TypeVariable, Type> typeParameterMap = GenericTypeResolver.getTypeVariableMap(MyBar.class);
Method bridged = MyBar.class.getDeclaredMethod("someMethod", String.class, Object.class); Method bridged = MyBar.class.getDeclaredMethod("someMethod", String.class, Object.class);
Method other = MyBar.class.getDeclaredMethod("someMethod", Integer.class, Object.class); Method other = MyBar.class.getDeclaredMethod("someMethod", Integer.class, Object.class);
Method bridge = MyBar.class.getDeclaredMethod("someMethod", Object.class, Object.class); Method bridge = MyBar.class.getDeclaredMethod("someMethod", Object.class, Object.class);
assertTrue("Should be bridge method", BridgeMethodResolver.isBridgeMethodFor(bridge, bridged, typeParameterMap)); assertTrue("Should be bridge method", BridgeMethodResolver.isBridgeMethodFor(bridge, bridged, MyBar.class));
assertFalse("Should not be bridge method", BridgeMethodResolver.isBridgeMethodFor(bridge, other, typeParameterMap)); assertFalse("Should not be bridge method", BridgeMethodResolver.isBridgeMethodFor(bridge, other, MyBar.class));
} }
@Test @Test
@Deprecated
public void testCreateTypeVariableMap() throws Exception { public void testCreateTypeVariableMap() throws Exception {
Map<TypeVariable, Type> typeVariableMap = GenericTypeResolver.getTypeVariableMap(MyBar.class); Map<TypeVariable, Type> typeVariableMap = GenericTypeResolver.getTypeVariableMap(MyBar.class);
TypeVariable<?> barT = findTypeVariable(InterBar.class, "T"); TypeVariable<?> barT = findTypeVariable(InterBar.class, "T");
@ -220,14 +220,14 @@ public class BridgeMethodResolverTests {
Method otherMethod = MessageBroadcasterImpl.class.getMethod("receive", NewMessageEvent.class); Method otherMethod = MessageBroadcasterImpl.class.getMethod("receive", NewMessageEvent.class);
assertFalse(otherMethod.isBridge()); assertFalse(otherMethod.isBridge());
Map<TypeVariable, Type> typeVariableMap = GenericTypeResolver.getTypeVariableMap(MessageBroadcasterImpl.class); assertFalse("Match identified incorrectly", BridgeMethodResolver.isBridgeMethodFor(bridgeMethod, otherMethod, MessageBroadcasterImpl.class));
assertFalse("Match identified incorrectly", BridgeMethodResolver.isBridgeMethodFor(bridgeMethod, otherMethod, typeVariableMap)); assertTrue("Match not found correctly", BridgeMethodResolver.isBridgeMethodFor(bridgeMethod, bridgedMethod, MessageBroadcasterImpl.class));
assertTrue("Match not found correctly", BridgeMethodResolver.isBridgeMethodFor(bridgeMethod, bridgedMethod, typeVariableMap));
assertEquals(bridgedMethod, BridgeMethodResolver.findBridgedMethod(bridgeMethod)); assertEquals(bridgedMethod, BridgeMethodResolver.findBridgedMethod(bridgeMethod));
} }
@Test @Test
@Deprecated
public void testSPR2454() throws Exception { public void testSPR2454() throws Exception {
Map<TypeVariable, Type> typeVariableMap = GenericTypeResolver.getTypeVariableMap(YourHomer.class); Map<TypeVariable, Type> typeVariableMap = GenericTypeResolver.getTypeVariableMap(YourHomer.class);
TypeVariable<?> variable = findTypeVariable(MyHomer.class, "L"); TypeVariable<?> variable = findTypeVariable(MyHomer.class, "L");
@ -768,6 +768,7 @@ public class BridgeMethodResolverTests {
} }
@SuppressWarnings({ "unused", "unchecked" })
public abstract class GenericEventBroadcasterImpl<T extends Event> extends GenericBroadcasterImpl public abstract class GenericEventBroadcasterImpl<T extends Event> extends GenericBroadcasterImpl
implements EventBroadcaster { implements EventBroadcaster {
@ -835,6 +836,7 @@ public class BridgeMethodResolverTests {
} }
@SuppressWarnings("unchecked")
public class MessageBroadcasterImpl extends GenericEventBroadcasterImpl<MessageEvent> public class MessageBroadcasterImpl extends GenericEventBroadcasterImpl<MessageEvent>
implements MessageBroadcaster { implements MessageBroadcaster {
@ -889,6 +891,7 @@ public class BridgeMethodResolverTests {
} }
@SuppressWarnings("unchecked")
public class SettableRepositoryRegistry<R extends SimpleGenericRepository<?>> public class SettableRepositoryRegistry<R extends SimpleGenericRepository<?>>
implements RepositoryRegistry { implements RepositoryRegistry {

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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.io.IOException;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.springframework.core.GenericTypeResolver;
import org.springframework.core.MethodParameter; import org.springframework.core.MethodParameter;
import org.springframework.core.ResolvableType;
import org.springframework.http.HttpInputMessage; import org.springframework.http.HttpInputMessage;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.converter.GenericHttpMessageConverter; import org.springframework.http.converter.GenericHttpMessageConverter;
@ -121,8 +119,8 @@ public abstract class AbstractMessageConverterMethodArgumentResolver implements
} }
Class<?> contextClass = methodParam.getDeclaringClass(); Class<?> contextClass = methodParam.getDeclaringClass();
Map<TypeVariable, Type> map = GenericTypeResolver.getTypeVariableMap(contextClass); Class<T> targetClass = (Class<T>) ResolvableType.forType(targetType,
Class<T> targetClass = (Class<T>) GenericTypeResolver.resolveType(targetType, map); ResolvableType.forMethodParameter(methodParam)).resolve();
for (HttpMessageConverter<?> converter : this.messageConverters) { for (HttpMessageConverter<?> converter : this.messageConverters) {
if (converter instanceof GenericHttpMessageConverter) { if (converter instanceof GenericHttpMessageConverter) {

Loading…
Cancel
Save