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:
committed by
Gary Russell
parent
0b3e2c98c3
commit
d53433cad7
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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".
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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 =
|
||||
|
||||
Reference in New Issue
Block a user