Skip to content

Commit 50b1116

Browse files
artembilangaryrussell
authored andcommitted
INT-4448, INT-4449: Fix Gateway for no-arg method (#2420)
* INT-4448, INT-4449: Fix Gateway for no-arg method JIRA: https://jira.spring.io/browse/INT-4448 JIRA: https://jira.spring.io/browse/INT-4449 When we are not interested in the `payload` to send, we use a gateway method without any args, but in this case for send operation (or send-and-receive) we should specify a default `payloadExpression` The `MessagingGatewayRegistrar` fails with `NPE` if we don't have a any global headers and have `defaultPayloadExpression` Also in this case the `GatewayProxyFactoryBean` fails to send and fallbacks to receive with the meaning "no args, not payloadExpression" * Fix `MessagingGatewayRegistrar` to check `hasDefaultHeaders` before processing them * Fix `GatewayProxyFactoryBean` to consult `this.globalMethodMetadata` if there is no `payloadExpression` for the method specific metadata **Cherry-pick to 5.0.x and 4.3.x** * Remove `oracle-java8-installer` since it looks like the resource is not available anymore: ``` Location: http://download.oracle.com/otn-pub/java/jdk/8u161-b12/2f38c3b165be4555a1fa6e98c45e0808/jdk-8u161-linux-x64.tar.gz?AuthParam=1523990114_ee8c82cbe67bc87d192cb79d3b902d2f [following] --2018-04-17 18:33:14-- http://download.oracle.com/otn-pub/java/jdk/8u161-b12/2f38c3b165be4555a1fa6e98c45e0808/jdk-8u161-linux-x64.tar.gz?AuthParam=1523990114_ee8c82cbe67bc87d192cb79d3b902d2f Connecting to download.oracle.com (download.oracle.com)|23.53.120.105|:80... connected. HTTP request sent, awaiting response... 404 Not Found 2018-04-17 18:35:15 ERROR 404: Not Found. ```
1 parent 887ccfe commit 50b1116

File tree

4 files changed

+67
-25
lines changed

4 files changed

+67
-25
lines changed

spring-integration-core/src/main/java/org/springframework/integration/config/MessagingGatewayRegistrar.java

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2014-2016 the original author or authors.
2+
* Copyright 2014-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -114,29 +114,35 @@ public BeanDefinitionHolder parse(Map<String, Object> gatewayAttributes) {
114114
: GatewayProxyFactoryBean.class);
115115

116116
if (hasDefaultHeaders || hasDefaultPayloadExpression) {
117-
BeanDefinitionBuilder methodMetadataBuilder = BeanDefinitionBuilder.genericBeanDefinition(GatewayMethodMetadata.class);
117+
BeanDefinitionBuilder methodMetadataBuilder =
118+
BeanDefinitionBuilder.genericBeanDefinition(GatewayMethodMetadata.class);
119+
118120
if (hasDefaultPayloadExpression) {
119121
methodMetadataBuilder.addPropertyValue("payloadExpression", defaultPayloadExpression);
120122
}
121-
Map<String, Object> headerExpressions = new ManagedMap<String, Object>();
122-
for (Map<String, Object> header : defaultHeaders) {
123-
String headerValue = (String) header.get("value");
124-
String headerExpression = (String) header.get("expression");
125-
boolean hasValue = StringUtils.hasText(headerValue);
126-
127-
if (hasValue == StringUtils.hasText(headerExpression)) {
128-
throw new BeanDefinitionStoreException("exactly one of 'value' or 'expression' " +
129-
"is required on a gateway's header.");
130-
}
131123

132-
BeanDefinition expressionDef =
133-
new RootBeanDefinition(hasValue ? LiteralExpression.class : ExpressionFactoryBean.class);
134-
expressionDef.getConstructorArgumentValues()
135-
.addGenericArgumentValue(hasValue ? headerValue : headerExpression);
124+
if (hasDefaultHeaders) {
125+
Map<String, Object> headerExpressions = new ManagedMap<String, Object>();
126+
for (Map<String, Object> header : defaultHeaders) {
127+
String headerValue = (String) header.get("value");
128+
String headerExpression = (String) header.get("expression");
129+
boolean hasValue = StringUtils.hasText(headerValue);
130+
131+
if (hasValue == StringUtils.hasText(headerExpression)) {
132+
throw new BeanDefinitionStoreException("exactly one of 'value' or 'expression' " +
133+
"is required on a gateway's header.");
134+
}
136135

137-
headerExpressions.put((String) header.get("name"), expressionDef);
136+
BeanDefinition expressionDef =
137+
new RootBeanDefinition(hasValue ? LiteralExpression.class : ExpressionFactoryBean.class);
138+
expressionDef.getConstructorArgumentValues()
139+
.addGenericArgumentValue(hasValue ? headerValue : headerExpression);
140+
141+
headerExpressions.put((String) header.get("name"), expressionDef);
142+
}
143+
methodMetadataBuilder.addPropertyValue("headerExpressions", headerExpressions);
138144
}
139-
methodMetadataBuilder.addPropertyValue("headerExpressions", headerExpressions);
145+
140146
gatewayProxyBuilder.addPropertyValue("globalMethodMetadata", methodMetadataBuilder.getBeanDefinition());
141147
}
142148

spring-integration-core/src/main/java/org/springframework/integration/gateway/GatewayProxyFactoryBean.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -454,10 +454,15 @@ private Object invokeGatewayMethod(MethodInvocation invocation, boolean runningO
454454
boolean hasPayloadExpression =
455455
method.isAnnotationPresent(org.springframework.integration.annotation.Payload.class)
456456
|| method.isAnnotationPresent(Payload.class);
457-
if (!hasPayloadExpression && this.methodMetadataMap != null) {
457+
if (!hasPayloadExpression) {
458458
// check for the method metadata next
459-
GatewayMethodMetadata metadata = this.methodMetadataMap.get(method.getName());
460-
hasPayloadExpression = (metadata != null) && StringUtils.hasText(metadata.getPayloadExpression());
459+
if (this.methodMetadataMap != null) {
460+
GatewayMethodMetadata metadata = this.methodMetadataMap.get(method.getName());
461+
hasPayloadExpression = (metadata != null) && StringUtils.hasText(metadata.getPayloadExpression());
462+
}
463+
else if (this.globalMethodMetadata != null) {
464+
hasPayloadExpression = StringUtils.hasText(this.globalMethodMetadata.getPayloadExpression());
465+
}
461466
}
462467
if (paramCount == 0 && !hasPayloadExpression) {
463468
if (shouldReply) {

spring-integration-core/src/test/java/org/springframework/integration/gateway/GatewayInterfaceTests-context.xml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
</int:channel>
1111

1212
<int:gateway id="sampleGateway"
13-
service-interface="org.springframework.integration.gateway.GatewayInterfaceTests.Bar"
13+
service-interface="org.springframework.integration.gateway.GatewayInterfaceTests$Bar"
1414
default-request-channel="requestChannelBaz"
1515
error-channel="errorChannel">
1616
<int:default-header name="name" expression="#gatewayMethod.name"/>
@@ -35,9 +35,14 @@
3535
<int:channel id="requestChannelBaz"/>
3636

3737
<int:gateway id="customMappedGateway"
38-
service-interface="org.springframework.integration.gateway.GatewayInterfaceTests.Baz"
38+
service-interface="org.springframework.integration.gateway.GatewayInterfaceTests$Baz"
3939
default-request-channel="requestChannelBaz" mapper="mapper"/>
4040

4141
<bean id="mapper" class="org.springframework.integration.gateway.GatewayInterfaceTests$BazMapper"/>
4242

43+
<int:gateway id="sampleGateway2"
44+
service-interface="org.springframework.integration.gateway.GatewayInterfaceTests$NoArgumentsGateway"
45+
default-request-channel="requestChannelBar"
46+
default-payload-expression="'foo'"/>
47+
4348
</beans>

spring-integration-core/src/test/java/org/springframework/integration/gateway/GatewayInterfaceTests.java

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2016 the original author or authors.
2+
* Copyright 2002-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -68,6 +68,7 @@
6868
import org.springframework.integration.configuration.EnableIntegrationTests.TestMessagingGateway;
6969
import org.springframework.integration.context.IntegrationContextUtils;
7070
import org.springframework.integration.context.IntegrationProperties;
71+
import org.springframework.integration.handler.AbstractReplyProducingMessageHandler;
7172
import org.springframework.integration.handler.BridgeHandler;
7273
import org.springframework.integration.support.MessageBuilder;
7374
import org.springframework.integration.test.util.TestUtils;
@@ -441,6 +442,26 @@ public void testIgnoredHeader() {
441442
((SubscribableChannel) this.errorChannel).unsubscribe(messageHandler);
442443
}
443444

445+
@Test
446+
public void testGatewayWithNoArgsMethod() {
447+
ConfigurableApplicationContext ac =
448+
new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", getClass());
449+
450+
DirectChannel channel = ac.getBean("requestChannelBar", DirectChannel.class);
451+
channel.subscribe(new AbstractReplyProducingMessageHandler() {
452+
453+
@Override
454+
protected Object handleRequestMessage(Message<?> requestMessage) {
455+
assertEquals("foo", requestMessage.getPayload());
456+
return "FOO";
457+
}
458+
459+
});
460+
461+
NoArgumentsGateway noArgumentsGateway = ac.getBean(NoArgumentsGateway.class);
462+
assertEquals("FOO", noArgumentsGateway.pullData());
463+
ac.close();
464+
}
444465

445466
public interface Foo {
446467

@@ -469,6 +490,11 @@ public interface Baz {
469490
void baz(String payload);
470491
}
471492

493+
public interface NoArgumentsGateway {
494+
495+
String pullData();
496+
}
497+
472498
public static class BazMapper implements MethodArgsMessageMapper {
473499

474500
@Override

0 commit comments

Comments
 (0)