From dc095322a2a80a53d4fd88fa4895ef72bc28c95d Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Wed, 18 Apr 2018 13:48:44 -0400 Subject: [PATCH] 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. ``` --- .travis.yml | 1 - .../config/MessagingGatewayRegistrar.java | 39 +++++++++++-------- .../gateway/GatewayProxyFactoryBean.java | 13 +++++-- .../gateway/GatewayInterfaceTests-context.xml | 9 ++++- .../gateway/GatewayInterfaceTests.java | 28 ++++++++++++- 5 files changed, 65 insertions(+), 25 deletions(-) diff --git a/.travis.yml b/.travis.yml index f1806a8756..93a98e3b40 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,6 @@ addons: - mongodb-3.0-precise packages: - mongodb-org-server - - oracle-java8-installer before_cache: - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock cache: diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/MessagingGatewayRegistrar.java b/spring-integration-core/src/main/java/org/springframework/integration/config/MessagingGatewayRegistrar.java index 89336ca641..e2482e175b 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/MessagingGatewayRegistrar.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/MessagingGatewayRegistrar.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2017 the original author or authors. + * Copyright 2014-2018 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. @@ -100,28 +100,33 @@ public class MessagingGatewayRegistrar implements ImportBeanDefinitionRegistrar if (hasDefaultHeaders || hasDefaultPayloadExpression) { BeanDefinitionBuilder methodMetadataBuilder = BeanDefinitionBuilder.genericBeanDefinition(GatewayMethodMetadata.class); + if (hasDefaultPayloadExpression) { methodMetadataBuilder.addPropertyValue("payloadExpression", defaultPayloadExpression); } - Map headerExpressions = new ManagedMap(); - for (Map header : defaultHeaders) { - String headerValue = (String) header.get("value"); - String headerExpression = (String) header.get("expression"); - boolean hasValue = StringUtils.hasText(headerValue); - if (hasValue == StringUtils.hasText(headerExpression)) { - throw new BeanDefinitionStoreException("exactly one of 'value' or 'expression' " + - "is required on a gateway's header."); + if (hasDefaultHeaders) { + Map headerExpressions = new ManagedMap(); + for (Map header : defaultHeaders) { + String headerValue = (String) header.get("value"); + String headerExpression = (String) header.get("expression"); + boolean hasValue = StringUtils.hasText(headerValue); + + if (hasValue == StringUtils.hasText(headerExpression)) { + throw new BeanDefinitionStoreException("exactly one of 'value' or 'expression' " + + "is required on a gateway's header."); + } + + BeanDefinition expressionDef = + new RootBeanDefinition(hasValue ? LiteralExpression.class : ExpressionFactoryBean.class); + expressionDef.getConstructorArgumentValues() + .addGenericArgumentValue(hasValue ? headerValue : headerExpression); + + headerExpressions.put((String) header.get("name"), expressionDef); } - - BeanDefinition expressionDef = - new RootBeanDefinition(hasValue ? LiteralExpression.class : ExpressionFactoryBean.class); - expressionDef.getConstructorArgumentValues() - .addGenericArgumentValue(hasValue ? headerValue : headerExpression); - - headerExpressions.put((String) header.get("name"), expressionDef); + methodMetadataBuilder.addPropertyValue("headerExpressions", headerExpressions); } - methodMetadataBuilder.addPropertyValue("headerExpressions", headerExpressions); + gatewayProxyBuilder.addPropertyValue("globalMethodMetadata", methodMetadataBuilder.getBeanDefinition()); } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/gateway/GatewayProxyFactoryBean.java b/spring-integration-core/src/main/java/org/springframework/integration/gateway/GatewayProxyFactoryBean.java index 3a7e67fb79..3e51ab7733 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/gateway/GatewayProxyFactoryBean.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/gateway/GatewayProxyFactoryBean.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 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. @@ -487,10 +487,15 @@ public class GatewayProxyFactoryBean extends AbstractEndpoint int paramCount = method.getParameterTypes().length; Object response = null; boolean hasPayloadExpression = method.isAnnotationPresent(Payload.class); - if (!hasPayloadExpression && this.methodMetadataMap != null) { + if (!hasPayloadExpression) { // check for the method metadata next - GatewayMethodMetadata metadata = this.methodMetadataMap.get(method.getName()); - hasPayloadExpression = (metadata != null) && StringUtils.hasText(metadata.getPayloadExpression()); + if (this.methodMetadataMap != null) { + GatewayMethodMetadata metadata = this.methodMetadataMap.get(method.getName()); + hasPayloadExpression = (metadata != null) && StringUtils.hasText(metadata.getPayloadExpression()); + } + else if (this.globalMethodMetadata != null) { + hasPayloadExpression = StringUtils.hasText(this.globalMethodMetadata.getPayloadExpression()); + } } if (paramCount == 0 && !hasPayloadExpression) { Long receiveTimeout = null; diff --git a/spring-integration-core/src/test/java/org/springframework/integration/gateway/GatewayInterfaceTests-context.xml b/spring-integration-core/src/test/java/org/springframework/integration/gateway/GatewayInterfaceTests-context.xml index 669a469a56..3b98b09c60 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/gateway/GatewayInterfaceTests-context.xml +++ b/spring-integration-core/src/test/java/org/springframework/integration/gateway/GatewayInterfaceTests-context.xml @@ -10,7 +10,7 @@ @@ -34,9 +34,14 @@ + + diff --git a/spring-integration-core/src/test/java/org/springframework/integration/gateway/GatewayInterfaceTests.java b/spring-integration-core/src/test/java/org/springframework/integration/gateway/GatewayInterfaceTests.java index 7a56c8d320..de88360d26 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/gateway/GatewayInterfaceTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/gateway/GatewayInterfaceTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 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. @@ -75,6 +75,7 @@ import org.springframework.integration.channel.DirectChannel; import org.springframework.integration.config.EnableIntegration; import org.springframework.integration.context.IntegrationContextUtils; import org.springframework.integration.context.IntegrationProperties; +import org.springframework.integration.handler.AbstractReplyProducingMessageHandler; import org.springframework.integration.handler.BridgeHandler; import org.springframework.integration.support.MessageBuilder; import org.springframework.integration.test.util.TestUtils; @@ -487,6 +488,26 @@ public class GatewayInterfaceTests { ((SubscribableChannel) this.errorChannel).unsubscribe(messageHandler); } + @Test + public void testGatewayWithNoArgsMethod() { + ConfigurableApplicationContext ac = + new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", getClass()); + + DirectChannel channel = ac.getBean("requestChannelBar", DirectChannel.class); + channel.subscribe(new AbstractReplyProducingMessageHandler() { + + @Override + protected Object handleRequestMessage(Message requestMessage) { + assertEquals("foo", requestMessage.getPayload()); + return "FOO"; + } + + }); + + NoArgumentsGateway noArgumentsGateway = ac.getBean(NoArgumentsGateway.class); + assertEquals("FOO", noArgumentsGateway.pullData()); + ac.close(); + } public interface Foo { @@ -520,6 +541,11 @@ public class GatewayInterfaceTests { void baz(String payload); } + public interface NoArgumentsGateway { + + String pullData(); + } + public static class BazMapper implements MethodArgsMessageMapper { @Override