diff --git a/sentinel-demo/sentinel-demo-annotation-spring-aop/src/main/java/com/alibaba/csp/sentinel/demo/annotation/aop/controller/DemoController.java b/sentinel-demo/sentinel-demo-annotation-spring-aop/src/main/java/com/alibaba/csp/sentinel/demo/annotation/aop/controller/DemoController.java index f06d8fc401..5fd955a72f 100644 --- a/sentinel-demo/sentinel-demo-annotation-spring-aop/src/main/java/com/alibaba/csp/sentinel/demo/annotation/aop/controller/DemoController.java +++ b/sentinel-demo/sentinel-demo-annotation-spring-aop/src/main/java/com/alibaba/csp/sentinel/demo/annotation/aop/controller/DemoController.java @@ -47,6 +47,12 @@ public String apiBar(@RequestParam(required = false) String t) { return service.hello(t); } + @GetMapping("/count") + public int count() { + service.test(); + return service.count(); + } + @GetMapping("/baz/{name}") public String apiBaz(@PathVariable("name") String name) { return service.helloAnother(name); diff --git a/sentinel-demo/sentinel-demo-annotation-spring-aop/src/main/java/com/alibaba/csp/sentinel/demo/annotation/aop/service/TestService.java b/sentinel-demo/sentinel-demo-annotation-spring-aop/src/main/java/com/alibaba/csp/sentinel/demo/annotation/aop/service/TestService.java index 5b83876ed5..b346aa7461 100644 --- a/sentinel-demo/sentinel-demo-annotation-spring-aop/src/main/java/com/alibaba/csp/sentinel/demo/annotation/aop/service/TestService.java +++ b/sentinel-demo/sentinel-demo-annotation-spring-aop/src/main/java/com/alibaba/csp/sentinel/demo/annotation/aop/service/TestService.java @@ -26,5 +26,7 @@ public interface TestService { String hello(String s); + int count(); + String helloAnother(String name); } diff --git a/sentinel-demo/sentinel-demo-annotation-spring-aop/src/main/java/com/alibaba/csp/sentinel/demo/annotation/aop/service/TestServiceImpl.java b/sentinel-demo/sentinel-demo-annotation-spring-aop/src/main/java/com/alibaba/csp/sentinel/demo/annotation/aop/service/TestServiceImpl.java index d7c4172b23..c01415ea1c 100644 --- a/sentinel-demo/sentinel-demo-annotation-spring-aop/src/main/java/com/alibaba/csp/sentinel/demo/annotation/aop/service/TestServiceImpl.java +++ b/sentinel-demo/sentinel-demo-annotation-spring-aop/src/main/java/com/alibaba/csp/sentinel/demo/annotation/aop/service/TestServiceImpl.java @@ -48,6 +48,12 @@ public String hello(String s) { return String.format("Hello, %s", s); } + @SentinelResource(value = "count", fallback = "helloFallback", defaultFallback = "countDefaultFallback") + @Override + public int count() { + throw new UnsupportedOperationException("unimplemented"); + } + @Override @SentinelResource(value = "helloAnother", defaultFallback = "defaultFallback", exceptionsToIgnore = {IllegalStateException.class}) @@ -77,4 +83,8 @@ public String defaultFallback() { System.out.println("Go to default fallback"); return "default_fallback"; } + + public int countDefaultFallback() { + return -1; + } } diff --git a/sentinel-extension/sentinel-annotation-aspectj/src/main/java/com/alibaba/csp/sentinel/annotation/aspectj/AbstractSentinelAspectSupport.java b/sentinel-extension/sentinel-annotation-aspectj/src/main/java/com/alibaba/csp/sentinel/annotation/aspectj/AbstractSentinelAspectSupport.java index e121df71e2..a8e703d660 100644 --- a/sentinel-extension/sentinel-annotation-aspectj/src/main/java/com/alibaba/csp/sentinel/annotation/aspectj/AbstractSentinelAspectSupport.java +++ b/sentinel-extension/sentinel-annotation-aspectj/src/main/java/com/alibaba/csp/sentinel/annotation/aspectj/AbstractSentinelAspectSupport.java @@ -179,12 +179,12 @@ private Method extractFallbackMethod(ProceedingJoinPoint pjp, String fallbackNam boolean mustStatic = locationClass != null && locationClass.length >= 1; Class clazz = mustStatic ? locationClass[0] : pjp.getTarget().getClass(); Method originMethod = resolveMethod(pjp); - MethodWrapper m = ResourceMetadataRegistry.lookupFallback(clazz, fallbackName, originMethod.getParameterTypes()); + MethodWrapper m = ResourceMetadataRegistry.lookupFallback(originMethod, clazz, fallbackName); if (m == null) { // First time, resolve the fallback. Method method = resolveFallbackInternal(originMethod, fallbackName, clazz, mustStatic); // Cache the method instance. - ResourceMetadataRegistry.updateFallbackFor(clazz, fallbackName, originMethod.getParameterTypes(), method); + ResourceMetadataRegistry.updateFallbackFor(originMethod, clazz, fallbackName, method); return method; } if (!m.isPresent()) { @@ -209,10 +209,11 @@ private Method extractDefaultFallbackMethod(ProceedingJoinPoint pjp, String defa boolean mustStatic = locationClass != null && locationClass.length >= 1; Class clazz = mustStatic ? locationClass[0] : pjp.getTarget().getClass(); - MethodWrapper m = ResourceMetadataRegistry.lookupDefaultFallback(clazz, defaultFallback); + Method originMethod = resolveMethod(pjp); + MethodWrapper m = ResourceMetadataRegistry.lookupDefaultFallback(originMethod, clazz, defaultFallback); if (m == null) { // First time, resolve the default fallback. - Class originReturnType = resolveMethod(pjp).getReturnType(); + Class originReturnType = originMethod.getReturnType(); // Default fallback allows two kinds of parameter list. // One is empty parameter list. Class[] defaultParamTypes = new Class[0]; @@ -225,7 +226,7 @@ private Method extractDefaultFallbackMethod(ProceedingJoinPoint pjp, String defa method = findMethod(mustStatic, clazz, defaultFallback, originReturnType, paramTypeWithException); } // Cache the method instance. - ResourceMetadataRegistry.updateDefaultFallbackFor(clazz, defaultFallback, method); + ResourceMetadataRegistry.updateDefaultFallbackFor(originMethod, clazz, defaultFallback, method); return method; } if (!m.isPresent()) { @@ -262,12 +263,12 @@ private Method extractBlockHandlerMethod(ProceedingJoinPoint pjp, String name, C clazz = pjp.getTarget().getClass(); } Method originMethod = resolveMethod(pjp); - MethodWrapper m = ResourceMetadataRegistry.lookupBlockHandler(clazz, name, originMethod.getParameterTypes()); + MethodWrapper m = ResourceMetadataRegistry.lookupBlockHandler(originMethod, clazz, name); if (m == null) { // First time, resolve the block handler. Method method = resolveBlockHandlerInternal(originMethod, name, clazz, mustStatic); // Cache the method instance. - ResourceMetadataRegistry.updateBlockHandlerFor(clazz, name, originMethod.getParameterTypes(), method); + ResourceMetadataRegistry.updateBlockHandlerFor(originMethod, clazz, name, method); return method; } if (!m.isPresent()) { diff --git a/sentinel-extension/sentinel-annotation-aspectj/src/main/java/com/alibaba/csp/sentinel/annotation/aspectj/HandlerMeta.java b/sentinel-extension/sentinel-annotation-aspectj/src/main/java/com/alibaba/csp/sentinel/annotation/aspectj/HandlerMeta.java new file mode 100644 index 0000000000..9d89a3e2f0 --- /dev/null +++ b/sentinel-extension/sentinel-annotation-aspectj/src/main/java/com/alibaba/csp/sentinel/annotation/aspectj/HandlerMeta.java @@ -0,0 +1,77 @@ +/* + * Copyright 1999-2024 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.csp.sentinel.annotation.aspectj; + +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Objects; + +/** + * `blockHandler`, `fallback` and `defaultFallback` handler metadata, describing the features of a handler method. + * It helps locate the handler method in the registry. + * + * @author dowenliu-xyz(hawkdowen@hotmail.com) + */ +final class HandlerMeta { + private final Class handlerClass; + private final Class returnType; + private final String handlerName; + private final Class[] parameterTypes; + + /** + * Create a handler metadata. + * + * @param originMethod the origin method which is annotated by `@SentinelResource` + * @param handlerClass the class of the handler method + * @param handlerName the name of the handler method + * @return the handler metadata + * @throws IllegalArgumentException if `originMethod` is null + */ + static HandlerMeta handlerMetaOf(Method originMethod, Class handlerClass, String handlerName) { + if (originMethod == null) { + throw new IllegalArgumentException("originMethod should not be null"); + } + return new HandlerMeta( + handlerClass, originMethod.getReturnType(), handlerName, originMethod.getParameterTypes()); + } + + private HandlerMeta(Class handlerClass, Class returnType, String handlerName, Class[] parameterTypes) { + this.handlerClass = handlerClass; + this.returnType = returnType; + this.handlerName = handlerName; + this.parameterTypes = parameterTypes; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + HandlerMeta that = (HandlerMeta) o; + return Objects.equals(handlerClass, that.handlerClass) && + Objects.equals(returnType, that.returnType) && + Objects.equals(handlerName, that.handlerName) && + Objects.deepEquals(parameterTypes, that.parameterTypes); + } + + @Override + public int hashCode() { + return Objects.hash(handlerClass, returnType, handlerName, Arrays.hashCode(parameterTypes)); + } +} diff --git a/sentinel-extension/sentinel-annotation-aspectj/src/main/java/com/alibaba/csp/sentinel/annotation/aspectj/ResourceMetadataRegistry.java b/sentinel-extension/sentinel-annotation-aspectj/src/main/java/com/alibaba/csp/sentinel/annotation/aspectj/ResourceMetadataRegistry.java index e810fafcf0..6468e84304 100644 --- a/sentinel-extension/sentinel-annotation-aspectj/src/main/java/com/alibaba/csp/sentinel/annotation/aspectj/ResourceMetadataRegistry.java +++ b/sentinel-extension/sentinel-annotation-aspectj/src/main/java/com/alibaba/csp/sentinel/annotation/aspectj/ResourceMetadataRegistry.java @@ -30,41 +30,97 @@ * @author dowenliu-xyz(hawkdowen@hotmail.com) */ final class ResourceMetadataRegistry { - private static final Map FALLBACK_MAP = new ConcurrentHashMap<>(); + private static final Map FALLBACK_METAMAP = new ConcurrentHashMap<>(); private static final Map DEFAULT_FALLBACK_MAP = new ConcurrentHashMap<>(); + private static final Map DEFAULT_FALLBACK_METAMAP = new ConcurrentHashMap<>(); private static final Map BLOCK_HANDLER_MAP = new ConcurrentHashMap<>(); + private static final Map BLOCK_HANDLER_METAMAP = new ConcurrentHashMap<>(); /** - * @deprecated use {@link #lookupFallback(Class, String, Class[])} + * @deprecated use {@link #lookupFallback(Method, Class, String)} */ @Deprecated static MethodWrapper lookupFallback(Class clazz, String name) { return FALLBACK_MAP.get(getKey(clazz, name)); } + /** + * @deprecated use {@link #lookupFallback(Method, Class, String)} + */ + @Deprecated static MethodWrapper lookupFallback(Class clazz, String name, Class[] parameterTypes) { return FALLBACK_MAP.get(getKey(clazz, name, parameterTypes)); } + /** + * Lookup the fallback handler method of the origin method, with specified name in the specified class. + * + * @param originMethod the origin method which is annotated by `@SentinelResource` with the fallback handler + * name value. + * @param handlerClass the class of the defaultFallback handler method. + * @param handlerName the name of expected fallback handler method. + * @return the found method wrapper. If currently the method is not registered, return {@code null}. Even if the + * returned wrapper is not {@code null}, the method it contains may still be {@code null}, which means that the + * expected handler method does not exist. + */ + static MethodWrapper lookupFallback(Method originMethod, Class handlerClass, String handlerName) { + return FALLBACK_METAMAP.get(HandlerMeta.handlerMetaOf(originMethod, handlerClass, handlerName)); + } + + /** + * @deprecated use {@link #lookupDefaultFallback(Method, Class, String)} + */ static MethodWrapper lookupDefaultFallback(Class clazz, String name) { return DEFAULT_FALLBACK_MAP.get(getKey(clazz, name)); } /** - * @deprecated use {@link #lookupBlockHandler(Class, String, Class[])} + * Lookup the defaultFallback handler method of the origin method, with specified name in the specified class. + * + * @param originMethod the origin method which is annotated by `@SentinelResource` with the defaultFallback + * handler name value. + * @param handlerClass the class of the defaultFallback handler method. + * @param handlerName the name of expected defaultFallback handler method. + * @return the found method wrapper. If currently the method is not registered, return {@code null}. Even if the + * returned wrapper is not {@code null}, the method it contains may still be {@code null}, which means that the + * expected handler method does not exist. + */ + static MethodWrapper lookupDefaultFallback(Method originMethod, Class handlerClass, String handlerName) { + return DEFAULT_FALLBACK_METAMAP.get(HandlerMeta.handlerMetaOf(originMethod, handlerClass, handlerName)); + } + + /** + * @deprecated use {@link #lookupBlockHandler(Method, Class, String)} */ @Deprecated static MethodWrapper lookupBlockHandler(Class clazz, String name) { return BLOCK_HANDLER_MAP.get(getKey(clazz, name)); } + /** + * @deprecated use {@link #lookupBlockHandler(Method, Class, String)} + */ 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)} + * Lookup the blockHandler handler method of the origin method, with specified name in the specified class. + * @param originMethod the origin method which is annotated by `@SentinelResource` with the blockHandler handler + * name value. + * @param handlerClass the class of the blockHandler handler method. + * @param handlerName the name of expected blockHandler handler method. + * @return the found method wrapper. If currently the method is not registered, return {@code null}. Even if the + * returned wrapper is not {@code null}, the method it contains may still be {@code null}, which means that the + * expected handler method does not exist. + */ + static MethodWrapper lookupBlockHandler(Method originMethod, Class handlerClass, String handlerName) { + return BLOCK_HANDLER_METAMAP.get(HandlerMeta.handlerMetaOf(originMethod, handlerClass, handlerName)); + } + + /** + * @deprecated use {@link #updateFallbackFor(Method, Class, String, Method)} */ @Deprecated static void updateFallbackFor(Class clazz, String name, Method method) { @@ -74,6 +130,9 @@ static void updateFallbackFor(Class clazz, String name, Method method) { FALLBACK_MAP.put(getKey(clazz, name), MethodWrapper.wrap(method)); } + /** + * @deprecated use {@link #updateFallbackFor(Method, Class, String, Method)} + */ static void updateFallbackFor(Class clazz, String handlerName, Class[] parameterTypes, Method handlerMethod) { if (clazz == null || StringUtil.isBlank(handlerName)) { throw new IllegalArgumentException("Bad argument"); @@ -81,6 +140,15 @@ static void updateFallbackFor(Class clazz, String handlerName, Class[] par FALLBACK_MAP.put(getKey(clazz, handlerName, parameterTypes), MethodWrapper.wrap(handlerMethod)); } + static void updateFallbackFor(Method originMethod, Class handlerClass, String handlerName, + Method handlerMethod) { + FALLBACK_METAMAP.put(HandlerMeta.handlerMetaOf(originMethod, handlerClass, handlerName), + MethodWrapper.wrap(handlerMethod)); + } + + /** + * @deprecated use {@link #updateDefaultFallbackFor(Method, Class, String, Method)} + */ static void updateDefaultFallbackFor(Class clazz, String name, Method method) { if (clazz == null || StringUtil.isBlank(name)) { throw new IllegalArgumentException("Bad argument"); @@ -88,9 +156,15 @@ static void updateDefaultFallbackFor(Class clazz, String name, Method method) DEFAULT_FALLBACK_MAP.put(getKey(clazz, name), MethodWrapper.wrap(method)); } + static void updateDefaultFallbackFor(Method originMethod, Class handlerClass, String handlerName, + Method handlerMethod) { + DEFAULT_FALLBACK_METAMAP.put(HandlerMeta.handlerMetaOf(originMethod, handlerClass, handlerName), + MethodWrapper.wrap(handlerMethod)); + } + /** - * @deprecated use {@link #updateBlockHandlerFor(Class, String, Class[], Method)} + * @deprecated use {@link #updateBlockHandlerFor(Method, Class, String, Method)} */ @Deprecated static void updateBlockHandlerFor(Class clazz, String name, Method method) { @@ -100,6 +174,9 @@ static void updateBlockHandlerFor(Class clazz, String name, Method method) { BLOCK_HANDLER_MAP.put(getKey(clazz, name), MethodWrapper.wrap(method)); } + /** + * @deprecated use {@link #updateBlockHandlerFor(Method, Class, String, Method)} + */ static void updateBlockHandlerFor(Class clazz, String handlerName, Class[] parameterTypes, Method handlerMethod) { if (clazz == null || StringUtil.isBlank(handlerName)) { @@ -108,6 +185,12 @@ static void updateBlockHandlerFor(Class clazz, String handlerName, Class[] BLOCK_HANDLER_MAP.put(getKey(clazz, handlerName, parameterTypes), MethodWrapper.wrap(handlerMethod)); } + static void updateBlockHandlerFor(Method originMethod, Class handlerClass, String handlerName, + Method handlerMethod) { + BLOCK_HANDLER_METAMAP.put(HandlerMeta.handlerMetaOf(originMethod, handlerClass, handlerName), + MethodWrapper.wrap(handlerMethod)); + } + private static String getKey(Class clazz, String name) { return String.format("%s:%s", clazz.getCanonicalName(), name); } @@ -126,6 +209,7 @@ private static String getKey(Class clazz, String name, Class[] parameterTy */ static void clearFallbackMap() { FALLBACK_MAP.clear(); + FALLBACK_METAMAP.clear(); } /** @@ -133,5 +217,13 @@ static void clearFallbackMap() { */ static void clearBlockHandlerMap() { BLOCK_HANDLER_MAP.clear(); + BLOCK_HANDLER_METAMAP.clear(); + } + + /** + * Only for internal test. + */ + static void clearDefaultFallbackMap() { + DEFAULT_FALLBACK_METAMAP.clear(); } } diff --git a/sentinel-extension/sentinel-annotation-aspectj/src/test/java/com/alibaba/csp/sentinel/annotation/aspectj/ResourceMetadataRegistryTest.java b/sentinel-extension/sentinel-annotation-aspectj/src/test/java/com/alibaba/csp/sentinel/annotation/aspectj/ResourceMetadataRegistryTest.java index 117fc621d0..5fec19e659 100644 --- a/sentinel-extension/sentinel-annotation-aspectj/src/test/java/com/alibaba/csp/sentinel/annotation/aspectj/ResourceMetadataRegistryTest.java +++ b/sentinel-extension/sentinel-annotation-aspectj/src/test/java/com/alibaba/csp/sentinel/annotation/aspectj/ResourceMetadataRegistryTest.java @@ -16,6 +16,8 @@ package com.alibaba.csp.sentinel.annotation.aspectj; import com.alibaba.csp.sentinel.annotation.aspectj.integration.service.FooService; +import com.alibaba.csp.sentinel.annotation.aspectj.integration.service.FooUtil; +import com.alibaba.csp.sentinel.slots.block.BlockException; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -31,58 +33,83 @@ public class ResourceMetadataRegistryTest { @Before - public void setUp() throws Exception { + public void setUp() { ResourceMetadataRegistry.clearBlockHandlerMap(); ResourceMetadataRegistry.clearFallbackMap(); + ResourceMetadataRegistry.clearDefaultFallbackMap(); } @After - public void tearDown() throws Exception { + public void tearDown() { ResourceMetadataRegistry.clearBlockHandlerMap(); ResourceMetadataRegistry.clearFallbackMap(); + ResourceMetadataRegistry.clearDefaultFallbackMap(); } @Test - public void testUpdateThenLookupFallback() { + public void testUpdateThenLookupFallback() throws NoSuchMethodException { 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, parameterTypes)).isNull(); + Method originMethod = clazz.getDeclaredMethod("fooWithFallback", int.class); + String methodName = "fooFallbackFunc"; + Method handlerMethod = clazz.getDeclaredMethod(methodName, int.class); + assertThat(ResourceMetadataRegistry.lookupFallback(originMethod, clazz, methodName)).isNull(); - ResourceMetadataRegistry.updateFallbackFor(clazz, methodName, parameterTypes, null); - assertThat(ResourceMetadataRegistry.lookupFallback(clazz, methodName, parameterTypes).isPresent()).isFalse(); + ResourceMetadataRegistry.updateFallbackFor(originMethod, clazz, methodName, null); + assertThat(ResourceMetadataRegistry.lookupFallback(originMethod, clazz, methodName).isPresent()).isFalse(); - ResourceMetadataRegistry.updateFallbackFor(clazz, methodName, parameterTypes, method); - MethodWrapper wrapper = ResourceMetadataRegistry.lookupFallback(clazz, methodName, parameterTypes); + ResourceMetadataRegistry.updateFallbackFor(originMethod, clazz, methodName, handlerMethod); + MethodWrapper wrapper = ResourceMetadataRegistry.lookupFallback(originMethod, clazz, methodName); assertThat(wrapper.isPresent()).isTrue(); - assertThat(wrapper.getMethod()).isSameAs(method); + assertThat(wrapper.getMethod()).isSameAs(handlerMethod); } @Test - public void testUpdateThenLookupBlockHandler() { + public void testUpdateThenLookupBlockHandler() throws NoSuchMethodException { 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, parameterTypes)).isNull(); + Method originMethod = clazz.getDeclaredMethod("foo", int.class); + String methodName = "fooBlockHandler"; + Method handlerMethod = clazz.getDeclaredMethod(methodName, int.class, BlockException.class); + assertThat(ResourceMetadataRegistry.lookupBlockHandler(originMethod, clazz, methodName)).isNull(); - ResourceMetadataRegistry.updateBlockHandlerFor(clazz, methodName, parameterTypes, null); - assertThat(ResourceMetadataRegistry.lookupBlockHandler(clazz, methodName, parameterTypes).isPresent()).isFalse(); + ResourceMetadataRegistry.updateBlockHandlerFor(originMethod, clazz, methodName, null); + assertThat(ResourceMetadataRegistry.lookupBlockHandler(originMethod, clazz, methodName).isPresent()).isFalse(); - ResourceMetadataRegistry.updateBlockHandlerFor(clazz, methodName, parameterTypes, method); - MethodWrapper wrapper = ResourceMetadataRegistry.lookupBlockHandler(clazz, methodName, parameterTypes); + ResourceMetadataRegistry.updateBlockHandlerFor(originMethod, clazz, methodName, handlerMethod); + MethodWrapper wrapper = ResourceMetadataRegistry.lookupBlockHandler(originMethod, clazz, methodName); assertThat(wrapper.isPresent()).isTrue(); - assertThat(wrapper.getMethod()).isSameAs(method); + assertThat(wrapper.getMethod()).isSameAs(handlerMethod); + } + + @Test + public void testUpdateThenLookupDefaultFallback() throws NoSuchMethodException { + Class clazz = FooService.class; + Method originMethod = clazz.getDeclaredMethod("anotherFoo", int.class); + String methodName = "globalDefaultFallback"; + Class handlerClass = FooUtil.class; + Method handlerMethod = handlerClass.getDeclaredMethod(methodName, Throwable.class); + assertThat(ResourceMetadataRegistry.lookupDefaultFallback(originMethod, clazz, methodName)).isNull(); + + ResourceMetadataRegistry.updateDefaultFallbackFor(originMethod, clazz, methodName, null); + assertThat(ResourceMetadataRegistry.lookupDefaultFallback(originMethod, clazz, methodName).isPresent()).isFalse(); + + ResourceMetadataRegistry.updateDefaultFallbackFor(originMethod, clazz, methodName, handlerMethod); + MethodWrapper wrapper = ResourceMetadataRegistry.lookupDefaultFallback(originMethod, clazz, methodName); + assertThat(wrapper.isPresent()).isTrue(); + assertThat(wrapper.getMethod()).isSameAs(handlerMethod); } @Test(expected = IllegalArgumentException.class) public void testUpdateBlockHandlerBadArgument() { - ResourceMetadataRegistry.updateBlockHandlerFor(null, "sxs", new Class[]{}, String.class.getMethods()[0]); + ResourceMetadataRegistry.updateBlockHandlerFor(null, null, "sxs", String.class.getMethods()[0]); } @Test(expected = IllegalArgumentException.class) public void testUpdateFallbackBadArgument() { - ResourceMetadataRegistry.updateBlockHandlerFor(String.class, "", new Class[0], String.class.getMethods()[0]); + ResourceMetadataRegistry.updateFallbackFor(null, String.class, "", String.class.getMethods()[0]); + } + + @Test(expected = IllegalArgumentException.class) + public void testUpdateDefaultFallbackBadArgument() { + ResourceMetadataRegistry.updateDefaultFallbackFor(null, String.class, "", String.class.getMethods()[0]); } }