Refactor from deprecated GenericTypeResolver calls
Refactor AbstractMessageConverterMethodArgumentResolver and BridgeMethodResolver to use ResolvableType in preference to deprecated GenericTypeResolver calls. Issue: SPR-10980
This commit is contained in:
parent
fdf0ef40c0
commit
501a1cbb5d
|
|
@ -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,32 +84,6 @@ public abstract class BridgeMethodResolver {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Searches for the bridged method in the given candidates.
|
|
||||||
* @param candidateMethods the List of candidate Methods
|
|
||||||
* @param bridgeMethod the bridge method
|
|
||||||
* @return the bridged method, or {@code null} if none found
|
|
||||||
*/
|
|
||||||
private static Method searchCandidates(List<Method> candidateMethods, Method bridgeMethod) {
|
|
||||||
if (candidateMethods.isEmpty()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
Map<TypeVariable, Type> typeParameterMap = GenericTypeResolver.getTypeVariableMap(bridgeMethod.getDeclaringClass());
|
|
||||||
Method previousMethod = null;
|
|
||||||
boolean sameSig = true;
|
|
||||||
for (Method candidateMethod : candidateMethods) {
|
|
||||||
if (isBridgeMethodFor(bridgeMethod, candidateMethod, typeParameterMap)) {
|
|
||||||
return candidateMethod;
|
|
||||||
}
|
|
||||||
else if (previousMethod != null) {
|
|
||||||
sameSig = sameSig &&
|
|
||||||
Arrays.equals(candidateMethod.getGenericParameterTypes(), previousMethod.getGenericParameterTypes());
|
|
||||||
}
|
|
||||||
previousMethod = candidateMethod;
|
|
||||||
}
|
|
||||||
return (sameSig ? candidateMethods.get(0) : null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns {@code true} if the supplied '{@code candidateMethod}' can be
|
* Returns {@code true} if the supplied '{@code candidateMethod}' can be
|
||||||
* consider a validate candidate for the {@link Method} that is {@link Method#isBridge() bridged}
|
* consider a validate candidate for the {@link Method} that is {@link Method#isBridge() bridged}
|
||||||
|
|
@ -124,16 +96,41 @@ public abstract class BridgeMethodResolver {
|
||||||
candidateMethod.getParameterTypes().length == bridgeMethod.getParameterTypes().length);
|
candidateMethod.getParameterTypes().length == bridgeMethod.getParameterTypes().length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Searches for the bridged method in the given candidates.
|
||||||
|
* @param candidateMethods the List of candidate Methods
|
||||||
|
* @param bridgeMethod the bridge method
|
||||||
|
* @return the bridged method, or {@code null} if none found
|
||||||
|
*/
|
||||||
|
private static Method searchCandidates(List<Method> candidateMethods, Method bridgeMethod) {
|
||||||
|
if (candidateMethods.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Method previousMethod = null;
|
||||||
|
boolean sameSig = true;
|
||||||
|
for (Method candidateMethod : candidateMethods) {
|
||||||
|
if (isBridgeMethodFor(bridgeMethod, candidateMethod, bridgeMethod.getDeclaringClass())) {
|
||||||
|
return candidateMethod;
|
||||||
|
}
|
||||||
|
else if (previousMethod != null) {
|
||||||
|
sameSig = sameSig &&
|
||||||
|
Arrays.equals(candidateMethod.getGenericParameterTypes(), previousMethod.getGenericParameterTypes());
|
||||||
|
}
|
||||||
|
previousMethod = candidateMethod;
|
||||||
|
}
|
||||||
|
return (sameSig ? candidateMethods.get(0) : null);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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) {
|
return false;
|
||||||
if (!candidateParameter.getComponentType().equals(
|
|
||||||
GenericTypeResolver.resolveType(((GenericArrayType) rawType).getGenericComponentType(), typeVariableMap))) {
|
|
||||||
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…
Reference in New Issue