cn.tom.kit.clazz.BridgeMethodResolver Maven / Gradle / Ivy
package cn.tom.kit.clazz;
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;
/**
* 泛型方法的工具类,可以用来处理bridged method。
*
*
* @author Service Platform Architecture Team ([email protected])
*/
public abstract class BridgeMethodResolver {
/**
* 通过参数Method找到我们调用的原始Method
* java 通过bridge方式来实现泛型。
*
*
* @param bridgeMethod
* @return the original method
*/
public static Method findBridgedMethod(Method bridgeMethod) {
if (bridgeMethod == null || !bridgeMethod.isBridge()) {
return bridgeMethod;
}
// Gather all methods with matching name and parameter size.
List candidateMethods = new ArrayList();
Method[] methods = ReflectUtil.getAllDeclaredMethods(bridgeMethod.getDeclaringClass());
for (Method candidateMethod : methods) {
if (isBridgedCandidateFor(candidateMethod, bridgeMethod)) {
candidateMethods.add(candidateMethod);
}
}
// Now perform simple quick check.
if (candidateMethods.size() == 1) {
return candidateMethods.get(0);
}
// Search for candidate match.
Method bridgedMethod = searchCandidates(candidateMethods, bridgeMethod);
if (bridgedMethod != null) {
// Bridged method found...
return bridgedMethod;
}
else {
// A bridge method was passed in but we couldn't find the bridged method.
// Let's proceed with the passed-in method and hope for the best...
return bridgeMethod;
}
}
private static Method searchCandidates(List candidateMethods, Method bridgeMethod) {
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)) {
return candidateMethod;
}
else if (previousMethod != null) {
sameSig = sameSig &&
Arrays.equals(candidateMethod.getGenericParameterTypes(), previousMethod.getGenericParameterTypes());
}
previousMethod = candidateMethod;
}
return (sameSig ? candidateMethods.get(0) : null);
}
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);
}
static boolean isBridgeMethodFor(Method bridgeMethod, Method candidateMethod, Map typeVariableMap) {
if (isResolvedTypeMatch(candidateMethod, bridgeMethod, typeVariableMap)) {
return true;
}
Method method = findGenericDeclaration(bridgeMethod);
return (method != null && isResolvedTypeMatch(method, candidateMethod, typeVariableMap));
}
private static Method findGenericDeclaration(Method bridgeMethod) {
// Search parent types for method that has same signature as bridge.
Class superclass = bridgeMethod.getDeclaringClass().getSuperclass();
while (!Object.class.equals(superclass)) {
Method method = searchForMatch(superclass, bridgeMethod);
if (method != null && !method.isBridge()) {
return method;
}
superclass = superclass.getSuperclass();
}
// Search interfaces.
Class[] interfaces = ReflectUtil.getAllInterfacesForClass(bridgeMethod.getDeclaringClass());
for (Class ifc : interfaces) {
Method method = searchForMatch(ifc, bridgeMethod);
if (method != null && !method.isBridge()) {
return method;
}
}
return null;
}
private static boolean isResolvedTypeMatch(
Method genericMethod, Method candidateMethod, Map typeVariableMap) {
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];
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;
}
}
// A non-array type: compare the type itself.
Class resolvedParameter = GenericTypeResolver.resolveType(genericParameter, typeVariableMap);
if (!candidateParameter.equals(resolvedParameter)) {
return false;
}
}
return true;
}
private static Method searchForMatch(Class type, Method bridgeMethod) {
return ReflectUtil.findMethod(type, bridgeMethod.getName(), bridgeMethod.getParameterTypes());
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy