/** * Create a {@link MethodInvoker} for the delegate from a single public * method. * * @param target an object to search for an appropriate method. * @param <C> the class. * @param <T> the type. * @return a {@link MethodInvoker} that calls a method on the delegate. */ public static <C, T> MethodInvoker getMethodInvokerForSingleArgument(Object target) { final AtomicReference<Method> methodHolder = new AtomicReference<>(); ReflectionUtils.doWithMethods(target.getClass(), method -> { if (method.getParameterTypes() == null || method.getParameterTypes().length != 1) { return; } if (method.getReturnType().equals(Void.TYPE) || ReflectionUtils.isEqualsMethod(method)) { return; } Assert.state(methodHolder.get() == null, "More than one non-void public method detected with single argument."); methodHolder.set(method); }); Method method = methodHolder.get(); return new SimpleMethodInvoker(target, method); } }
@Override public Object invokeMethod(Object... args) { Class<?>[] parameterTypes = method.getParameterTypes(); Object[] invokeArgs; if (parameterTypes.length == 0) { invokeArgs = new Object[] {}; } else if (parameterTypes.length != args.length) { throw new IllegalArgumentException("Wrong number of arguments, expected no more than: [" + parameterTypes.length + "]"); } else { invokeArgs = args; } method.setAccessible(true); try { // Extract the target from an Advised as late as possible // in case it contains a lazy initialization Object target = extractTarget(object, method); return method.invoke(target, invokeArgs); } catch (Exception e) { throw new IllegalArgumentException("Unable to invoke method: [" + method + "] on object: [" + object + "] with arguments: [" + Arrays.toString(args) + "]", e); } }
/** * Create a {@link MethodInvoker} using the provided method name to search. * * @param object to be invoked * @param methodName of the method to be invoked * @param paramsRequired boolean indicating whether the parameters are * required, if false, a no args version of the method will be searched for. * @param paramTypes - parameter types of the method to search for. * @return MethodInvoker if the method is found, null if it is not. */ public static MethodInvoker getMethodInvokerByName(Object object, String methodName, boolean paramsRequired, Class<?>... paramTypes) { Assert.notNull(object, "Object to invoke must not be null"); Method method = ClassUtils.getMethodIfAvailable(object.getClass(), methodName, paramTypes); if (method == null) { String errorMsg = "no method found with name [" + methodName + "] on class [" + object.getClass().getSimpleName() + "] compatible with the signature [" + getParamTypesString(paramTypes) + "]."; Assert.isTrue(!paramsRequired, errorMsg); // if no method was found for the given parameters, and the // parameters aren't required, then try with no params method = ClassUtils.getMethodIfAvailable(object.getClass(), methodName); Assert.notNull(method, errorMsg); } return new SimpleMethodInvoker(object, method); }
private Object extractTarget(Object target, Method method) { if (target instanceof Advised) { Object source; try { source = ((Advised) target).getTargetSource().getTarget(); } catch (Exception e) { throw new IllegalStateException("Could not extract target from proxy", e); } if (source instanceof Advised) { source = extractTarget(source, method); } if (method.getDeclaringClass().isAssignableFrom(source.getClass())) { target = source; } } return target; }
@Test public void testEquals() throws Exception{ Method method = TestClass.class.getMethod("beforeWithArgument", String.class); MethodInvoker methodInvoker = new SimpleMethodInvoker(testClass, method); method = TestClass.class.getMethod("beforeWithArgument", String.class); MethodInvoker methodInvoker2 = new SimpleMethodInvoker(testClass, method); assertEquals(methodInvoker, methodInvoker2); }
@Override public Object invokeMethod(Object... args) { Class<?>[] parameterTypes = method.getParameterTypes(); Object[] invokeArgs; if (parameterTypes.length == 0) { invokeArgs = new Object[] {}; } else if (parameterTypes.length != args.length) { throw new IllegalArgumentException("Wrong number of arguments, expected no more than: [" + parameterTypes.length + "]"); } else { invokeArgs = args; } method.setAccessible(true); try { // Extract the target from an Advised as late as possible // in case it contains a lazy initialization Object target = extractTarget(object, method); return method.invoke(target, invokeArgs); } catch (Exception e) { throw new IllegalArgumentException("Unable to invoke method: [" + method + "] on object: [" + object + "] with arguments: [" + Arrays.toString(args) + "]", e); } }
return new SimpleMethodInvoker(target, annotatedMethod.get());
private Object extractTarget(Object target, Method method) { if (target instanceof Advised) { Object source; try { source = ((Advised) target).getTargetSource().getTarget(); } catch (Exception e) { throw new IllegalStateException("Could not extract target from proxy", e); } if (source instanceof Advised) { source = extractTarget(source, method); } if (method.getDeclaringClass().isAssignableFrom(source.getClass())) { target = source; } } return target; }
@Test public void testMethodWithArgument() throws Exception{ MethodInvoker methodInvoker = new SimpleMethodInvoker(testClass, "argumentTest", Object.class); methodInvoker.invokeMethod(new Object()); assertTrue(testClass.argumentTestCalled); }
@Test public void testMethodWithExecution() throws Exception{ Method method = TestClass.class.getMethod("beforeWithArgument", String.class); MethodInvoker methodInvoker = new SimpleMethodInvoker(testClass, method); methodInvoker.invokeMethod(value); assertTrue(testClass.beforeCalled); }
@Test(expected=IllegalArgumentException.class) public void testMethodWithTooManyArguments() throws Exception{ Method method = TestClass.class.getMethod("beforeWithTooManyArguments", String.class, int.class); MethodInvoker methodInvoker = new SimpleMethodInvoker(testClass, method); methodInvoker.invokeMethod(value); assertFalse(testClass.beforeCalled); }
@Test public void testMethod() throws Exception{ Method method = TestClass.class.getMethod("before"); MethodInvoker methodInvoker = new SimpleMethodInvoker(testClass, method); methodInvoker.invokeMethod(value); assertTrue(testClass.beforeCalled); }
@Test public void testMethodByNameWithExecution() throws Exception{ MethodInvoker methodInvoker = new SimpleMethodInvoker(testClass, "beforeWithArgument", String.class); methodInvoker.invokeMethod(value); assertTrue(testClass.beforeCalled); }
@Test public void testMethodByName() throws Exception{ MethodInvoker methodInvoker = new SimpleMethodInvoker(testClass, "before", String.class); methodInvoker.invokeMethod(value); assertTrue(testClass.beforeCalled); }
@Test(expected=IllegalArgumentException.class) public void testMethodByNameWithTooManyArguments() throws Exception{ MethodInvoker methodInvoker = new SimpleMethodInvoker(testClass, "beforeWithTooManyArguments", String.class); methodInvoker.invokeMethod(value); assertFalse(testClass.beforeCalled); }
@Test public void testNormalCase() throws Throwable{ Map<String, Set<MethodInvoker>> invokerMap = new HashMap<>(); for(Method method : TestClass.class.getMethods()){ invokerMap.put(method.getName(), asSet( new SimpleMethodInvoker(testClass, method))); } interceptor = new MethodInvokerMethodInterceptor(invokerMap); interceptor.invoke(new StubMethodInvocation(TestClass.class.getMethod("method1"))); assertEquals(1, testClass.method1Count); interceptor.invoke(new StubMethodInvocation(TestClass.class.getMethod("method2"))); assertEquals(1, testClass.method2Count); }
/** * Create a {@link MethodInvoker} for the delegate from a single public * method. * * @param target an object to search for an appropriate method. * @param <C> the class. * @param <T> the type. * @return a {@link MethodInvoker} that calls a method on the delegate. */ public static <C, T> MethodInvoker getMethodInvokerForSingleArgument(Object target) { final AtomicReference<Method> methodHolder = new AtomicReference<>(); ReflectionUtils.doWithMethods(target.getClass(), method -> { if (method.getParameterTypes() == null || method.getParameterTypes().length != 1) { return; } if (method.getReturnType().equals(Void.TYPE) || ReflectionUtils.isEqualsMethod(method)) { return; } Assert.state(methodHolder.get() == null, "More than one non-void public method detected with single argument."); methodHolder.set(method); }); Method method = methodHolder.get(); return new SimpleMethodInvoker(target, method); } }
/** * Create a {@link MethodInvoker} using the provided method name to search. * * @param object to be invoked * @param methodName of the method to be invoked * @param paramsRequired boolean indicating whether the parameters are * required, if false, a no args version of the method will be searched for. * @param paramTypes - parameter types of the method to search for. * @return MethodInvoker if the method is found, null if it is not. */ public static MethodInvoker getMethodInvokerByName(Object object, String methodName, boolean paramsRequired, Class<?>... paramTypes) { Assert.notNull(object, "Object to invoke must not be null"); Method method = ClassUtils.getMethodIfAvailable(object.getClass(), methodName, paramTypes); if (method == null) { String errorMsg = "no method found with name [" + methodName + "] on class [" + object.getClass().getSimpleName() + "] compatible with the signature [" + getParamTypesString(paramTypes) + "]."; Assert.isTrue(!paramsRequired, errorMsg); // if no method was found for the given parameters, and the // parameters aren't required, then try with no params method = ClassUtils.getMethodIfAvailable(object.getClass(), methodName); Assert.notNull(method, errorMsg); } return new SimpleMethodInvoker(object, method); }
return new SimpleMethodInvoker(target, annotatedMethod.get());