Improve messaging gateway mapping
The `#args` and `#gatewayMethod` SpEL variables have been deprecated for a while * Remove their population and usage in favor of `MethodArgsHolder` `root` of the evaluation context This change optimize a gateway mapping logic the way that there is no need in evaluation context for every call: we can just reuse a global one * Some other `GatewayMethodInboundMessageMapper` code style refactoring * Fix effected test classes and their configs
This commit is contained in:
committed by
Gary Russell
parent
a9f511c170
commit
a30dc10447
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -38,7 +38,6 @@ import org.springframework.core.annotation.SynthesizingMethodParameter;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.integration.expression.ExpressionUtils;
|
||||
import org.springframework.integration.mapping.InboundMessageMapper;
|
||||
import org.springframework.integration.mapping.MessageMappingException;
|
||||
@@ -107,9 +106,7 @@ class GatewayMethodInboundMessageMapper implements InboundMessageMapper<Object[]
|
||||
|
||||
private Expression payloadExpression;
|
||||
|
||||
private EvaluationContext payloadExpressionEvaluationContext;
|
||||
|
||||
private BeanFactory beanFactory;
|
||||
private EvaluationContext evaluationContext;
|
||||
|
||||
@Nullable
|
||||
private Expression sendTimeoutExpression;
|
||||
@@ -148,18 +145,14 @@ class GatewayMethodInboundMessageMapper implements InboundMessageMapper<Object[]
|
||||
this.globalHeaderExpressions = globalHeaderExpressions;
|
||||
this.parameterList = getMethodParameterList(method);
|
||||
this.payloadExpression = parsePayloadExpression(method);
|
||||
if (messageBuilderFactory == null) {
|
||||
this.messageBuilderFactory = new DefaultMessageBuilderFactory();
|
||||
}
|
||||
else {
|
||||
this.messageBuilderFactory = messageBuilderFactory;
|
||||
}
|
||||
if (mapper == null) {
|
||||
this.argsMapper = new DefaultMethodArgsMessageMapper();
|
||||
}
|
||||
else {
|
||||
this.argsMapper = mapper;
|
||||
}
|
||||
this.messageBuilderFactory =
|
||||
messageBuilderFactory == null
|
||||
? new DefaultMessageBuilderFactory()
|
||||
: messageBuilderFactory;
|
||||
this.argsMapper =
|
||||
mapper == null
|
||||
? new DefaultMethodArgsMessageMapper()
|
||||
: mapper;
|
||||
}
|
||||
|
||||
|
||||
@@ -169,8 +162,7 @@ class GatewayMethodInboundMessageMapper implements InboundMessageMapper<Object[]
|
||||
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) {
|
||||
this.beanFactory = beanFactory;
|
||||
this.payloadExpressionEvaluationContext = ExpressionUtils.createStandardEvaluationContext(beanFactory);
|
||||
this.evaluationContext = ExpressionUtils.createStandardEvaluationContext(beanFactory);
|
||||
}
|
||||
|
||||
public void setSendTimeoutExpression(Expression sendTimeoutExpression) {
|
||||
@@ -197,38 +189,31 @@ class GatewayMethodInboundMessageMapper implements InboundMessageMapper<Object[]
|
||||
try {
|
||||
return this.argsMapper.toMessage(new MethodArgsHolder(this.method, arguments), headers);
|
||||
}
|
||||
catch (MessagingException e) { // NOSONAR to avoid if..else
|
||||
throw e;
|
||||
catch (MessagingException ex) { // NOSONAR to avoid if..else
|
||||
throw ex;
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new MessageMappingException("Failed to map arguments: " + Arrays.toString(arguments), e);
|
||||
catch (Exception ex) {
|
||||
throw new MessageMappingException("Failed to map arguments: " + Arrays.toString(arguments), ex);
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, Object> evaluateHeaders(EvaluationContext methodInvocationEvaluationContext,
|
||||
MethodArgsHolder methodArgsHolder, Map<String, Expression> headerExpressions) {
|
||||
private Map<String, Object> evaluateHeaders(MethodArgsHolder methodArgsHolder,
|
||||
Map<String, Expression> headerExpressions) {
|
||||
|
||||
Map<String, Object> evaluatedHeaders = new HashMap<>();
|
||||
for (Map.Entry<String, Expression> entry : headerExpressions.entrySet()) {
|
||||
Object value = entry.getValue().getValue(methodInvocationEvaluationContext, methodArgsHolder);
|
||||
Object value = entry.getValue()
|
||||
.getValue(GatewayMethodInboundMessageMapper.this.evaluationContext, methodArgsHolder);
|
||||
evaluatedHeaders.put(entry.getKey(), value);
|
||||
}
|
||||
return evaluatedHeaders;
|
||||
}
|
||||
|
||||
// TODO Remove in the future release. The MethodArgsHolder as a root object covers this use-case.
|
||||
private StandardEvaluationContext createMethodInvocationEvaluationContext(Object[] arguments) {
|
||||
StandardEvaluationContext context = ExpressionUtils.createStandardEvaluationContext(this.beanFactory);
|
||||
context.setVariable("args", arguments);
|
||||
context.setVariable("gatewayMethod", this.method);
|
||||
return context;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Object evaluatePayloadExpression(String expressionString, Object argumentValue) {
|
||||
Expression expression =
|
||||
this.parameterPayloadExpressions.computeIfAbsent(expressionString, PARSER::parseExpression);
|
||||
return expression.getValue(this.payloadExpressionEvaluationContext, argumentValue);
|
||||
return expression.getValue(this.evaluationContext, argumentValue);
|
||||
}
|
||||
|
||||
|
||||
@@ -287,15 +272,11 @@ class GatewayMethodInboundMessageMapper implements InboundMessageMapper<Object[]
|
||||
|
||||
public class DefaultMethodArgsMessageMapper implements MethodArgsMessageMapper {
|
||||
|
||||
private final MessageBuilderFactory msgBuilderFactory =
|
||||
GatewayMethodInboundMessageMapper.this.messageBuilderFactory;
|
||||
|
||||
@Override
|
||||
public Message<?> toMessage(MethodArgsHolder holder, @Nullable Map<String, Object> headersToMap) {
|
||||
Object messageOrPayload = null;
|
||||
boolean foundPayloadAnnotation = false;
|
||||
Object[] arguments = holder.getArgs();
|
||||
EvaluationContext methodInvocationEvaluationContext = createMethodInvocationEvaluationContext(arguments);
|
||||
Map<String, Object> headersToPopulate =
|
||||
headersToMap != null
|
||||
? new HashMap<>(headersToMap)
|
||||
@@ -303,7 +284,7 @@ class GatewayMethodInboundMessageMapper implements InboundMessageMapper<Object[]
|
||||
if (GatewayMethodInboundMessageMapper.this.payloadExpression != null) {
|
||||
messageOrPayload =
|
||||
GatewayMethodInboundMessageMapper.this.payloadExpression.getValue(
|
||||
methodInvocationEvaluationContext, holder);
|
||||
GatewayMethodInboundMessageMapper.this.evaluationContext, holder);
|
||||
}
|
||||
for (int i = 0; i < GatewayMethodInboundMessageMapper.this.parameterList.size(); i++) {
|
||||
Object argumentValue = arguments[i];
|
||||
@@ -337,8 +318,8 @@ class GatewayMethodInboundMessageMapper implements InboundMessageMapper<Object[]
|
||||
() -> "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);
|
||||
populateSendAndReplyTimeoutHeaders(holder, headersToPopulate);
|
||||
return buildMessage(holder, headersToPopulate, messageOrPayload);
|
||||
}
|
||||
|
||||
private void headerOrHeaders(Map<String, Object> headersToPopulate, Object argumentValue,
|
||||
@@ -406,45 +387,46 @@ class GatewayMethodInboundMessageMapper implements InboundMessageMapper<Object[]
|
||||
copyHeaders(argumentValue, headersToPopulate);
|
||||
}
|
||||
|
||||
private void populateSendAndReplyTimeoutHeaders(EvaluationContext methodInvocationEvaluationContext,
|
||||
MethodArgsHolder methodArgsHolder, Map<String, Object> headersToPopulate) {
|
||||
private void populateSendAndReplyTimeoutHeaders(MethodArgsHolder methodArgsHolder,
|
||||
Map<String, Object> headersToPopulate) {
|
||||
|
||||
if (GatewayMethodInboundMessageMapper.this.sendTimeoutExpression != null) {
|
||||
headersToPopulate.computeIfAbsent(GenericMessagingTemplate.DEFAULT_SEND_TIMEOUT_HEADER,
|
||||
v -> GatewayMethodInboundMessageMapper.this.sendTimeoutExpression
|
||||
.getValue(methodInvocationEvaluationContext, methodArgsHolder, Long.class));
|
||||
.getValue(GatewayMethodInboundMessageMapper.this.evaluationContext,
|
||||
methodArgsHolder, Long.class));
|
||||
}
|
||||
if (GatewayMethodInboundMessageMapper.this.replyTimeoutExpression != null) {
|
||||
headersToPopulate.computeIfAbsent(GenericMessagingTemplate.DEFAULT_RECEIVE_TIMEOUT_HEADER,
|
||||
v -> GatewayMethodInboundMessageMapper.this.replyTimeoutExpression
|
||||
.getValue(methodInvocationEvaluationContext, methodArgsHolder, Long.class));
|
||||
.getValue(GatewayMethodInboundMessageMapper.this.evaluationContext,
|
||||
methodArgsHolder, Long.class));
|
||||
}
|
||||
}
|
||||
|
||||
private Message<?> buildMessage(MethodArgsHolder methodArgsHolder, Map<String, Object> headers,
|
||||
Object messageOrPayload, EvaluationContext methodInvocationEvaluationContext) {
|
||||
Object messageOrPayload) {
|
||||
|
||||
MessageBuilderFactory msgBuilderFactory = GatewayMethodInboundMessageMapper.this.messageBuilderFactory;
|
||||
AbstractIntegrationMessageBuilder<?> builder =
|
||||
(messageOrPayload instanceof Message)
|
||||
? this.msgBuilderFactory.fromMessage((Message<?>) messageOrPayload)
|
||||
: this.msgBuilderFactory.withPayload(messageOrPayload);
|
||||
(messageOrPayload instanceof Message<?> msg)
|
||||
? msgBuilderFactory.fromMessage(msg)
|
||||
: msgBuilderFactory.withPayload(messageOrPayload);
|
||||
builder.copyHeadersIfAbsent(headers);
|
||||
// Explicit headers in XML override any @Header annotations...
|
||||
if (!CollectionUtils.isEmpty(GatewayMethodInboundMessageMapper.this.headerExpressions)) {
|
||||
Map<String, Object> evaluatedHeaders = evaluateHeaders(methodInvocationEvaluationContext,
|
||||
methodArgsHolder, GatewayMethodInboundMessageMapper.this.headerExpressions);
|
||||
Map<String, Object> evaluatedHeaders =
|
||||
evaluateHeaders(methodArgsHolder, GatewayMethodInboundMessageMapper.this.headerExpressions);
|
||||
builder.copyHeaders(evaluatedHeaders);
|
||||
}
|
||||
// ...whereas global (default) headers do not...
|
||||
if (!CollectionUtils.isEmpty(GatewayMethodInboundMessageMapper.this.globalHeaderExpressions)) {
|
||||
Map<String, Object> evaluatedHeaders = evaluateHeaders(methodInvocationEvaluationContext,
|
||||
methodArgsHolder, GatewayMethodInboundMessageMapper.this.globalHeaderExpressions);
|
||||
Map<String, Object> evaluatedHeaders =
|
||||
evaluateHeaders(methodArgsHolder,
|
||||
GatewayMethodInboundMessageMapper.this.globalHeaderExpressions);
|
||||
builder.copyHeadersIfAbsent(evaluatedHeaders);
|
||||
}
|
||||
if (GatewayMethodInboundMessageMapper.this.headers != null) {
|
||||
builder.copyHeadersIfAbsent(GatewayMethodInboundMessageMapper.this.headers);
|
||||
}
|
||||
return builder.build();
|
||||
return builder.copyHeadersIfAbsent(GatewayMethodInboundMessageMapper.this.headers).build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015-2020 the original author or authors.
|
||||
* Copyright 2015-2022 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.
|
||||
|
||||
@@ -1467,7 +1467,7 @@ public class EnableIntegrationTests {
|
||||
@TestMessagingGateway
|
||||
public interface TestGateway {
|
||||
|
||||
@Gateway(headers = @GatewayHeader(name = "calledMethod", expression = "#gatewayMethod.name"))
|
||||
@Gateway(headers = @GatewayHeader(name = "calledMethod", expression = "method.name"))
|
||||
String echo(String payload);
|
||||
|
||||
@Gateway(requestChannel = "sendAsyncChannel")
|
||||
@@ -1482,7 +1482,7 @@ public class EnableIntegrationTests {
|
||||
@TestMessagingGateway2
|
||||
public interface TestGateway2 {
|
||||
|
||||
@Gateway(headers = @GatewayHeader(name = "calledMethod", expression = "#gatewayMethod.name"))
|
||||
@Gateway(headers = @GatewayHeader(name = "calledMethod", expression = "method.name"))
|
||||
String echo2(String payload);
|
||||
|
||||
}
|
||||
|
||||
@@ -393,10 +393,10 @@ public class AsyncGatewayTests {
|
||||
|
||||
CompletableFuture<Message<?>> returnMessageListenable(String s);
|
||||
|
||||
@Gateway(headers = @GatewayHeader(name = "method", expression = "#gatewayMethod.name"))
|
||||
@Gateway(headers = @GatewayHeader(name = "method", expression = "method.name"))
|
||||
CustomFuture returnCustomFuture(String s);
|
||||
|
||||
@Gateway(headers = @GatewayHeader(name = "method", expression = "#gatewayMethod.name"))
|
||||
@Gateway(headers = @GatewayHeader(name = "method", expression = "method.name"))
|
||||
Future<?> returnCustomFutureWithTypeFuture(String s);
|
||||
|
||||
Mono<String> returnStringPromise(String s);
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
service-interface="org.springframework.integration.gateway.GatewayInterfaceTests$Bar"
|
||||
default-request-channel="requestChannelBaz"
|
||||
error-channel="errorChannel">
|
||||
<int:default-header name="name" expression="#gatewayMethod.name"/>
|
||||
<int:default-header name="string" expression="#gatewayMethod.toString()"/>
|
||||
<int:default-header name="object" expression="#gatewayMethod"/>
|
||||
<int:default-header name="name" expression="method.name"/>
|
||||
<int:default-header name="string" expression="method.toString()"/>
|
||||
<int:default-header name="object" expression="method"/>
|
||||
<int:method name="baz">
|
||||
<int:header name="name" value="overrideGlobal"/>
|
||||
</int:method>
|
||||
|
||||
@@ -522,8 +522,8 @@ public class GatewayInterfaceTests {
|
||||
|
||||
void baz(String payload);
|
||||
|
||||
@Gateway(payloadExpression = "#args[0]", requestChannel = "lateReplyChannel",
|
||||
requestTimeoutExpression = "#args[1]", replyTimeoutExpression = "#args[2]")
|
||||
@Gateway(payloadExpression = "args[0]", requestChannel = "lateReplyChannel",
|
||||
requestTimeoutExpression = "args[1]", replyTimeoutExpression = "args[2]")
|
||||
String lateReply(String payload, long requestTimeout, long replyTimeout);
|
||||
|
||||
}
|
||||
@@ -651,7 +651,7 @@ public class GatewayInterfaceTests {
|
||||
@Profile("gatewayTest")
|
||||
public interface Int2634Gateway {
|
||||
|
||||
@Gateway(requestChannel = "gatewayChannel", payloadExpression = "#args[0]")
|
||||
@Gateway(requestChannel = "gatewayChannel", payloadExpression = "args[0]")
|
||||
Object test1(Map<Object, ?> map);
|
||||
|
||||
@Gateway(requestChannel = "gatewayChannel")
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
<int:gateway id="sampleGateway"
|
||||
service-interface="org.springframework.integration.gateway.GatewayInterfaceTests.Bar"
|
||||
default-request-channel="requestChannelBaz" default-payload-expression="'foo'">
|
||||
<int:default-header name="name" expression="#gatewayMethod.name"/>
|
||||
<int:default-header name="string" expression="#gatewayMethod.toString()"/>
|
||||
<int:default-header name="object" expression="#gatewayMethod"/>
|
||||
<int:default-header name="name" expression="method.name"/>
|
||||
<int:default-header name="string" expression="method.toString()"/>
|
||||
<int:default-header name="object" expression="method"/>
|
||||
<int:method name="baz">
|
||||
<int:header name="name" value="overrideGlobal"/>
|
||||
</int:method>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -17,13 +17,15 @@
|
||||
package org.springframework.integration.gateway;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.expression.Expression;
|
||||
@@ -40,6 +42,7 @@ import org.springframework.messaging.handler.annotation.Payload;
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
* @author Gary Russell
|
||||
* @author Artem Bilan
|
||||
*/
|
||||
public class GatewayMethodInboundMessageMapperToMessageTests {
|
||||
|
||||
@@ -52,20 +55,22 @@ public class GatewayMethodInboundMessageMapperToMessageTests {
|
||||
assertThat(message.getPayload()).isEqualTo("test");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
@Test
|
||||
public void toMessageWithTooManyParameters() throws Exception {
|
||||
Method method = TestService.class.getMethod("sendPayload", String.class);
|
||||
GatewayMethodInboundMessageMapper mapper = new GatewayMethodInboundMessageMapper(method);
|
||||
mapper.setBeanFactory(mock(BeanFactory.class));
|
||||
mapper.toMessage(new Object[] { "test", "oops" });
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> mapper.toMessage(new Object[] { "test", "oops" }));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
@Test
|
||||
public void toMessageWithEmptyParameterArray() throws Exception {
|
||||
Method method = TestService.class.getMethod("sendPayload", String.class);
|
||||
GatewayMethodInboundMessageMapper mapper = new GatewayMethodInboundMessageMapper(method);
|
||||
mapper.setBeanFactory(mock(BeanFactory.class));
|
||||
mapper.toMessage(new Object[] {});
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> mapper.toMessage(new Object[] {}));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -79,13 +84,14 @@ public class GatewayMethodInboundMessageMapperToMessageTests {
|
||||
assertThat(message.getHeaders().get("foo")).isEqualTo("bar");
|
||||
}
|
||||
|
||||
@Test(expected = MessageMappingException.class)
|
||||
@Test
|
||||
public void toMessageWithPayloadAndRequiredHeaderButNullValue() throws Exception {
|
||||
Method method = TestService.class.getMethod(
|
||||
"sendPayloadAndHeader", String.class, String.class);
|
||||
GatewayMethodInboundMessageMapper mapper = new GatewayMethodInboundMessageMapper(method);
|
||||
mapper.setBeanFactory(mock(BeanFactory.class));
|
||||
mapper.toMessage(new Object[] { "test", null });
|
||||
assertThatExceptionOfType(MessageMappingException.class)
|
||||
.isThrownBy(() -> mapper.toMessage(new Object[] { "test", null }));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -116,7 +122,7 @@ public class GatewayMethodInboundMessageMapperToMessageTests {
|
||||
"sendPayloadAndHeadersMap", String.class, Map.class);
|
||||
GatewayMethodInboundMessageMapper mapper = new GatewayMethodInboundMessageMapper(method);
|
||||
mapper.setBeanFactory(mock(BeanFactory.class));
|
||||
Map<String, Object> headers = new HashMap<String, Object>();
|
||||
Map<String, Object> headers = new HashMap<>();
|
||||
headers.put("abc", 123);
|
||||
headers.put("def", 456);
|
||||
Message<?> message = mapper.toMessage(new Object[] { "test", headers });
|
||||
@@ -135,15 +141,16 @@ public class GatewayMethodInboundMessageMapperToMessageTests {
|
||||
assertThat(message.getPayload()).isEqualTo("test");
|
||||
}
|
||||
|
||||
@Test(expected = MessageMappingException.class)
|
||||
@Test
|
||||
public void toMessageWithPayloadAndHeadersMapWithNonStringKey() throws Exception {
|
||||
Method method = TestService.class.getMethod(
|
||||
"sendPayloadAndHeadersMap", String.class, Map.class);
|
||||
GatewayMethodInboundMessageMapper mapper = new GatewayMethodInboundMessageMapper(method);
|
||||
mapper.setBeanFactory(mock(BeanFactory.class));
|
||||
Map<Integer, String> headers = new HashMap<Integer, String>();
|
||||
Map<Integer, String> headers = new HashMap<>();
|
||||
headers.put(123, "abc");
|
||||
mapper.toMessage(new Object[] { "test", headers });
|
||||
assertThatExceptionOfType(MessageMappingException.class)
|
||||
.isThrownBy(() -> mapper.toMessage(new Object[] { "test", headers }));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -167,13 +174,14 @@ public class GatewayMethodInboundMessageMapperToMessageTests {
|
||||
assertThat(message.getHeaders().get("foo")).isEqualTo("bar");
|
||||
}
|
||||
|
||||
@Test(expected = MessageMappingException.class)
|
||||
@Test
|
||||
public void toMessageWithMessageParameterAndRequiredHeaderButNullValue() throws Exception {
|
||||
Method method = TestService.class.getMethod("sendMessageAndHeader", Message.class, String.class);
|
||||
GatewayMethodInboundMessageMapper mapper = new GatewayMethodInboundMessageMapper(method);
|
||||
mapper.setBeanFactory(mock(BeanFactory.class));
|
||||
Message<?> inputMessage = MessageBuilder.withPayload("test message").build();
|
||||
mapper.toMessage(new Object[] { inputMessage, null });
|
||||
assertThatExceptionOfType(MessageMappingException.class)
|
||||
.isThrownBy(() -> mapper.toMessage(new Object[] { inputMessage, null }));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -198,26 +206,28 @@ public class GatewayMethodInboundMessageMapperToMessageTests {
|
||||
assertThat(message.getHeaders().get("foo")).isNull();
|
||||
}
|
||||
|
||||
@Test(expected = MessageMappingException.class)
|
||||
@Test
|
||||
public void noArgs() throws Exception {
|
||||
Method method = TestService.class.getMethod("noArgs", new Class<?>[] {});
|
||||
Method method = TestService.class.getMethod("noArgs");
|
||||
GatewayMethodInboundMessageMapper mapper = new GatewayMethodInboundMessageMapper(method);
|
||||
mapper.setBeanFactory(mock(BeanFactory.class));
|
||||
mapper.toMessage(new Object[] {});
|
||||
assertThatExceptionOfType(MessageMappingException.class)
|
||||
.isThrownBy(() -> mapper.toMessage(new Object[] {}));
|
||||
}
|
||||
|
||||
@Test(expected = MessageMappingException.class)
|
||||
@Test
|
||||
public void onlyHeaders() throws Exception {
|
||||
Method method = TestService.class.getMethod("onlyHeaders", String.class, String.class);
|
||||
GatewayMethodInboundMessageMapper mapper = new GatewayMethodInboundMessageMapper(method);
|
||||
mapper.setBeanFactory(mock(BeanFactory.class));
|
||||
mapper.toMessage(new Object[] { "abc", "def" });
|
||||
assertThatExceptionOfType(MessageMappingException.class)
|
||||
.isThrownBy(() -> mapper.toMessage(new Object[] { "abc", "def" }));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toMessageWithPayloadAndHeaders() throws Exception {
|
||||
Method method = TestService.class.getMethod("sendPayload", String.class);
|
||||
Map<String, Expression> headers = new HashMap<String, Expression>();
|
||||
Map<String, Expression> headers = new HashMap<>();
|
||||
headers.put("foo", new LiteralExpression("foo"));
|
||||
headers.put("bar", new SpelExpressionParser().parseExpression("6 * 7"));
|
||||
headers.put("baz", new LiteralExpression("hello"));
|
||||
@@ -232,7 +242,7 @@ public class GatewayMethodInboundMessageMapperToMessageTests {
|
||||
@Test
|
||||
public void toMessageWithNonHeaderMapPayloadExpressionA() throws Exception {
|
||||
Method method = TestService.class.getMethod("sendNonHeadersMap", Map.class);
|
||||
Map<Integer, Object> map = new HashMap<Integer, Object>();
|
||||
Map<Integer, Object> map = new HashMap<>();
|
||||
map.put(1, "One");
|
||||
map.put(2, "Two");
|
||||
GatewayMethodInboundMessageMapper mapper = new GatewayMethodInboundMessageMapper(method);
|
||||
@@ -258,7 +268,7 @@ public class GatewayMethodInboundMessageMapperToMessageTests {
|
||||
@Test
|
||||
public void toMessageWithNonHeaderMapPayloadAnnotation() throws Exception {
|
||||
Method method = TestService.class.getMethod("sendNonHeadersMapWithPayloadAnnotation", Map.class);
|
||||
Map<Integer, Object> map = new HashMap<Integer, Object>();
|
||||
Map<Integer, Object> map = new HashMap<>();
|
||||
map.put(1, "One");
|
||||
map.put(2, "Two");
|
||||
GatewayMethodInboundMessageMapper mapper = new GatewayMethodInboundMessageMapper(method);
|
||||
@@ -270,10 +280,10 @@ public class GatewayMethodInboundMessageMapperToMessageTests {
|
||||
@Test
|
||||
public void toMessageWithTwoMapsOneNonHeaderPayloadExpression() throws Exception {
|
||||
Method method = TestService.class.getMethod("sendNonHeadersMapFirstArgument", Map.class, Map.class);
|
||||
Map<Integer, Object> mapA = new HashMap<Integer, Object>();
|
||||
Map<Integer, Object> mapA = new HashMap<>();
|
||||
mapA.put(1, "One");
|
||||
mapA.put(2, "Two");
|
||||
Map<String, Object> mapB = new HashMap<String, Object>();
|
||||
Map<String, Object> mapB = new HashMap<>();
|
||||
mapB.put("1", "ONE");
|
||||
mapB.put("2", "TWO");
|
||||
GatewayMethodInboundMessageMapper mapper = new GatewayMethodInboundMessageMapper(method);
|
||||
@@ -310,7 +320,7 @@ public class GatewayMethodInboundMessageMapperToMessageTests {
|
||||
|
||||
void sendNonHeadersMap(Map<Integer, Object> map);
|
||||
|
||||
@Payload("#args[0]")
|
||||
@Payload("args[0]")
|
||||
void sendNonHeadersMapWithPayloadAnnotation(Map<Integer, Object> map);
|
||||
|
||||
void sendNonHeadersMapFirstArgument(Map<Integer, Object> mapA, Map<String, Object> mapB);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -226,10 +226,10 @@ public class GatewayProxyMessageMappingTests {
|
||||
|
||||
void twoMapsAndOneAnnotatedWithPayload(@Payload Map<String, Object> payload, Map<String, Object> headers);
|
||||
|
||||
@Payload("#args[0] + #args[1] + '!'")
|
||||
@Payload("args[0] + args[1] + '!'")
|
||||
void payloadAnnotationAtMethodLevel(String a, String b);
|
||||
|
||||
@Payload("@testBean.exclaim(#args[0])")
|
||||
@Payload("@testBean.exclaim(args[0])")
|
||||
void payloadAnnotationAtMethodLevelUsingBeanResolver(String s);
|
||||
|
||||
void payloadAnnotationWithExpression(@Payload("toUpperCase()") String s);
|
||||
|
||||
@@ -8,13 +8,13 @@
|
||||
https://www.springframework.org/schema/integration/spring-integration.xsd">
|
||||
|
||||
<int:gateway id="gateway" service-interface="org.springframework.integration.gateway.GatewayWithPayloadExpressionTests$SampleGateway">
|
||||
<int:method name="send1" request-channel="input" payload-expression="#args[0] + 'bar'"/>
|
||||
<int:method name="send2" request-channel="input" payload-expression="@testBean.sum(#args[0])"/>
|
||||
<int:method name="send3" request-channel="input" payload-expression="#gatewayMethod.name"/>
|
||||
<int:method name="send1" request-channel="input" payload-expression="args[0] + 'bar'"/>
|
||||
<int:method name="send2" request-channel="input" payload-expression="@testBean.sum(args[0])"/>
|
||||
<int:method name="send3" request-channel="input" payload-expression="method.name"/>
|
||||
</int:gateway>
|
||||
|
||||
<int:gateway id="annotatedGateway"
|
||||
service-interface="org.springframework.integration.gateway.GatewayWithPayloadExpressionTests.SampleAnnotatedGateway"
|
||||
service-interface="org.springframework.integration.gateway.GatewayWithPayloadExpressionTests$SampleAnnotatedGateway"
|
||||
default-request-channel="input"/>
|
||||
|
||||
<int:channel id="input">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -18,15 +18,13 @@ package org.springframework.integration.gateway;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.PollableChannel;
|
||||
import org.springframework.messaging.handler.annotation.Payload;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
@@ -35,8 +33,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration
|
||||
@SpringJUnitConfig
|
||||
public class GatewayWithPayloadExpressionTests {
|
||||
|
||||
@Autowired
|
||||
@@ -91,7 +88,7 @@ public class GatewayWithPayloadExpressionTests {
|
||||
|
||||
public interface SampleAnnotatedGateway {
|
||||
|
||||
@Payload("#args[0] + #args[1]")
|
||||
@Payload("args[0] + args[1]")
|
||||
void send(String value1, String value2);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -38,7 +38,7 @@ public interface TestService {
|
||||
|
||||
void oneWay(String input);
|
||||
|
||||
@Payload("#args[0]")
|
||||
@Payload("args[0]")
|
||||
void oneWayWithTimeouts(String input, Long sendTimeout, Long receiveTimeout);
|
||||
|
||||
String solicitResponse();
|
||||
@@ -51,7 +51,7 @@ public interface TestService {
|
||||
|
||||
Message<?> requestReplyWithMessageReturnValue(String input);
|
||||
|
||||
@Payload("#gatewayMethod.name + #args.length")
|
||||
@Payload("method.name + args.length")
|
||||
String requestReplyWithPayloadAnnotation();
|
||||
|
||||
Future<Message<?>> async(String s);
|
||||
|
||||
@@ -163,13 +163,7 @@ NOTE: If a no-argument gateway is specified in XML, and the interface method has
|
||||
The `<header/>` element supports `expression` as an alternative to `value`.
|
||||
The SpEL expression is evaluated to determine the value of the header.
|
||||
Starting with version 5.2, the `#root` object of the evaluation context is a `MethodArgsHolder` with `getMethod()` and `getArgs()` accessors.
|
||||
|
||||
These two expression evaluation context variables are deprecated since version 5.2:
|
||||
|
||||
* #args: An `Object[]` containing the method arguments
|
||||
* #gatewayMethod: The object (derived from `java.reflect.Method`) that represents the method in the `service-interface` that was invoked.
|
||||
A header containing this variable can be used later in the flow (for example, for routing).
|
||||
For example, if you wish to route on the simple method name, you might add a header with the following expression: `#gatewayMethod.name`.
|
||||
For example, if you wish to route on the simple method name, you might add a header with the following expression: `method.name`.
|
||||
|
||||
NOTE: The `java.reflect.Method` is not serializable.
|
||||
A header with an expression of `method` is lost if you later serialize the message.
|
||||
|
||||
Reference in New Issue
Block a user