GH-3912: Handler: ignore Groovy generated methods
Fixes https://github.com/spring-projects/spring-integration/issues/3912 **Cherry-pick to `5.5.x`**
This commit is contained in:
committed by
Gary Russell
parent
beef2e68c7
commit
c922905c1c
@@ -53,6 +53,7 @@ import org.springframework.core.KotlinDetector;
|
||||
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.convert.ConversionFailedException;
|
||||
@@ -759,7 +760,7 @@ public class MessagingMethodInvokerHelper extends AbstractExpressionEvaluator im
|
||||
ambiguousFallbackType, ambiguousFallbackMessageGenericType, matchesAnnotation, handlerMethod1);
|
||||
}
|
||||
|
||||
}, new UniqueMethodFilter(targetClass));
|
||||
}, ((ReflectionUtils.MethodFilter) this::isHandlerMethod).and(new UniqueMethodFilter(targetClass)));
|
||||
|
||||
if (candidateMethods.isEmpty() && candidateMessageMethods.isEmpty() && fallbackMethods.isEmpty()
|
||||
&& fallbackMessageMethods.isEmpty()) {
|
||||
@@ -767,36 +768,16 @@ public class MessagingMethodInvokerHelper extends AbstractExpressionEvaluator im
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private HandlerMethod obtainHandlerMethodIfAny(Method methodToProcess) {
|
||||
HandlerMethod handlerMethodToUse = null;
|
||||
if (isMethodEligible(methodToProcess)) {
|
||||
try {
|
||||
handlerMethodToUse = createHandlerMethod(
|
||||
AopUtils.selectInvocableMethod(methodToProcess, ClassUtils.getUserClass(this.targetObject)));
|
||||
}
|
||||
catch (Exception ex) {
|
||||
LOGGER.debug(ex, "Method [" + methodToProcess + "] is not eligible for Message handling.");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (AnnotationUtils.getAnnotation(methodToProcess, Default.class) != null) {
|
||||
Assert.state(this.defaultHandlerMethod == null,
|
||||
() -> "Only one method can be @Default, but there are more for: " + this.targetObject);
|
||||
this.defaultHandlerMethod = handlerMethodToUse;
|
||||
}
|
||||
}
|
||||
|
||||
return handlerMethodToUse;
|
||||
}
|
||||
|
||||
private boolean isMethodEligible(Method methodToProcess) {
|
||||
return !(methodToProcess.isBridge() || // NOSONAR boolean complexity
|
||||
isMethodDefinedOnObjectClass(methodToProcess) ||
|
||||
methodToProcess.getDeclaringClass().equals(Proxy.class) ||
|
||||
(this.requiresReply && void.class.equals(methodToProcess.getReturnType())) ||
|
||||
(this.methodName != null && !this.methodName.equals(methodToProcess.getName())) ||
|
||||
(this.methodName == null && isPausableMethod(methodToProcess)));
|
||||
private boolean isHandlerMethod(Method method) {
|
||||
Class<?> declaringClass = method.getDeclaringClass();
|
||||
return !(method.isSynthetic() ||
|
||||
ReflectionUtils.isObjectMethod(method) ||
|
||||
AnnotatedElementUtils.isAnnotated(method, "groovy.transform.Generated") ||
|
||||
declaringClass.getName().equals("groovy.lang.GroovyObject") ||
|
||||
declaringClass.equals(Proxy.class) ||
|
||||
(this.requiresReply && void.class.equals(method.getReturnType())) ||
|
||||
(this.methodName != null && !this.methodName.equals(method.getName())) ||
|
||||
(this.methodName == null && isPausableMethod(method)));
|
||||
}
|
||||
|
||||
private boolean isPausableMethod(Method pausableMethod) {
|
||||
@@ -811,6 +792,27 @@ public class MessagingMethodInvokerHelper extends AbstractExpressionEvaluator im
|
||||
return pausable;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private HandlerMethod obtainHandlerMethodIfAny(Method methodToProcess) {
|
||||
HandlerMethod handlerMethodToUse;
|
||||
try {
|
||||
handlerMethodToUse = createHandlerMethod(
|
||||
AopUtils.selectInvocableMethod(methodToProcess, ClassUtils.getUserClass(this.targetObject)));
|
||||
}
|
||||
catch (Exception ex) {
|
||||
LOGGER.debug(ex, "Method [" + methodToProcess + "] is not eligible for Message handling.");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (AnnotationUtils.getAnnotation(methodToProcess, Default.class) != null) {
|
||||
Assert.state(this.defaultHandlerMethod == null,
|
||||
() -> "Only one method can be @Default, but there are more for: " + this.targetObject);
|
||||
this.defaultHandlerMethod = handlerMethodToUse;
|
||||
}
|
||||
|
||||
return handlerMethodToUse;
|
||||
}
|
||||
|
||||
private void populateHandlerMethod(Map<Class<?>, HandlerMethod> candidateMethods,
|
||||
Map<Class<?>, HandlerMethod> candidateMessageMethods, Map<Class<?>, HandlerMethod> fallbackMethods,
|
||||
Map<Class<?>, HandlerMethod> fallbackMessageMethods, AtomicReference<Class<?>> ambiguousFallbackType,
|
||||
@@ -1013,8 +1015,7 @@ public class MessagingMethodInvokerHelper extends AbstractExpressionEvaluator im
|
||||
|
||||
private static boolean isMethodDefinedOnObjectClass(Method method) {
|
||||
return method != null && // NOSONAR
|
||||
(method.getDeclaringClass().equals(Object.class) || ReflectionUtils.isEqualsMethod(method) ||
|
||||
ReflectionUtils.isHashCodeMethod(method) || ReflectionUtils.isToStringMethod(method) ||
|
||||
(ReflectionUtils.isObjectMethod(method) ||
|
||||
AopUtils.isFinalizeMethod(method) || (method.getName().equals("clone")
|
||||
&& method.getParameterTypes().length == 0));
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
package org.springframework.integration.groovy.dsl.test
|
||||
|
||||
|
||||
import groovy.transform.CompileStatic
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.springframework.beans.factory.BeanFactory
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
@@ -45,6 +45,7 @@ import reactor.core.publisher.Flux
|
||||
import reactor.test.StepVerifier
|
||||
|
||||
import java.time.Duration
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
import java.util.function.Function
|
||||
|
||||
import static org.springframework.integration.groovy.dsl.IntegrationGroovyDsl.integrationFlow
|
||||
@@ -196,6 +197,19 @@ class GroovyDslTests {
|
||||
assert this.wireTapChannel.receive(10_000)?.payload == 'test'
|
||||
}
|
||||
|
||||
@Autowired
|
||||
@Qualifier('externalServiceFlow.input')
|
||||
private MessageChannel externalServiceFlowInput
|
||||
|
||||
@Autowired
|
||||
GroovyTestService groovyTestService
|
||||
|
||||
@Test
|
||||
void 'handle service'() {
|
||||
this.externalServiceFlowInput.send(new GenericMessage<Object>('test'))
|
||||
assert groovyTestService.result.get() == 'TEST'
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableIntegration
|
||||
static class Config {
|
||||
@@ -301,6 +315,30 @@ class GroovyDslTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
myService() {
|
||||
new GroovyTestService()
|
||||
}
|
||||
|
||||
@Bean
|
||||
externalServiceFlow(GroovyTestService groovyTestService) {
|
||||
integrationFlow {
|
||||
handle groovyTestService
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@CompileStatic
|
||||
static class GroovyTestService {
|
||||
|
||||
AtomicReference<String> result = new AtomicReference<>()
|
||||
|
||||
void handlePayload(String payload) {
|
||||
result.set payload.toUpperCase()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user