-
Notifications
You must be signed in to change notification settings - Fork 8.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix reflection exceptions caused by having identically named fallback…
…/blockHandler with different parameter types (#3395)
- Loading branch information
1 parent
bb813dd
commit 568e2df
Showing
9 changed files
with
180 additions
and
51 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -34,6 +34,7 @@ | |
* | ||
* @author Eric Zhao | ||
* @author zhaoyuguang | ||
* @author dowenliu-xyz([email protected]) | ||
*/ | ||
public abstract class AbstractSentinelAspectSupport { | ||
|
||
|
@@ -177,12 +178,13 @@ private Method extractFallbackMethod(ProceedingJoinPoint pjp, String fallbackNam | |
} | ||
boolean mustStatic = locationClass != null && locationClass.length >= 1; | ||
Class<?> clazz = mustStatic ? locationClass[0] : pjp.getTarget().getClass(); | ||
MethodWrapper m = ResourceMetadataRegistry.lookupFallback(clazz, fallbackName); | ||
Method originMethod = resolveMethod(pjp); | ||
MethodWrapper m = ResourceMetadataRegistry.lookupFallback(clazz, fallbackName, originMethod.getParameterTypes()); | ||
if (m == null) { | ||
// First time, resolve the fallback. | ||
Method method = resolveFallbackInternal(pjp, fallbackName, clazz, mustStatic); | ||
Method method = resolveFallbackInternal(originMethod, fallbackName, clazz, mustStatic); | ||
// Cache the method instance. | ||
ResourceMetadataRegistry.updateFallbackFor(clazz, fallbackName, method); | ||
ResourceMetadataRegistry.updateFallbackFor(clazz, fallbackName, originMethod.getParameterTypes(), method); | ||
return method; | ||
} | ||
if (!m.isPresent()) { | ||
|
@@ -232,9 +234,7 @@ private Method extractDefaultFallbackMethod(ProceedingJoinPoint pjp, String defa | |
return m.getMethod(); | ||
} | ||
|
||
private Method resolveFallbackInternal(ProceedingJoinPoint pjp, /*@NonNull*/ String name, Class<?> clazz, | ||
boolean mustStatic) { | ||
Method originMethod = resolveMethod(pjp); | ||
private Method resolveFallbackInternal(Method originMethod, String name, Class<?> clazz, boolean mustStatic) { | ||
// Fallback function allows two kinds of parameter list. | ||
Class<?>[] defaultParamTypes = originMethod.getParameterTypes(); | ||
Class<?>[] paramTypesWithException = Arrays.copyOf(defaultParamTypes, defaultParamTypes.length + 1); | ||
|
@@ -261,12 +261,13 @@ private Method extractBlockHandlerMethod(ProceedingJoinPoint pjp, String name, C | |
// By default current class. | ||
clazz = pjp.getTarget().getClass(); | ||
} | ||
MethodWrapper m = ResourceMetadataRegistry.lookupBlockHandler(clazz, name); | ||
Method originMethod = resolveMethod(pjp); | ||
MethodWrapper m = ResourceMetadataRegistry.lookupBlockHandler(clazz, name, originMethod.getParameterTypes()); | ||
if (m == null) { | ||
// First time, resolve the block handler. | ||
Method method = resolveBlockHandlerInternal(pjp, name, clazz, mustStatic); | ||
Method method = resolveBlockHandlerInternal(originMethod, name, clazz, mustStatic); | ||
// Cache the method instance. | ||
ResourceMetadataRegistry.updateBlockHandlerFor(clazz, name, method); | ||
ResourceMetadataRegistry.updateBlockHandlerFor(clazz, name, originMethod.getParameterTypes(), method); | ||
return method; | ||
} | ||
if (!m.isPresent()) { | ||
|
@@ -275,9 +276,7 @@ private Method extractBlockHandlerMethod(ProceedingJoinPoint pjp, String name, C | |
return m.getMethod(); | ||
} | ||
|
||
private Method resolveBlockHandlerInternal(ProceedingJoinPoint pjp, /*@NonNull*/ String name, Class<?> clazz, | ||
boolean mustStatic) { | ||
Method originMethod = resolveMethod(pjp); | ||
private Method resolveBlockHandlerInternal(Method originMethod, String name, Class<?> clazz, boolean mustStatic) { | ||
Class<?>[] originList = originMethod.getParameterTypes(); | ||
Class<?>[] parameterTypes = Arrays.copyOf(originList, originList.length + 1); | ||
parameterTypes[parameterTypes.length - 1] = BlockException.class; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,59 +16,111 @@ | |
package com.alibaba.csp.sentinel.annotation.aspectj; | ||
|
||
import java.lang.reflect.Method; | ||
import java.util.Arrays; | ||
import java.util.Map; | ||
import java.util.concurrent.ConcurrentHashMap; | ||
import java.util.stream.Collectors; | ||
|
||
import com.alibaba.csp.sentinel.util.StringUtil; | ||
|
||
/** | ||
* Registry for resource configuration metadata (e.g. fallback method) | ||
* | ||
* @author Eric Zhao | ||
* @author dowenliu-xyz([email protected]) | ||
*/ | ||
final class ResourceMetadataRegistry { | ||
|
||
private static final Map<String, MethodWrapper> FALLBACK_MAP = new ConcurrentHashMap<>(); | ||
private static final Map<String, MethodWrapper> DEFAULT_FALLBACK_MAP = new ConcurrentHashMap<>(); | ||
private static final Map<String, MethodWrapper> BLOCK_HANDLER_MAP = new ConcurrentHashMap<>(); | ||
|
||
/** | ||
* @deprecated use {@link #lookupFallback(Class, String, Class[])} | ||
*/ | ||
@Deprecated | ||
static MethodWrapper lookupFallback(Class<?> clazz, String name) { | ||
return FALLBACK_MAP.get(getKey(clazz, name)); | ||
} | ||
|
||
static MethodWrapper lookupFallback(Class<?> clazz, String name, Class<?>[] parameterTypes) { | ||
return FALLBACK_MAP.get(getKey(clazz, name, parameterTypes)); | ||
} | ||
|
||
static MethodWrapper lookupDefaultFallback(Class<?> clazz, String name) { | ||
return DEFAULT_FALLBACK_MAP.get(getKey(clazz, name)); | ||
} | ||
|
||
/** | ||
* @deprecated use {@link #lookupBlockHandler(Class, String, Class[])} | ||
*/ | ||
@Deprecated | ||
static MethodWrapper lookupBlockHandler(Class<?> clazz, String name) { | ||
return BLOCK_HANDLER_MAP.get(getKey(clazz, name)); | ||
} | ||
|
||
static MethodWrapper lookupBlockHandler(Class<?> clazz, String name, Class<?>[] parameterTypes) { | ||
return BLOCK_HANDLER_MAP.get(getKey(clazz, name, parameterTypes)); | ||
} | ||
|
||
/** | ||
* @deprecated use {@link #updateFallbackFor(Class, String, Class[], Method)} | ||
*/ | ||
@Deprecated | ||
static void updateFallbackFor(Class<?> clazz, String name, Method method) { | ||
if (clazz == null || StringUtil.isBlank(name)) { | ||
throw new IllegalArgumentException("Bad argument"); | ||
} | ||
FALLBACK_MAP.put(getKey(clazz, name), MethodWrapper.wrap(method)); | ||
} | ||
|
||
static void updateFallbackFor(Class<?> clazz, String handlerName, Class<?>[] parameterTypes, Method handlerMethod) { | ||
if (clazz == null || StringUtil.isBlank(handlerName)) { | ||
throw new IllegalArgumentException("Bad argument"); | ||
} | ||
FALLBACK_MAP.put(getKey(clazz, handlerName, parameterTypes), MethodWrapper.wrap(handlerMethod)); | ||
} | ||
|
||
static void updateDefaultFallbackFor(Class<?> clazz, String name, Method method) { | ||
if (clazz == null || StringUtil.isBlank(name)) { | ||
throw new IllegalArgumentException("Bad argument"); | ||
} | ||
DEFAULT_FALLBACK_MAP.put(getKey(clazz, name), MethodWrapper.wrap(method)); | ||
} | ||
|
||
|
||
/** | ||
* @deprecated use {@link #updateBlockHandlerFor(Class, String, Class[], Method)} | ||
*/ | ||
@Deprecated | ||
static void updateBlockHandlerFor(Class<?> clazz, String name, Method method) { | ||
if (clazz == null || StringUtil.isBlank(name)) { | ||
throw new IllegalArgumentException("Bad argument"); | ||
} | ||
BLOCK_HANDLER_MAP.put(getKey(clazz, name), MethodWrapper.wrap(method)); | ||
} | ||
|
||
static void updateBlockHandlerFor(Class<?> clazz, String handlerName, Class<?>[] parameterTypes, | ||
Method handlerMethod) { | ||
if (clazz == null || StringUtil.isBlank(handlerName)) { | ||
throw new IllegalArgumentException("Bad argument"); | ||
} | ||
BLOCK_HANDLER_MAP.put(getKey(clazz, handlerName, parameterTypes), MethodWrapper.wrap(handlerMethod)); | ||
} | ||
|
||
private static String getKey(Class<?> clazz, String name) { | ||
return String.format("%s:%s", clazz.getCanonicalName(), name); | ||
} | ||
|
||
private static String getKey(Class<?> clazz, String name, Class<?>[] parameterTypes) { | ||
return String.format( | ||
"%s:%s;%s", | ||
clazz.getCanonicalName(), | ||
name, | ||
Arrays.stream(parameterTypes).map(Class::getCanonicalName).collect(Collectors.joining(",")) | ||
); | ||
} | ||
|
||
/** | ||
* Only for internal test. | ||
*/ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,6 +26,7 @@ | |
|
||
/** | ||
* @author Eric Zhao | ||
* @author dowenliu-xyz([email protected]) | ||
*/ | ||
public class ResourceMetadataRegistryTest { | ||
|
||
|
@@ -45,14 +46,15 @@ public void tearDown() throws Exception { | |
public void testUpdateThenLookupFallback() { | ||
Class<?> clazz = FooService.class; | ||
String methodName = "someMethodFallback"; | ||
Class<?>[] parameterTypes = new Class<?>[]{String.class, int.class}; | ||
Method method = clazz.getMethods()[0]; | ||
assertThat(ResourceMetadataRegistry.lookupFallback(clazz, methodName)).isNull(); | ||
assertThat(ResourceMetadataRegistry.lookupFallback(clazz, methodName, parameterTypes)).isNull(); | ||
|
||
ResourceMetadataRegistry.updateFallbackFor(clazz, methodName, null); | ||
assertThat(ResourceMetadataRegistry.lookupFallback(clazz, methodName).isPresent()).isFalse(); | ||
ResourceMetadataRegistry.updateFallbackFor(clazz, methodName, parameterTypes, null); | ||
assertThat(ResourceMetadataRegistry.lookupFallback(clazz, methodName, parameterTypes).isPresent()).isFalse(); | ||
|
||
ResourceMetadataRegistry.updateFallbackFor(clazz, methodName, method); | ||
MethodWrapper wrapper = ResourceMetadataRegistry.lookupFallback(clazz, methodName); | ||
ResourceMetadataRegistry.updateFallbackFor(clazz, methodName, parameterTypes, method); | ||
MethodWrapper wrapper = ResourceMetadataRegistry.lookupFallback(clazz, methodName, parameterTypes); | ||
assertThat(wrapper.isPresent()).isTrue(); | ||
assertThat(wrapper.getMethod()).isSameAs(method); | ||
} | ||
|
@@ -61,25 +63,26 @@ public void testUpdateThenLookupFallback() { | |
public void testUpdateThenLookupBlockHandler() { | ||
Class<?> clazz = FooService.class; | ||
String methodName = "someMethodBlockHand;er"; | ||
Class<?>[] parameterTypes = new Class<?>[]{String.class, int.class}; | ||
Method method = clazz.getMethods()[1]; | ||
assertThat(ResourceMetadataRegistry.lookupBlockHandler(clazz, methodName)).isNull(); | ||
assertThat(ResourceMetadataRegistry.lookupBlockHandler(clazz, methodName, parameterTypes)).isNull(); | ||
|
||
ResourceMetadataRegistry.updateBlockHandlerFor(clazz, methodName, null); | ||
assertThat(ResourceMetadataRegistry.lookupBlockHandler(clazz, methodName).isPresent()).isFalse(); | ||
ResourceMetadataRegistry.updateBlockHandlerFor(clazz, methodName, parameterTypes, null); | ||
assertThat(ResourceMetadataRegistry.lookupBlockHandler(clazz, methodName, parameterTypes).isPresent()).isFalse(); | ||
|
||
ResourceMetadataRegistry.updateBlockHandlerFor(clazz, methodName, method); | ||
MethodWrapper wrapper = ResourceMetadataRegistry.lookupBlockHandler(clazz, methodName); | ||
ResourceMetadataRegistry.updateBlockHandlerFor(clazz, methodName, parameterTypes, method); | ||
MethodWrapper wrapper = ResourceMetadataRegistry.lookupBlockHandler(clazz, methodName, parameterTypes); | ||
assertThat(wrapper.isPresent()).isTrue(); | ||
assertThat(wrapper.getMethod()).isSameAs(method); | ||
} | ||
|
||
@Test(expected = IllegalArgumentException.class) | ||
public void testUpdateBlockHandlerBadArgument() { | ||
ResourceMetadataRegistry.updateBlockHandlerFor(null, "sxs", String.class.getMethods()[0]); | ||
ResourceMetadataRegistry.updateBlockHandlerFor(null, "sxs", new Class<?>[]{}, String.class.getMethods()[0]); | ||
} | ||
|
||
@Test(expected = IllegalArgumentException.class) | ||
public void testUpdateFallbackBadArgument() { | ||
ResourceMetadataRegistry.updateBlockHandlerFor(String.class, "", String.class.getMethods()[0]); | ||
ResourceMetadataRegistry.updateBlockHandlerFor(String.class, "", new Class[0], String.class.getMethods()[0]); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -34,6 +34,7 @@ | |
* | ||
* @author Eric Zhao | ||
* @author seasidesky | ||
* @author dowenliu-xyz([email protected]) | ||
*/ | ||
public abstract class AbstractSentinelInterceptorSupport { | ||
|
||
|
@@ -170,12 +171,13 @@ private Method extractFallbackMethod(InvocationContext ctx, String fallbackName, | |
} | ||
boolean mustStatic = locationClass != null && locationClass.length >= 1; | ||
Class<?> clazz = mustStatic ? locationClass[0] : ctx.getTarget().getClass(); | ||
MethodWrapper m = ResourceMetadataRegistry.lookupFallback(clazz, fallbackName); | ||
Method originMethod = resolveMethod(ctx); | ||
MethodWrapper m = ResourceMetadataRegistry.lookupFallback(clazz, fallbackName, originMethod.getParameterTypes()); | ||
if (m == null) { | ||
// First time, resolve the fallback. | ||
Method method = resolveFallbackInternal(ctx, fallbackName, clazz, mustStatic); | ||
Method method = resolveFallbackInternal(originMethod, fallbackName, clazz, mustStatic); | ||
// Cache the method instance. | ||
ResourceMetadataRegistry.updateFallbackFor(clazz, fallbackName, method); | ||
ResourceMetadataRegistry.updateFallbackFor(clazz, fallbackName, originMethod.getParameterTypes(), method); | ||
return method; | ||
} | ||
if (!m.isPresent()) { | ||
|
@@ -225,9 +227,7 @@ private Method extractDefaultFallbackMethod(InvocationContext ctx, String defaul | |
return m.getMethod(); | ||
} | ||
|
||
private Method resolveFallbackInternal(InvocationContext ctx, /*@NonNull*/ String name, Class<?> clazz, | ||
boolean mustStatic) { | ||
Method originMethod = resolveMethod(ctx); | ||
private Method resolveFallbackInternal(Method originMethod, String name, Class<?> clazz, boolean mustStatic) { | ||
// Fallback function allows two kinds of parameter list. | ||
Class<?>[] defaultParamTypes = originMethod.getParameterTypes(); | ||
Class<?>[] paramTypesWithException = Arrays.copyOf(defaultParamTypes, defaultParamTypes.length + 1); | ||
|
@@ -254,12 +254,13 @@ private Method extractBlockHandlerMethod(InvocationContext ctx, String name, Cla | |
// By default current class. | ||
clazz = ctx.getTarget().getClass(); | ||
} | ||
MethodWrapper m = ResourceMetadataRegistry.lookupBlockHandler(clazz, name); | ||
Method originMethod = resolveMethod(ctx); | ||
MethodWrapper m = ResourceMetadataRegistry.lookupBlockHandler(clazz, name, originMethod.getParameterTypes()); | ||
if (m == null) { | ||
// First time, resolve the block handler. | ||
Method method = resolveBlockHandlerInternal(ctx, name, clazz, mustStatic); | ||
Method method = resolveBlockHandlerInternal(originMethod, name, clazz, mustStatic); | ||
// Cache the method instance. | ||
ResourceMetadataRegistry.updateBlockHandlerFor(clazz, name, method); | ||
ResourceMetadataRegistry.updateBlockHandlerFor(clazz, name, originMethod.getParameterTypes(), method); | ||
return method; | ||
} | ||
if (!m.isPresent()) { | ||
|
@@ -268,9 +269,7 @@ private Method extractBlockHandlerMethod(InvocationContext ctx, String name, Cla | |
return m.getMethod(); | ||
} | ||
|
||
private Method resolveBlockHandlerInternal(InvocationContext ctx, /*@NonNull*/ String name, Class<?> clazz, | ||
boolean mustStatic) { | ||
Method originMethod = resolveMethod(ctx); | ||
private Method resolveBlockHandlerInternal(Method originMethod, String name, Class<?> clazz, boolean mustStatic) { | ||
Class<?>[] originList = originMethod.getParameterTypes(); | ||
Class<?>[] parameterTypes = Arrays.copyOf(originList, originList.length + 1); | ||
parameterTypes[parameterTypes.length - 1] = BlockException.class; | ||
|
Oops, something went wrong.