GH-2690: Add MessageHandlerMethodFactory beans (#2798)

* GH-2690: Add MessageHandlerMethodFactory beans

Fixes https://github.com/spring-projects/spring-integration/issues/2690

For more end-user flexibility and for simplicity of the `MessagingMethodInvokerHelper`
logic, add `IntegrationContextUtils.MESSAGE_HANDLER_FACTORY_BEAN_NAME` and
`IntegrationContextUtils.LIST_MESSAGE_HANDLER_FACTORY_BEAN_NAME`
infrastructure beans

* Use mentioned beans in the `MessagingMethodInvokerHelper` if any,
otherwise fallback to the locally configured `MessageHandlerMethodFactory`,
although this is necessary only for our non-Spring-based unit tests
* Relax `BeanFactory` requirement for the `EvaluationContext` since it
is going to be there in the Spring-based environment, but might not be
available in the plain unit tests
* Provide some optimization and refactoring for the `MessagingMethodInvokerHelper`
* Remove deprecated `HandlerMethodArgumentResolversHolder` and
`ARGUMENT_RESOLVERS_BEAN_NAME` & `LIST_ARGUMENT_RESOLVERS_BEAN_NAME`
bean definitions and constants for their names

* * Revert `getEvaluationContext(false)` usage.
* Fix `MessagingMethodInvokerHelper` to propagate `BeanFactory` to
argument resolvers if any
This commit is contained in:
Artem Bilan
2019-03-13 13:34:41 -04:00
committed by Gary Russell
parent 0b3e2c98c3
commit d53433cad7
7 changed files with 144 additions and 283 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -67,6 +67,7 @@ import org.springframework.integration.support.converter.ConfigurableCompositeMe
import org.springframework.integration.support.converter.DefaultDatatypeChannelMessageConverter;
import org.springframework.integration.support.json.JacksonPresent;
import org.springframework.integration.support.utils.IntegrationUtils;
import org.springframework.messaging.handler.annotation.support.DefaultMessageHandlerMethodFactory;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.util.ClassUtils;
@@ -122,8 +123,8 @@ class DefaultConfiguringBeanFactoryPostProcessor
registerGlobalChannelInterceptorProcessor();
registerDefaultDatatypeChannelMessageConverter();
registerArgumentResolverMessageConverter();
registerArgumentResolvers();
registerListCapableArgumentResolvers();
registerMessageHandlerMethodFactory();
registerListMessageHandlerMethodFactory();
}
else if (logger.isWarnEnabled()) {
logger.warn("BeanFactory is not a BeanDefinitionRegistry. " +
@@ -479,32 +480,32 @@ class DefaultConfiguringBeanFactoryPostProcessor
}
}
/**
* Register the default
* {@link org.springframework.integration.handler.support.HandlerMethodArgumentResolversHolder} for handler
* method invocation.
*/
private void registerArgumentResolvers() {
if (!this.beanFactory.containsBean(IntegrationContextUtils.ARGUMENT_RESOLVERS_BEAN_NAME)) {
this.registry.registerBeanDefinition(IntegrationContextUtils.ARGUMENT_RESOLVERS_BEAN_NAME,
internalArgumentResolversBuilder(false));
private void registerMessageHandlerMethodFactory() {
if (!this.beanFactory.containsBean(IntegrationContextUtils.MESSAGE_HANDLER_FACTORY_BEAN_NAME)) {
BeanDefinitionBuilder messageHandlerMethodFactoryBuilder =
createMessageHandlerMethodFactoryBeanDefinition(false);
this.registry.registerBeanDefinition(IntegrationContextUtils.MESSAGE_HANDLER_FACTORY_BEAN_NAME,
messageHandlerMethodFactoryBuilder.getBeanDefinition());
}
}
/**
* Register the default
* {@link org.springframework.integration.handler.support.HandlerMethodArgumentResolversHolder} for handler
* method invocation for lists.
*/
private void registerListCapableArgumentResolvers() {
if (!this.beanFactory.containsBean(IntegrationContextUtils.LIST_ARGUMENT_RESOLVERS_BEAN_NAME)) {
this.registry.registerBeanDefinition(IntegrationContextUtils.LIST_ARGUMENT_RESOLVERS_BEAN_NAME,
internalArgumentResolversBuilder(true));
private void registerListMessageHandlerMethodFactory() {
if (!this.beanFactory.containsBean(IntegrationContextUtils.LIST_MESSAGE_HANDLER_FACTORY_BEAN_NAME)) {
BeanDefinitionBuilder messageHandlerMethodFactoryBuilder =
createMessageHandlerMethodFactoryBeanDefinition(true);
this.registry.registerBeanDefinition(IntegrationContextUtils.LIST_MESSAGE_HANDLER_FACTORY_BEAN_NAME,
messageHandlerMethodFactoryBuilder.getBeanDefinition());
}
}
@SuppressWarnings("deprecation")
private BeanDefinition internalArgumentResolversBuilder(boolean listCapable) {
private BeanDefinitionBuilder createMessageHandlerMethodFactoryBeanDefinition(boolean listCapable) {
return BeanDefinitionBuilder.genericBeanDefinition(DefaultMessageHandlerMethodFactory.class)
.addPropertyReference("messageConverter",
IntegrationContextUtils.ARGUMENT_RESOLVER_MESSAGE_CONVERTER_BEAN_NAME)
.addPropertyValue("customArgumentResolvers", buildArgumentResolvers(listCapable));
}
private ManagedList<BeanDefinition> buildArgumentResolvers(boolean listCapable) {
ManagedList<BeanDefinition> resolvers = new ManagedList<>();
resolvers.add(new RootBeanDefinition(PayloadExpressionArgumentResolver.class));
BeanDefinitionBuilder builder =
@@ -513,7 +514,6 @@ class DefaultConfiguringBeanFactoryPostProcessor
// TODO Validator ?
resolvers.add(builder.getBeanDefinition());
resolvers.add(new RootBeanDefinition(PayloadsArgumentResolver.class));
resolvers.add(new RootBeanDefinition(MapArgumentResolver.class));
if (listCapable) {
resolvers.add(
@@ -522,10 +522,8 @@ class DefaultConfiguringBeanFactoryPostProcessor
.getBeanDefinition());
}
return BeanDefinitionBuilder.genericBeanDefinition(
org.springframework.integration.handler.support.HandlerMethodArgumentResolversHolder.class)
.addConstructorArgValue(resolvers)
.getBeanDefinition();
resolvers.add(new RootBeanDefinition(MapArgumentResolver.class));
return resolvers;
}
}

View File

@@ -101,14 +101,12 @@ public abstract class IntegrationContextUtils {
public static final String ARGUMENT_RESOLVER_MESSAGE_CONVERTER_BEAN_NAME =
"integrationArgumentResolverMessageConverter";
public static final String ARGUMENT_RESOLVERS_BEAN_NAME = "integrationArgumentResolvers";
public static final String LIST_ARGUMENT_RESOLVERS_BEAN_NAME = "integrationListArgumentResolvers";
public static final String DISPOSABLES_BEAN_NAME = "integrationDisposableAutoCreatedBeans";
public static final String MESSAGE_HANDLER_FACTORY_BEAN_NAME = "integrationMessageHandlerMethodFactory";
public static final String LIST_MESSAGE_HANDLER_FACTORY_BEAN_NAME = "integrationListMessageHandlerMethodFactory";
/**
* @param beanFactory BeanFactory for lookup, must not be null.
* @return The {@link MetadataStore} bean whose name is "metadataStore".

View File

@@ -61,7 +61,7 @@ public class ExpressionCommandMessageProcessor extends AbstractMessageProcessor<
}
if (methodFilter != null) {
MethodResolver methodResolver = new ExpressionCommandMethodResolver(methodFilter);
getEvaluationContext(false).setMethodResolvers(Collections.singletonList(methodResolver));
getEvaluationContext().setMethodResolvers(Collections.singletonList(methodResolver));
}
}

View File

@@ -1,54 +0,0 @@
/*
* Copyright 2017-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.handler.support;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver;
/**
* A holder for the configured argument resolvers.
*
* @author Gary Russell
*
* @since 5.0
* @deprecated as of 5.1.2. Instead simply configure your own MessageHandlerMethodFactory as a bean.
*/
@Deprecated
public class HandlerMethodArgumentResolversHolder {
private final List<HandlerMethodArgumentResolver> resolvers;
public HandlerMethodArgumentResolversHolder(List<HandlerMethodArgumentResolver> resolvers) {
this.resolvers = new ArrayList<>(resolvers);
}
public List<HandlerMethodArgumentResolver> getResolvers() {
return Collections.unmodifiableList(this.resolvers);
}
public void addResolver(HandlerMethodArgumentResolver resolver) {
this.resolvers.add(resolver);
}
public boolean removeResolver(HandlerMethodArgumentResolver resolver) {
return this.resolvers.remove(resolver);
}
}

View File

@@ -43,7 +43,6 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanExpressionContext;
import org.springframework.beans.factory.config.BeanExpressionResolver;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
@@ -56,7 +55,6 @@ import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.convert.ConversionFailedException;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.ConverterNotFoundException;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.EvaluationException;
@@ -341,8 +339,6 @@ public class MessagingMethodInvokerHelper extends AbstractExpressionEvaluator im
@Override
public void setBeanFactory(BeanFactory beanFactory) {
super.setBeanFactory(beanFactory);
((DefaultMessageHandlerMethodFactory) this.messageHandlerMethodFactory).setBeanFactory(beanFactory);
if (beanFactory instanceof ConfigurableListableBeanFactory) {
BeanExpressionResolver beanExpressionResolver = ((ConfigurableListableBeanFactory) beanFactory)
.getBeanExpressionResolver();
@@ -353,15 +349,6 @@ public class MessagingMethodInvokerHelper extends AbstractExpressionEvaluator im
}
}
@Override
public void setConversionService(ConversionService conversionService) {
super.setConversionService(conversionService);
if (conversionService != null) {
((DefaultMessageHandlerMethodFactory) this.messageHandlerMethodFactory)
.setConversionService(conversionService);
}
}
@Nullable
public Object process(Message<?> message) {
ParametersWrapper parameters = new ParametersWrapper(message);
@@ -398,20 +385,9 @@ public class MessagingMethodInvokerHelper extends AbstractExpressionEvaluator im
return !(this.targetObject instanceof Lifecycle) || ((Lifecycle) this.targetObject).isRunning();
}
/*
* Private constructors for internal use
*/
private boolean isProvidedMessageHandlerFactoryBean() {
BeanFactory beanFactory = getBeanFactory();
return beanFactory != null
&& beanFactory.containsBean(IntegrationContextUtils.MESSAGE_HANDLER_FACTORY_BEAN_NAME);
}
private HandlerMethod createHandlerMethod(Method method) {
try {
InvocableHandlerMethod invocableHandlerMethod = createInvocableHandlerMethod(method);
HandlerMethod newHandlerMethod = new HandlerMethod(invocableHandlerMethod, this.canProcessMessageList);
HandlerMethod newHandlerMethod = new HandlerMethod(method, this.canProcessMessageList);
checkSpelInvokerRequired(getTargetClass(this.targetObject), method, newHandlerMethod);
return newHandlerMethod;
}
@@ -438,7 +414,7 @@ public class MessagingMethodInvokerHelper extends AbstractExpressionEvaluator im
}
private void prepareEvaluationContext() {
StandardEvaluationContext context = getEvaluationContext(false);
StandardEvaluationContext context = getEvaluationContext();
Class<?> targetType = AopUtils.getTargetClass(this.targetObject);
if (this.method != null) {
context.registerMethodFilter(targetType, new FixedMethodFilter(this.method));
@@ -471,13 +447,12 @@ public class MessagingMethodInvokerHelper extends AbstractExpressionEvaluator im
if (this.expectedType == null) {
return true;
}
List<Method> methods = filter.filter(Arrays.asList(ReflectionUtils.getAllDeclaredMethods(targetType)));
for (Method candidate : methods) {
if (typeConverter.canConvert(TypeDescriptor.valueOf(candidate.getReturnType()), this.expectedType)) {
return true;
}
}
return false;
return methods
.stream()
.anyMatch(candidate ->
typeConverter.canConvert(TypeDescriptor.valueOf(candidate.getReturnType()), this.expectedType));
}
@Nullable
@@ -493,18 +468,16 @@ public class MessagingMethodInvokerHelper extends AbstractExpressionEvaluator im
if (!candidate.initialized) {
initializeHandler(candidate);
}
Expression expression = candidate.expression;
Object result;
if (this.useSpelInvoker || candidate.spelOnly) {
result = invokeExpression(expression, parameters);
result = invokeExpression(candidate.expression, parameters);
}
else {
result = invokeHandlerMethod(candidate, parameters);
}
if (result != null && this.expectedType != null) {
return getEvaluationContext(true)
return getEvaluationContext()
.getTypeConverter()
.convertValue(result, TypeDescriptor.forObject(result), this.expectedType);
}
@@ -513,129 +486,94 @@ public class MessagingMethodInvokerHelper extends AbstractExpressionEvaluator im
}
}
private void initializeHandler(HandlerMethod candidate) {
ExpressionParser parser;
if (candidate.useSpelInvoker == null) {
parser = EXPRESSION_PARSER_DEFAULT;
private synchronized void initialize() {
if (isProvidedMessageHandlerFactoryBean()) {
LOGGER.info("Overriding default instance of MessageHandlerMethodFactory with provided one.");
this.messageHandlerMethodFactory =
getBeanFactory()
.getBean(
this.canProcessMessageList
? IntegrationContextUtils.LIST_MESSAGE_HANDLER_FACTORY_BEAN_NAME
: IntegrationContextUtils.MESSAGE_HANDLER_FACTORY_BEAN_NAME,
MessageHandlerMethodFactory.class);
}
else {
String compilerMode = resolveExpression(candidate.useSpelInvoker.compilerMode(),
"UseSpelInvoker.compilerMode:").toUpperCase();
parser = !StringUtils.hasText(compilerMode)
? EXPRESSION_PARSER_DEFAULT
: SPEL_COMPILERS.get(SpelCompilerMode.valueOf(compilerMode));
configureLocalMessageHandlerFactory();
}
candidate.expression = parser.parseExpression(candidate.expressionString);
candidate.initialized = true;
prepareEvaluationContext();
this.initialized = true;
}
@SuppressWarnings("deprecation")
private synchronized void initialize() {
if (!this.initialized) {
BeanFactory beanFactory = getBeanFactory();
if (isProvidedMessageHandlerFactoryBean()) {
LOGGER.info("Overriding default instance of MessageHandlerMethodFactory with provided one.");
this.messageHandlerMethodFactory =
beanFactory.getBean(IntegrationContextUtils.MESSAGE_HANDLER_FACTORY_BEAN_NAME,
MessageHandlerMethodFactory.class);
this.handlerMethodsList
.stream()
.map(Map::values)
.flatMap(Collection::stream)
.forEach(handlerMethod ->
handlerMethod.replaceInvocableHandlerMethod(
createInvocableHandlerMethod(handlerMethod.invocableHandlerMethod.getMethod())));
}
else {
if (beanFactory != null &&
beanFactory.containsBean(
IntegrationContextUtils.ARGUMENT_RESOLVER_MESSAGE_CONVERTER_BEAN_NAME)) {
try {
MessageConverter messageConverter =
beanFactory.getBean(
IntegrationContextUtils.ARGUMENT_RESOLVER_MESSAGE_CONVERTER_BEAN_NAME,
MessageConverter.class);
((DefaultMessageHandlerMethodFactory) this.messageHandlerMethodFactory)
.setMessageConverter(messageConverter);
HandlerMethodArgumentResolversHolder handlerMethodArgumentResolversHolder =
beanFactory.getBean(this.canProcessMessageList
? IntegrationContextUtils.LIST_ARGUMENT_RESOLVERS_BEAN_NAME
: IntegrationContextUtils.ARGUMENT_RESOLVERS_BEAN_NAME,
HandlerMethodArgumentResolversHolder.class);
((DefaultMessageHandlerMethodFactory) this.messageHandlerMethodFactory)
.setCustomArgumentResolvers(
handlerMethodArgumentResolversHolder.getResolvers());
}
catch (NoSuchBeanDefinitionException e) {
configureLocalMessageHandlerFactory();
}
}
else {
configureLocalMessageHandlerFactory();
}
((DefaultMessageHandlerMethodFactory) this.messageHandlerMethodFactory).afterPropertiesSet();
}
prepareEvaluationContext();
this.initialized = true;
}
private boolean isProvidedMessageHandlerFactoryBean() {
BeanFactory beanFactory = getBeanFactory();
return beanFactory != null
&& beanFactory.containsBean(
this.canProcessMessageList
? IntegrationContextUtils.LIST_MESSAGE_HANDLER_FACTORY_BEAN_NAME
: IntegrationContextUtils.MESSAGE_HANDLER_FACTORY_BEAN_NAME);
}
/*
* This should not be needed in production but we have many tests
* that don't run in an application context.
*/
private void configureLocalMessageHandlerFactory() {
MessageConverter messageConverter = null;
BeanFactory beanFactory = getBeanFactory();
if (beanFactory != null &&
beanFactory.containsBean(IntegrationContextUtils.ARGUMENT_RESOLVER_MESSAGE_CONVERTER_BEAN_NAME)) {
messageConverter = beanFactory
.getBean(IntegrationContextUtils.ARGUMENT_RESOLVER_MESSAGE_CONVERTER_BEAN_NAME,
MessageConverter.class);
((DefaultMessageHandlerMethodFactory) this.messageHandlerMethodFactory)
.setMessageConverter(messageConverter);
private void initializeHandler(HandlerMethod candidate) {
ExpressionParser parser;
if (candidate.useSpelInvoker == null) {
parser = EXPRESSION_PARSER_DEFAULT;
}
else {
messageConverter = new ConfigurableCompositeMessageConverter();
String compilerMode = resolveExpression(candidate.useSpelInvoker.compilerMode()).toUpperCase();
parser = !StringUtils.hasText(compilerMode)
? EXPRESSION_PARSER_DEFAULT
: SPEL_COMPILERS.get(SpelCompilerMode.valueOf(compilerMode));
}
NullAwarePayloadArgumentResolver nullResolver = new NullAwarePayloadArgumentResolver(messageConverter);
PayloadExpressionArgumentResolver payloadExpressionArgumentResolver = new PayloadExpressionArgumentResolver();
if (beanFactory != null) {
payloadExpressionArgumentResolver.setBeanFactory(beanFactory);
candidate.expression = parser.parseExpression(candidate.expressionString);
if (!this.useSpelInvoker && !candidate.spelOnly) {
candidate.setInvocableHandlerMethod(createInvocableHandlerMethod(candidate.method));
}
candidate.initialized = true;
}
PayloadsArgumentResolver payloadsArgumentResolver = new PayloadsArgumentResolver();
if (beanFactory != null) {
payloadsArgumentResolver.setBeanFactory(beanFactory);
}
private void configureLocalMessageHandlerFactory() {
BeanFactory beanFactory = getBeanFactory();
MapArgumentResolver mapArgumentResolver = new MapArgumentResolver();
if (beanFactory != null) {
mapArgumentResolver.setBeanFactory(beanFactory);
}
MessageConverter messageConverter = new ConfigurableCompositeMessageConverter();
List<HandlerMethodArgumentResolver> customArgumentResolvers = new LinkedList<>();
PayloadExpressionArgumentResolver payloadExpressionArgumentResolver = new PayloadExpressionArgumentResolver();
PayloadsArgumentResolver payloadsArgumentResolver = new PayloadsArgumentResolver();
customArgumentResolvers.add(payloadExpressionArgumentResolver);
customArgumentResolvers.add(nullResolver);
customArgumentResolvers.add(new NullAwarePayloadArgumentResolver(messageConverter));
customArgumentResolvers.add(payloadsArgumentResolver);
CollectionArgumentResolver collectionArgumentResolver = null;
if (this.canProcessMessageList) {
CollectionArgumentResolver collectionArgumentResolver = new CollectionArgumentResolver(true);
if (beanFactory != null) {
collectionArgumentResolver.setBeanFactory(beanFactory);
}
collectionArgumentResolver = new CollectionArgumentResolver(true);
customArgumentResolvers.add(collectionArgumentResolver);
}
MapArgumentResolver mapArgumentResolver = new MapArgumentResolver();
customArgumentResolvers.add(mapArgumentResolver);
((DefaultMessageHandlerMethodFactory) this.messageHandlerMethodFactory)
.setCustomArgumentResolvers(customArgumentResolvers);
if (beanFactory != null) {
payloadExpressionArgumentResolver.setBeanFactory(beanFactory);
payloadsArgumentResolver.setBeanFactory(beanFactory);
mapArgumentResolver.setBeanFactory(beanFactory);
if (collectionArgumentResolver != null) {
collectionArgumentResolver.setBeanFactory(beanFactory);
}
}
DefaultMessageHandlerMethodFactory localHandlerMethodFactory =
(DefaultMessageHandlerMethodFactory) this.messageHandlerMethodFactory;
localHandlerMethodFactory.setMessageConverter(messageConverter);
localHandlerMethodFactory.setCustomArgumentResolvers(customArgumentResolvers);
localHandlerMethodFactory.afterPropertiesSet();
}
private Object invokeHandlerMethod(HandlerMethod handlerMethod, ParametersWrapper parameters) {
@@ -943,27 +881,20 @@ public class MessagingMethodInvokerHelper extends AbstractExpressionEvaluator im
@Nullable
private Method obtainFrameworkMethod(Class<?> targetClass) {
Method frameworkMethod = null;
for (Class<?> iface : ClassUtils.getAllInterfacesForClass(targetClass)) {
try {
// Can't use real class because of package tangle
if ("org.springframework.integration.gateway.RequestReplyExchanger".equals(iface.getName())) {
frameworkMethod =
ClassUtils.getMostSpecificMethod(
targetClass.getMethod("exchange", Message.class),
this.targetObject.getClass());
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(this.targetObject.getClass() +
": Ambiguous fallback methods; using RequestReplyExchanger.exchange()");
}
break;
return ClassUtils.getMostSpecificMethod(
targetClass.getMethod("exchange", Message.class),
this.targetObject.getClass());
}
}
catch (Exception ex) {
throw new IllegalStateException(ex);
}
}
return frameworkMethod;
return null;
}
private void findSingleSpecifMethodOnInterfacesIfProxy(Map<Class<?>, HandlerMethod> candidateMessageMethods,
@@ -1026,7 +957,7 @@ public class MessagingMethodInvokerHelper extends AbstractExpressionEvaluator im
}
}
private String resolveExpression(String value, String msg) {
private String resolveExpression(String value) {
String resolvedValue = resolve(value);
if (!(resolvedValue.startsWith("#{") && value.endsWith("}"))) {
@@ -1034,7 +965,7 @@ public class MessagingMethodInvokerHelper extends AbstractExpressionEvaluator im
}
Object evaluated = this.resolver.evaluate(resolvedValue, this.expressionContext);
Assert.isInstanceOf(String.class, evaluated, msg);
Assert.isInstanceOf(String.class, evaluated, "UseSpelInvoker.compilerMode:");
return (String) evaluated;
}
@@ -1125,22 +1056,24 @@ public class MessagingMethodInvokerHelper extends AbstractExpressionEvaluator im
private final boolean canProcessMessageList;
private final Method method;
private InvocableHandlerMethod invocableHandlerMethod;
private volatile Expression expression;
private Expression expression;
private volatile TypeDescriptor targetParameterTypeDescriptor;
private TypeDescriptor targetParameterTypeDescriptor;
private volatile Class<?> targetParameterType = Void.class;
private Class<?> targetParameterType = Void.class;
private MethodParameter exclusiveMethodParameter;
private volatile boolean messageMethod;
private boolean messageMethod;
private UseSpelInvoker useSpelInvoker;
private volatile boolean spelOnly;
private volatile UseSpelInvoker useSpelInvoker;
private volatile boolean initialized;
// The number of times InvocableHandlerMethod was attempted and failed - enables us to eventually
@@ -1148,13 +1081,13 @@ public class MessagingMethodInvokerHelper extends AbstractExpressionEvaluator im
// Switching to spelOnly afterwards forever.
private volatile int failedAttempts = 0;
HandlerMethod(InvocableHandlerMethod invocableHandlerMethod, boolean canProcessMessageList) {
this.invocableHandlerMethod = invocableHandlerMethod;
HandlerMethod(Method method, boolean canProcessMessageList) {
this.method = method;
this.canProcessMessageList = canProcessMessageList;
this.expressionString = generateExpression(this.invocableHandlerMethod.getMethod());
this.expressionString = generateExpression(this.method);
}
void replaceInvocableHandlerMethod(InvocableHandlerMethod newInvocableHandlerMethod) {
void setInvocableHandlerMethod(InvocableHandlerMethod newInvocableHandlerMethod) {
this.invocableHandlerMethod = newInvocableHandlerMethod;
}
@@ -1184,7 +1117,7 @@ public class MessagingMethodInvokerHelper extends AbstractExpressionEvaluator im
@Override
public String toString() {
return this.invocableHandlerMethod.toString();
return this.method.toString();
}
private String generateExpression(Method method) {

View File

@@ -107,8 +107,7 @@ public class AggregatorAnnotationTests {
Object handlerMethod = processorAccessor.getPropertyValue("handlerMethod");
assertThat(handlerMethod).isNotNull();
DirectFieldAccessor handlerMethodAccessor = new DirectFieldAccessor(handlerMethod);
Method completionCheckerMethod = (Method) handlerMethodAccessor.getPropertyValue(
"invocableHandlerMethod.method");
Method completionCheckerMethod = (Method) handlerMethodAccessor.getPropertyValue("method");
assertThat(completionCheckerMethod.getName()).isEqualTo("correlate");
context.close();
}

View File

@@ -17,12 +17,13 @@
package org.springframework.integration.transformer;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.Mockito.mock;
import java.lang.reflect.Method;
import java.util.Properties;
import org.junit.Test;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.integration.annotation.Transformer;
@@ -37,10 +38,10 @@ import org.springframework.messaging.support.GenericMessage;
* @author Mark Fisher
* @author Artem Bilan
*/
public class MethodInvokingTransformerTests {
class MethodInvokingTransformerTests {
@Test
public void simplePayloadConfiguredWithMethodReference() throws Exception {
void simplePayloadConfiguredWithMethodReference() throws Exception {
TestBean testBean = new TestBean();
Method testMethod = testBean.getClass().getMethod("exclaim", String.class);
MethodInvokingTransformer transformer = new MethodInvokingTransformer(testBean, testMethod);
@@ -51,7 +52,7 @@ public class MethodInvokingTransformerTests {
}
@Test
public void simplePayloadConfiguredWithMethodName() {
void simplePayloadConfiguredWithMethodName() {
TestBean testBean = new TestBean();
MethodInvokingTransformer transformer = new MethodInvokingTransformer(testBean, "exclaim");
transformer.setBeanFactory(mock(BeanFactory.class));
@@ -61,7 +62,7 @@ public class MethodInvokingTransformerTests {
}
@Test
public void typeConversionConfiguredWithMethodReference() throws Exception {
void typeConversionConfiguredWithMethodReference() throws Exception {
TestBean testBean = new TestBean();
Method testMethod = testBean.getClass().getMethod("exclaim", String.class);
MethodInvokingTransformer transformer = new MethodInvokingTransformer(testBean, testMethod);
@@ -72,7 +73,7 @@ public class MethodInvokingTransformerTests {
}
@Test
public void typeConversionConfiguredWithMethodName() {
void typeConversionConfiguredWithMethodName() {
TestBean testBean = new TestBean();
MethodInvokingTransformer transformer = new MethodInvokingTransformer(testBean, "exclaim");
transformer.setBeanFactory(mock(BeanFactory.class));
@@ -81,25 +82,8 @@ public class MethodInvokingTransformerTests {
assertThat(result.getPayload()).isEqualTo("123!");
}
@Test(expected = MessageHandlingException.class)
public void typeConversionFailureConfiguredWithMethodReference() throws Exception {
TestBean testBean = new TestBean();
Method testMethod = testBean.getClass().getMethod("exclaim", String.class);
MethodInvokingTransformer transformer = new MethodInvokingTransformer(testBean, testMethod);
Message<?> message = new GenericMessage<TestBean>(new TestBean());
transformer.transform(message);
}
@Test(expected = MessageHandlingException.class)
public void typeConversionFailureConfiguredWithMethodName() {
TestBean testBean = new TestBean();
MethodInvokingTransformer transformer = new MethodInvokingTransformer(testBean, "exclaim");
Message<?> message = new GenericMessage<>(new TestBean());
transformer.transform(message);
}
@Test
public void headerAnnotationConfiguredWithMethodReference() throws Exception {
void headerAnnotationConfiguredWithMethodReference() throws Exception {
TestBean testBean = new TestBean();
Method testMethod = testBean.getClass().getMethod("headerTest", String.class, Integer.class);
MethodInvokingTransformer transformer = new MethodInvokingTransformer(testBean, testMethod);
@@ -111,7 +95,7 @@ public class MethodInvokingTransformerTests {
}
@Test
public void headerAnnotationConfiguredWithMethodName() {
void headerAnnotationConfiguredWithMethodName() {
TestBean testBean = new TestBean();
MethodInvokingTransformer transformer = new MethodInvokingTransformer(testBean, "headerTest");
transformer.setBeanFactory(mock(BeanFactory.class));
@@ -121,18 +105,19 @@ public class MethodInvokingTransformerTests {
assertThat(result.getPayload()).isEqualTo("foo123");
}
@Test(expected = MessageHandlingException.class)
public void headerValueNotProvided() throws Exception {
@Test
void headerValueNotProvided() throws Exception {
TestBean testBean = new TestBean();
Method testMethod = testBean.getClass().getMethod("headerTest", String.class, Integer.class);
MethodInvokingTransformer transformer = new MethodInvokingTransformer(testBean, testMethod);
Message<String> message = MessageBuilder.withPayload("foo")
.setHeader("wrong", 123).build();
transformer.transform(message);
assertThatExceptionOfType(MessageHandlingException.class)
.isThrownBy(() -> transformer.transform(message));
}
@Test
public void optionalHeaderAnnotation() throws Exception {
void optionalHeaderAnnotation() throws Exception {
TestBean testBean = new TestBean();
Method testMethod = testBean.getClass().getMethod("optionalHeaderTest", String.class, Integer.class);
MethodInvokingTransformer transformer = new MethodInvokingTransformer(testBean, testMethod);
@@ -143,7 +128,7 @@ public class MethodInvokingTransformerTests {
}
@Test
public void optionalHeaderValueNotProvided() throws Exception {
void optionalHeaderValueNotProvided() throws Exception {
TestBean testBean = new TestBean();
Method testMethod = testBean.getClass().getMethod("optionalHeaderTest", String.class, Integer.class);
MethodInvokingTransformer transformer = new MethodInvokingTransformer(testBean, testMethod);
@@ -154,7 +139,7 @@ public class MethodInvokingTransformerTests {
}
@Test
public void messageReturnValueConfiguredWithMethodReference() throws Exception {
void messageReturnValueConfiguredWithMethodReference() throws Exception {
TestBean testBean = new TestBean();
Method testMethod = testBean.getClass().getMethod("messageReturnValueTest", Message.class);
MethodInvokingTransformer transformer = new MethodInvokingTransformer(testBean, testMethod);
@@ -165,7 +150,7 @@ public class MethodInvokingTransformerTests {
}
@Test
public void messageReturnValueConfiguredWithMethodName() {
void messageReturnValueConfiguredWithMethodName() {
TestBean testBean = new TestBean();
MethodInvokingTransformer transformer = new MethodInvokingTransformer(testBean, "messageReturnValueTest");
transformer.setBeanFactory(mock(BeanFactory.class));
@@ -176,7 +161,7 @@ public class MethodInvokingTransformerTests {
@Test
@SuppressWarnings("unchecked")
public void propertiesPayloadConfiguredWithMethodReference() throws Exception {
void propertiesPayloadConfiguredWithMethodReference() throws Exception {
TestBean testBean = new TestBean();
Method testMethod = testBean.getClass().getMethod("propertyPayloadTest", Properties.class);
MethodInvokingTransformer transformer = new MethodInvokingTransformer(testBean, testMethod);
@@ -198,7 +183,7 @@ public class MethodInvokingTransformerTests {
@Test
@SuppressWarnings("unchecked")
public void propertiesPayloadConfiguredWithMethodName() {
void propertiesPayloadConfiguredWithMethodName() {
TestBean testBean = new TestBean();
MethodInvokingTransformer transformer = new MethodInvokingTransformer(testBean, "propertyPayloadTest");
transformer.setBeanFactory(mock(BeanFactory.class));
@@ -218,7 +203,7 @@ public class MethodInvokingTransformerTests {
}
@Test
public void nullReturningMethod() {
void nullReturningMethod() {
TestBean testBean = new TestBean();
MethodInvokingTransformer transformer = new MethodInvokingTransformer(testBean, "nullReturnValueTest");
transformer.setBeanFactory(mock(BeanFactory.class));
@@ -228,8 +213,9 @@ public class MethodInvokingTransformerTests {
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Test // this changed in 2.0 see INT-785 and INT-1130
public void headerEnricherConfiguredWithMethodReference() throws Exception {
@Test
// this changed in 2.0 see INT-785 and INT-1130
void headerEnricherConfiguredWithMethodReference() throws Exception {
TestBean testBean = new TestBean();
Method testMethod = testBean.getClass().getMethod("propertyEnricherTest", String.class);
HeaderEnricher transformer = new HeaderEnricher();
@@ -248,8 +234,9 @@ public class MethodInvokingTransformerTests {
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Test // this changed in 2.0 see INT-785 and INT-1130
public void headerEnricherConfiguredWithMethodName() {
@Test
// this changed in 2.0 see INT-785 and INT-1130
void headerEnricherConfiguredWithMethodName() {
TestBean testBean = new TestBean();
HeaderEnricher transformer = new HeaderEnricher();
MethodInvokingMessageProcessor processor =