Skip to content

Commit c922905

Browse files
artembilangaryrussell
authored andcommitted
GH-3912: Handler: ignore Groovy generated methods
Fixes #3912 **Cherry-pick to `5.5.x`**
1 parent beef2e6 commit c922905

File tree

2 files changed

+73
-34
lines changed

2 files changed

+73
-34
lines changed

spring-integration-core/src/main/java/org/springframework/integration/handler/support/MessagingMethodInvokerHelper.java

+34-33
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
5454
import org.springframework.core.MethodParameter;
5555
import org.springframework.core.ParameterNameDiscoverer;
56+
import org.springframework.core.annotation.AnnotatedElementUtils;
5657
import org.springframework.core.annotation.AnnotationAttributes;
5758
import org.springframework.core.annotation.AnnotationUtils;
5859
import org.springframework.core.convert.ConversionFailedException;
@@ -759,44 +760,24 @@ else if (!Modifier.isPublic(method1.getModifiers())) {
759760
ambiguousFallbackType, ambiguousFallbackMessageGenericType, matchesAnnotation, handlerMethod1);
760761
}
761762

762-
}, new UniqueMethodFilter(targetClass));
763+
}, ((ReflectionUtils.MethodFilter) this::isHandlerMethod).and(new UniqueMethodFilter(targetClass)));
763764

764765
if (candidateMethods.isEmpty() && candidateMessageMethods.isEmpty() && fallbackMethods.isEmpty()
765766
&& fallbackMessageMethods.isEmpty()) {
766767
findSingleSpecificMethodOnInterfacesIfProxy(candidateMessageMethods, candidateMethods);
767768
}
768769
}
769770

