diff --git a/spring-integration-core/src/main/java/org/springframework/integration/gateway/GatewayMethodInboundMessageMapper.java b/spring-integration-core/src/main/java/org/springframework/integration/gateway/GatewayMethodInboundMessageMapper.java index 83ed90a9a3..7d1b864fa9 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/gateway/GatewayMethodInboundMessageMapper.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/gateway/GatewayMethodInboundMessageMapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2021 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. @@ -197,7 +197,7 @@ class GatewayMethodInboundMessageMapper implements InboundMessageMapper "unable to determine a Message or payload parameter on method [" - + GatewayMethodInboundMessageMapper.this.method + "]"); + () -> "The 'payload' (or 'Message') for gateway [" + GatewayMethodInboundMessageMapper.this.method + + "] method call cannot be determined (must not be 'null') from the provided arguments: " + + Arrays.toString(arguments)); populateSendAndReplyTimeoutHeaders(methodInvocationEvaluationContext, holder, headersToPopulate); return buildMessage(holder, headersToPopulate, messageOrPayload, methodInvocationEvaluationContext); } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/support/MessagingMethodInvokerHelper.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/support/MessagingMethodInvokerHelper.java index abf1fb398e..6615f9b5fb 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/support/MessagingMethodInvokerHelper.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/support/MessagingMethodInvokerHelper.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2021 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. @@ -37,7 +37,6 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; import java.util.function.Function; -import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.aop.framework.Advised; @@ -58,6 +57,7 @@ import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.convert.ConversionFailedException; import org.springframework.core.convert.ConverterNotFoundException; import org.springframework.core.convert.TypeDescriptor; +import org.springframework.core.log.LogAccessor; import org.springframework.expression.EvaluationException; import org.springframework.expression.Expression; import org.springframework.expression.ExpressionParser; @@ -127,7 +127,7 @@ public class MessagingMethodInvokerHelper extends AbstractExpressionEvaluator im private static final String CANDIDATE_MESSAGE_METHODS = "CANDIDATE_MESSAGE_METHODS"; - private static final Log LOGGER = LogFactory.getLog(MessagingMethodInvokerHelper.class); + private static final LogAccessor LOGGER = new LogAccessor(LogFactory.getLog(MessagingMethodInvokerHelper.class)); // Number of times to try an InvocableHandlerMethod before giving up in favor of an expression. private static final int FAILED_ATTEMPTS_THRESHOLD = 100; @@ -186,20 +186,20 @@ public class MessagingMethodInvokerHelper extends AbstractExpressionEvaluator im private final HandlerMethod handlerMethod; + private final String displayString; + + private final boolean requiresReply; + private HandlerMethod defaultHandlerMethod; private BeanExpressionResolver resolver = new StandardBeanExpressionResolver(); private BeanExpressionContext expressionContext; - private volatile String displayString; - - private volatile boolean requiresReply; + private boolean useSpelInvoker; private volatile boolean initialized; - private boolean useSpelInvoker; - public MessagingMethodInvokerHelper(Object targetObject, Method method, Class expectedType, boolean canProcessMessageList) { @@ -257,7 +257,7 @@ public class MessagingMethodInvokerHelper extends AbstractExpressionEvaluator im this.handlerMessageMethods = null; this.handlerMethodsList.add( Collections.singletonMap(this.handlerMethod.targetParameterType, this.handlerMethod)); - setDisplayString(targetObject, method); + this.displayString = buildDisplayString(targetObject, method); this.jsonObjectMapper = configureJsonObjectMapperIfAny(); } @@ -314,7 +314,7 @@ public class MessagingMethodInvokerHelper extends AbstractExpressionEvaluator im this.handlerMethodsList.add(this.handlerMethods); this.handlerMethodsList.add(this.handlerMessageMethods); - setDisplayString(targetObject, methodName); + this.displayString = buildDisplayString(targetObject, methodName); this.jsonObjectMapper = configureJsonObjectMapperIfAny(); } @@ -401,17 +401,17 @@ public class MessagingMethodInvokerHelper extends AbstractExpressionEvaluator im return this.messageHandlerMethodFactory.createInvocableHandlerMethod(this.targetObject, method); } - private void setDisplayString(Object targetObject, Object targetMethod) { - StringBuilder sb = new StringBuilder(targetObject.getClass().getName()); + private String buildDisplayString(Object targetObject, Object targetMethod) { + StringBuilder sb = + new StringBuilder(targetObject.getClass().getName()) + .append('.'); if (targetMethod instanceof Method) { - sb.append(".") - .append(((Method) targetMethod).getName()); + sb.append(((Method) targetMethod).getName()); } else if (targetMethod instanceof String) { - sb.append(".") - .append(targetMethod); + sb.append(targetMethod); } - this.displayString = sb.toString() + "]"; + return sb.append(']').toString(); } private void prepareEvaluationContext() { @@ -620,12 +620,10 @@ public class MessagingMethodInvokerHelper extends AbstractExpressionEvaluator im if (++handlerMethod.failedAttempts >= FAILED_ATTEMPTS_THRESHOLD) { handlerMethod.spelOnly = true; - if (LOGGER.isInfoEnabled()) { - LOGGER.info("Failed to invoke [ " + handlerMethod.invocableHandlerMethod + - "] with provided arguments [ " + parameters + " ]. \n" + - "Falling back to SpEL invocation for expression [ " + - expression.getExpressionString() + " ]"); - } + LOGGER.info(() -> "Failed to invoke [ " + handlerMethod.invocableHandlerMethod + + "] with provided arguments [ " + parameters + " ]. \n" + + "Falling back to SpEL invocation for expression [ " + + expression.getExpressionString() + " ]"); } return invokeExpression(expression, parameters); @@ -692,8 +690,8 @@ public class MessagingMethodInvokerHelper extends AbstractExpressionEvaluator im parameters.payload = targetPayload; } } - catch (Exception e) { - LOGGER.debug("Failed to convert from JSON", e); + catch (Exception ex) { + LOGGER.debug(ex, "Failed to convert from JSON"); } } @@ -790,7 +788,7 @@ public class MessagingMethodInvokerHelper extends AbstractExpressionEvaluator im if (candidateMethods.isEmpty() && candidateMessageMethods.isEmpty() && fallbackMethods.isEmpty() && fallbackMessageMethods.isEmpty()) { - findSingleSpecifMethodOnInterfacesIfProxy(candidateMessageMethods, candidateMethods); + findSingleSpecificMethodOnInterfacesIfProxy(candidateMessageMethods, candidateMethods); } } @@ -802,10 +800,8 @@ public class MessagingMethodInvokerHelper extends AbstractExpressionEvaluator im handlerMethodToUse = createHandlerMethod( AopUtils.selectInvocableMethod(methodToProcess, ClassUtils.getUserClass(this.targetObject))); } - catch (Exception e) { - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("Method [" + methodToProcess + "] is not eligible for Message handling.", e); - } + catch (Exception ex) { + LOGGER.debug(ex, "Method [" + methodToProcess + "] is not eligible for Message handling."); return null; } @@ -909,7 +905,7 @@ public class MessagingMethodInvokerHelper extends AbstractExpressionEvaluator im return null; } - private void findSingleSpecifMethodOnInterfacesIfProxy(Map, HandlerMethod> candidateMessageMethods, + private void findSingleSpecificMethodOnInterfacesIfProxy(Map, HandlerMethod> candidateMessageMethods, Map, HandlerMethod> candidateMethods) { if (AopUtils.isAopProxy(this.targetObject)) { final AtomicReference targetMethod = new AtomicReference<>(); @@ -1153,7 +1149,7 @@ public class MessagingMethodInvokerHelper extends AbstractExpressionEvaluator im methodParameter, parameterTypeDescriptor, parameterType, genericParameterType, mappingAnnotation); } - sb.append(")"); + sb.append(')'); if (this.targetParameterTypeDescriptor == null) { this.targetParameterTypeDescriptor = TypeDescriptor.valueOf(Void.class); } @@ -1332,7 +1328,8 @@ public class MessagingMethodInvokerHelper extends AbstractExpressionEvaluator im if (this.targetParameterTypeDescriptor != null) { throw new IneligibleMethodException("Found more than one parameter type candidate: [" + - this.targetParameterTypeDescriptor + "] and [" + targetParameterType + "]"); + this.targetParameterTypeDescriptor + "] and [" + targetParameterType + "].\n" + + "Consider annotating one of the parameters with '@Payload'."); } this.targetParameterTypeDescriptor = targetParameterType; if (Message.class.isAssignableFrom(targetParameterType.getObjectType())) { diff --git a/spring-integration-core/src/test/java/org/springframework/integration/endpoint/PseudoTransactionalMessageSourceTests.java b/spring-integration-core/src/test/java/org/springframework/integration/endpoint/PseudoTransactionalMessageSourceTests.java index 4ad2f6005b..0f5c0beadf 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/endpoint/PseudoTransactionalMessageSourceTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/endpoint/PseudoTransactionalMessageSourceTests.java @@ -17,29 +17,23 @@ package org.springframework.integration.endpoint; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.fail; +import static org.assertj.core.api.Assertions.assertThatNoException; import static org.mockito.Mockito.mock; import java.lang.reflect.Method; import java.util.concurrent.atomic.AtomicInteger; -import org.apache.commons.logging.Log; import org.junit.jupiter.api.Test; -import org.mockito.Mockito; -import org.springframework.beans.DirectFieldAccessor; import org.springframework.beans.factory.BeanFactory; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.core.log.LogAccessor; import org.springframework.expression.spel.standard.SpelExpressionParser; -import org.springframework.integration.channel.NullChannel; import org.springframework.integration.channel.QueueChannel; import org.springframework.integration.config.EnableIntegration; import org.springframework.integration.core.MessageSource; -import org.springframework.integration.test.util.TestUtils; import org.springframework.integration.transaction.DefaultTransactionSynchronizationFactory; import org.springframework.integration.transaction.ExpressionEvaluatingTransactionSynchronizationProcessor; import org.springframework.integration.transaction.IntegrationResourceHolder; @@ -96,19 +90,8 @@ public class PseudoTransactionalMessageSourceTests { } }); - MessageChannel afterCommitChannel = new NullChannel(); + QueueChannel afterCommitChannel = new QueueChannel(); syncProcessor.setAfterCommitChannel(afterCommitChannel); - LogAccessor logAccessor = TestUtils.getPropertyValue(afterCommitChannel, "LOG", LogAccessor.class); - - Log logger = logAccessor.getLog(); - - logger = Mockito.spy(logger); - - Mockito.when(logger.isDebugEnabled()).thenReturn(true); - - DirectFieldAccessor dfa = new DirectFieldAccessor(logAccessor); - dfa.setPropertyValue("log", logger); - TransactionSynchronizationManager.initSynchronization(); TransactionSynchronizationManager.setActualTransactionActive(true); doPoll(adapter); @@ -118,7 +101,10 @@ public class PseudoTransactionalMessageSourceTests { assertThat(beforeCommitMessage).isNotNull(); assertThat(beforeCommitMessage.getPayload()).isEqualTo("qox"); - Mockito.verify(logger).debug(Mockito.any(CharSequence.class)); + assertThat(afterCommitChannel.receive(1000)) + .isNotNull() + .extracting(Message::getPayload) + .isEqualTo("qux"); TransactionSynchronizationUtils.triggerAfterCompletion(TransactionSynchronization.STATUS_COMMITTED); TransactionSynchronizationManager.clearSynchronization(); @@ -393,14 +379,12 @@ public class PseudoTransactionalMessageSourceTests { } protected void doPoll(SourcePollingChannelAdapter adapter) { - try { - Method method = AbstractPollingEndpoint.class.getDeclaredMethod("doPoll"); - method.setAccessible(true); - method.invoke(adapter); - } - catch (Exception e) { - fail("Failed to invoke doPoll(): " + e.toString()); - } + assertThatNoException() + .isThrownBy(() -> { + Method method = AbstractPollingEndpoint.class.getDeclaredMethod("doPoll"); + method.setAccessible(true); + method.invoke(adapter); + }); } public class Bar {