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:
Artem Bilan
2022-10-06 14:26:38 -04:00
committed by Gary Russell
parent a9f511c170
commit a30dc10447
13 changed files with 105 additions and 122 deletions

View File

@@ -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.

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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>

View File

@@ -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")

View File

@@ -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>

View File

@@ -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);

View File

@@ -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);

View File

@@ -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">

View File

@@ -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);
}

View File

@@ -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);