770-
@Nullable
771-
private HandlerMethod obtainHandlerMethodIfAny(Method methodToProcess) {
772-
HandlerMethod handlerMethodToUse = null;
773-
if (isMethodEligible(methodToProcess)) {
774-
try {
775-
handlerMethodToUse = createHandlerMethod(
776-
AopUtils.selectInvocableMethod(methodToProcess, ClassUtils.getUserClass(this.targetObject)));
777-
}
778-
catch (Exception ex) {
779-
LOGGER.debug(ex, "Method [" + methodToProcess + "] is not eligible for Message handling.");
780-
return null;
781-
}
782-
783-
if (AnnotationUtils.getAnnotation(methodToProcess, Default.class) != null) {
784-
Assert.state(this.defaultHandlerMethod == null,
785-
() -> "Only one method can be @Default, but there are more for: " + this.targetObject);
786-
this.defaultHandlerMethod = handlerMethodToUse;
787-
}
788-
}
789-
790-
return handlerMethodToUse;
791-
}
792-
793-
private boolean isMethodEligible(Method methodToProcess) {
794-
return !(methodToProcess.isBridge() || // NOSONAR boolean complexity
795-
isMethodDefinedOnObjectClass(methodToProcess) ||
796-
methodToProcess.getDeclaringClass().equals(Proxy.class) ||
797-
(this.requiresReply && void.class.equals(methodToProcess.getReturnType())) ||
798-
(this.methodName != null && !this.methodName.equals(methodToProcess.getName())) ||
799-
(this.methodName == null && isPausableMethod(methodToProcess)));
771+
private boolean isHandlerMethod(Method method) {
772+
Class<?> declaringClass = method.getDeclaringClass();
773+
return !(method.isSynthetic() ||
774+
ReflectionUtils.isObjectMethod(method) ||
775+
AnnotatedElementUtils.isAnnotated(method, "groovy.transform.Generated") ||
776+
declaringClass.getName().equals("groovy.lang.GroovyObject") ||
777+
declaringClass.equals(Proxy.class) ||
778+
(this.requiresReply && void.class.equals(method.getReturnType())) ||
779+
(this.methodName != null && !this.methodName.equals(method.getName())) ||
780+
(this.methodName == null && isPausableMethod(method)));
800781
}
801782

802783
private boolean isPausableMethod(Method pausableMethod) {
@@ -811,6 +792,27 @@ private boolean isPausableMethod(Method pausableMethod) {
811792
return pausable;
812793
}
813794

795+
@Nullable
796+
private HandlerMethod obtainHandlerMethodIfAny(Method methodToProcess) {
797+
HandlerMethod handlerMethodToUse;
798+
try {
799+
handlerMethodToUse = createHandlerMethod(
800+
AopUtils.selectInvocableMethod(methodToProcess, ClassUtils.getUserClass(this.targetObject)));
801+
}
802+
catch (Exception ex) {
803+
LOGGER.debug(ex, "Method [" + methodToProcess + "] is not eligible for Message handling.");
804+
return null;
805+
}
806+
807+
if (AnnotationUtils.getAnnotation(methodToProcess, Default.class) != null) {
808+
Assert.state(this.defaultHandlerMethod == null,
809+
() -> "Only one method can be @Default, but there are more for: " + this.targetObject);
810+
this.defaultHandlerMethod = handlerMethodToUse;
811+
}
812+
813+
return handlerMethodToUse;
814+
}
815+
814816
private void populateHandlerMethod(Map<Class<?>, HandlerMethod> candidateMethods,
815817
Map<Class<?>, HandlerMethod> candidateMessageMethods, Map<Class<?>, HandlerMethod> fallbackMethods,
816818
Map<Class<?>, HandlerMethod> fallbackMessageMethods, AtomicReference<Class<?>> ambiguousFallbackType,
@@ -1013,8 +1015,7 @@ private HandlerMethod findClosestMatch(Class<?> payloadType) {
10131015

10141016
private static boolean isMethodDefinedOnObjectClass(Method method) {
10151017
return method != null && // NOSONAR
1016-
(method.getDeclaringClass().equals(Object.class) || ReflectionUtils.isEqualsMethod(method) ||
1017-
ReflectionUtils.isHashCodeMethod(method) || ReflectionUtils.isToStringMethod(method) ||
1018+
(ReflectionUtils.isObjectMethod(method) ||
10181019
AopUtils.isFinalizeMethod(method) || (method.getName().equals("clone")
10191020
&& method.getParameterTypes().length == 0));
10201021
}

spring-integration-groovy/src/test/groovy/org/springframework/integration/groovy/dsl/test/GroovyDslTests.groovy

+39-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
package org.springframework.integration.groovy.dsl.test
1818

19-
19+
import groovy.transform.CompileStatic
2020
import org.junit.jupiter.api.Test
2121
import org.springframework.beans.factory.BeanFactory
2222
import org.springframework.beans.factory.annotation.Autowired
@@ -45,6 +45,7 @@ import reactor.core.publisher.Flux
4545
import reactor.test.StepVerifier
4646

4747
import java.time.Duration
48+
import java.util.concurrent.atomic.AtomicReference
4849
import java.util.function.Function
4950

5051
import static org.springframework.integration.groovy.dsl.IntegrationGroovyDsl.integrationFlow
@@ -196,6 +197,19 @@ class GroovyDslTests {
196197
assert this.wireTapChannel.receive(10_000)?.payload == 'test'
197198
}
198199

200+
@Autowired
201+
@Qualifier('externalServiceFlow.input')
202+
private MessageChannel externalServiceFlowInput
203+
204+
@Autowired
205+
GroovyTestService groovyTestService
206+
207+
@Test
208+
void 'handle service'() {
209+
this.externalServiceFlowInput.send(new GenericMessage<Object>('test'))
210+
assert groovyTestService.result.get() == 'TEST'
211+
}
212+
199213
@Configuration
200214
@EnableIntegration
201215
static class Config {
@@ -301,6 +315,30 @@ class GroovyDslTests {
301315
}
302316
}
303317

318+
@Bean
319+
myService() {
320+
new GroovyTestService()
321+
}
322+
323+
@Bean
324+
externalServiceFlow(GroovyTestService groovyTestService) {
325+
integrationFlow {
326+
handle groovyTestService
327+
}
328+
329+
}
330+
331+
}
332+
333+
@CompileStatic
334+
static class GroovyTestService {
335+
336+
AtomicReference<String> result = new AtomicReference<>()
337+
338+
void handlePayload(String payload) {
339+
result.set payload.toUpperCase()
340+
}
341+
304342
}
305343

306344
}

0 commit comments

Comments
 (0)