Skip to content

Commit fcca7a7

Browse files
authored
GH-3230: MMIH: Fix Pausable/Lifecycle Methods
Resolves #3230 Previously, methods with the same name as `Lifecycle` methods were unconditionally ignored. - Use logic similar to `ControlBusMethodFilter` to explicitly compare the candidate Method to those on `Paused` and `Lifecycle` and only ignore those. - Explicitly disallow these methods when named - previously the check was only performed if no method name was supplied. * - reinstate `Pausable/Lifecycle` methods if explicitly requested. - log `Pausable` methods that are not candidates. * - Fix typo in test method. **Cherry-pick to 5.2.x**
1 parent 76e7901 commit fcca7a7

File tree

2 files changed

+71
-6
lines changed

2 files changed

+71
-6
lines changed

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

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -71,6 +71,7 @@
7171
import org.springframework.integration.annotation.ServiceActivator;
7272
import org.springframework.integration.annotation.UseSpelInvoker;
7373
import org.springframework.integration.context.IntegrationContextUtils;
74+
import org.springframework.integration.core.Pausable;
7475
import org.springframework.integration.support.MutableMessage;
7576
import org.springframework.integration.support.NullAwarePayloadArgumentResolver;
7677
import org.springframework.integration.support.converter.ConfigurableCompositeMessageConverter;
@@ -97,7 +98,6 @@
9798
import org.springframework.util.Assert;
9899
import org.springframework.util.ClassUtils;
99100
import org.springframework.util.CollectionUtils;
100-
import org.springframework.util.ObjectUtils;
101101
import org.springframework.util.ReflectionUtils;
102102
import org.springframework.util.StringUtils;
103103

@@ -823,9 +823,19 @@ private boolean isMethodEligible(Method methodToProcess) {
823823
methodToProcess.getDeclaringClass().equals(Proxy.class) ||
824824
(this.requiresReply && void.class.equals(methodToProcess.getReturnType())) ||
825825
(this.methodName != null && !this.methodName.equals(methodToProcess.getName())) ||
826-
(this.methodName == null &&
827-
ObjectUtils.containsElement(new String[] { "start", "stop", "isRunning" },
828-
methodToProcess.getName())));
826+
(this.methodName == null && isPausableMethod(methodToProcess)));
827+
}
828+
829+
private boolean isPausableMethod(Method pausableMethod) {
830+
Class<?> declaringClass = pausableMethod.getDeclaringClass();
831+
boolean pausable = (Pausable.class.isAssignableFrom(declaringClass)
832+
|| Lifecycle.class.isAssignableFrom(declaringClass))
833+
&& ReflectionUtils.findMethod(Pausable.class, pausableMethod.getName(),
834+
pausableMethod.getParameterTypes()) != null;
835+
if (pausable && this.logger.isTraceEnabled()) {
836+
this.logger.trace(pausableMethod + " is not considered a candidate method unless explicitly requested");
837+
}
838+
return pausable;
829839
}
830840

831841
private void populateHandlerMethod(Map<Class<?>, HandlerMethod> candidateMethods,

spring-integration-core/src/test/java/org/springframework/integration/handler/MethodInvokingMessageProcessorTests.java

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@
1919
import static org.assertj.core.api.Assertions.assertThat;
2020
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
2121
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
22+
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
2223
import static org.assertj.core.api.Assertions.fail;
2324
import static org.mockito.AdditionalAnswers.returnsFirstArg;
2425
import static org.mockito.ArgumentMatchers.anyString;
@@ -51,6 +52,7 @@
5152
import org.springframework.beans.factory.BeanFactory;
5253
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
5354
import org.springframework.context.ApplicationContext;
55+
import org.springframework.context.Lifecycle;
5456
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
5557
import org.springframework.context.annotation.Bean;
5658
import org.springframework.context.annotation.Configuration;
@@ -1165,6 +1167,31 @@ public String myMethod(List<Employee<Person>> msg) {
11651167
assertThat(result).isEqualTo("Foo,Bar");
11661168
}
11671169

1170+
@Test
1171+
void lifecycleOnly() {
1172+
assertThatIllegalStateException().isThrownBy(() ->
1173+
new MethodInvokingMessageProcessor(new LifecycleBean(), (String) null))
1174+
.withMessageContaining("no eligible methods");
1175+
}
1176+
1177+
@Test
1178+
void lifecycleOnlyExplicitMethod() {
1179+
LifecycleBean targetObject = new LifecycleBean();
1180+
MethodInvokingMessageProcessor processor = new MethodInvokingMessageProcessor(targetObject, "start");
1181+
processor.setBeanFactory(mock(BeanFactory.class));
1182+
Object result = processor.processMessage(new GenericMessage<>("testing"));
1183+
assertThat(targetObject.startCalled).isTrue();
1184+
}
1185+
1186+
@Test
1187+
void lifecycleWithValidStartMethod() {
1188+
MethodInvokingMessageProcessor processor = new MethodInvokingMessageProcessor(new LifeCycleWithCustomStart(),
1189+
(String) null);
1190+
processor.setBeanFactory(mock(BeanFactory.class));
1191+
Object result = processor.processMessage(new GenericMessage<>("testing"));
1192+
assertThat(result).isEqualTo("TESTING");
1193+
}
1194+
11681195
public static class Employee<T> {
11691196

11701197
private T entity;
@@ -1586,4 +1613,32 @@ public Integer getBaz() {
15861613

15871614
}
15881615

1616+
public static class LifecycleBean implements Lifecycle {
1617+
1618+
boolean startCalled;
1619+
1620+
@Override
1621+
public void start() {
1622+
this.startCalled = true;
1623+
}
1624+
1625+
@Override
1626+
public void stop() {
1627+
}
1628+
1629+
@Override
1630+
public boolean isRunning() {
1631+
return false;
1632+
}
1633+
1634+
}
1635+
1636+
public static class LifeCycleWithCustomStart extends LifecycleBean {
1637+
1638+
public String start(String in) {
1639+
return in.toUpperCase();
1640+
}
1641+
1642+
}
1643+
15891644
}

0 commit comments

Comments
 (0)