From 8276bf8eae6d189527f7127fa1af9100d56a0faa Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Tue, 7 Feb 2017 12:30:33 -0500 Subject: [PATCH] MMIH: Use Original Method for InvocableHandMethod The `MessagingMethodInvokerHelper` extracts `targetClass` to process methods and avoid extra methods when class is Proxy The `InvocableHandlerMethod` is based on the reflection method invocation and we should use runtime methods on the proxy to invoke. We don't see such a problem in SpEL because it is parsed from the plain String to the real code later Polishing Add an Advice to the test. --- .../util/MessagingMethodInvokerHelper.java | 6 ++- .../MethodInvokingMessageProcessorTests.java | 38 +++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/spring-integration-core/src/main/java/org/springframework/integration/util/MessagingMethodInvokerHelper.java b/spring-integration-core/src/main/java/org/springframework/integration/util/MessagingMethodInvokerHelper.java index 114159e8af..2bf31e0485 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/util/MessagingMethodInvokerHelper.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/util/MessagingMethodInvokerHelper.java @@ -527,6 +527,7 @@ public class MessagingMethodInvokerHelper extends AbstractExpressionEvaluator } HandlerMethod handlerMethod1; try { + method1 = org.springframework.util.ClassUtils.getMostSpecificMethod(method1, targetObject.getClass()); InvocableHandlerMethod invocableHandlerMethod = this.messageHandlerMethodFactory.createInvocableHandlerMethod(targetObject, method1); handlerMethod1 = new HandlerMethod(invocableHandlerMethod, this.canProcessMessageList); @@ -626,9 +627,11 @@ public class MessagingMethodInvokerHelper extends AbstractExpressionEvaluator } } if (frameworkMethods.size() == 1) { + Method method = org.springframework.util.ClassUtils.getMostSpecificMethod(frameworkMethods.get(0), + targetObject.getClass()); InvocableHandlerMethod invocableHandlerMethod = this.messageHandlerMethodFactory.createInvocableHandlerMethod(targetObject, - frameworkMethods.get(0)); + method); HandlerMethod handlerMethod = new HandlerMethod(invocableHandlerMethod, this.canProcessMessageList); handlerMethods.put(CANDIDATE_METHODS, Collections.singletonMap(Object.class, handlerMethod)); handlerMethods.put(CANDIDATE_MESSAGE_METHODS, candidateMessageMethods); @@ -671,6 +674,7 @@ public class MessagingMethodInvokerHelper extends AbstractExpressionEvaluator } Method method = targetMethod.get(); if (method != null) { + method = org.springframework.util.ClassUtils.getMostSpecificMethod(method, targetObject.getClass()); InvocableHandlerMethod invocableHandlerMethod = this.messageHandlerMethodFactory.createInvocableHandlerMethod(targetObject, method); HandlerMethod handlerMethod = new HandlerMethod(invocableHandlerMethod, this.canProcessMessageList); diff --git a/spring-integration-core/src/test/java/org/springframework/integration/handler/MethodInvokingMessageProcessorTests.java b/spring-integration-core/src/test/java/org/springframework/integration/handler/MethodInvokingMessageProcessorTests.java index fd3d9c06e8..c9058168dc 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/handler/MethodInvokingMessageProcessorTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/handler/MethodInvokingMessageProcessorTests.java @@ -23,6 +23,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.Mockito.mock; @@ -32,7 +33,10 @@ import java.util.LinkedHashMap; import java.util.Map; import java.util.Optional; import java.util.Properties; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; +import org.aopalliance.intercept.MethodInterceptor; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hamcrest.Description; @@ -42,6 +46,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.springframework.aop.framework.ProxyFactory; import org.springframework.beans.DirectFieldAccessor; import org.springframework.beans.factory.BeanFactory; import org.springframework.expression.spel.SpelCompilerMode; @@ -54,7 +59,9 @@ import org.springframework.integration.support.MessageBuilder; import org.springframework.integration.test.util.TestUtils; import org.springframework.integration.util.MessagingMethodInvokerHelper; import org.springframework.messaging.Message; +import org.springframework.messaging.MessageHandler; import org.springframework.messaging.MessageHandlingException; +import org.springframework.messaging.MessagingException; import org.springframework.messaging.handler.annotation.Header; import org.springframework.messaging.support.GenericMessage; import org.springframework.util.StopWatch; @@ -761,6 +768,37 @@ public class MethodInvokingMessageProcessorTests { } + @Test + public void testProxyInvocation() { + final AtomicReference result = new AtomicReference<>(); + + class MyHandler implements MessageHandler { + + @Override + public void handleMessage(Message message) throws MessagingException { + result.set(message.getPayload()); + } + + } + + MessageHandler service = new MyHandler(); + final AtomicBoolean adviceCalled = new AtomicBoolean(); + ProxyFactory proxyFactory = new ProxyFactory(service); + proxyFactory.addAdvice((MethodInterceptor) i -> { + adviceCalled.set(true); + return i.proceed(); + }); + service = (MessageHandler) proxyFactory.getProxy(getClass().getClassLoader()); + + MethodInvokingMessageProcessor processor = new MethodInvokingMessageProcessor(service, "handleMessage"); + + processor.processMessage(new GenericMessage<>("foo")); + + assertEquals("foo", result.get()); + assertTrue(adviceCalled.get()); + } + + private DirectFieldAccessor compileImmediate(MethodInvokingMessageProcessor processor) { // Update the parser configuration compiler mode SpelParserConfiguration config = TestUtils.getPropertyValue(processor,