From e42f23654d102a0d876948c5142dc9466ef3929a Mon Sep 17 00:00:00 2001 From: jatinsaxena Date: Tue, 15 Nov 2022 23:05:47 -0600 Subject: [PATCH 1/6] Add webclient request attribute --- .../WebFluxOutboundChannelAdapterParser.java | 13 ++++++++- ...WebFluxRequestExecutingMessageHandler.java | 28 +++++++++++++++++++ .../config/spring-integration-webflux.xsd | 14 ++++++++++ ...FluxOutboundGatewayParserTests-context.xml | 3 +- .../WebFluxOutboundGatewayParserTests.java | 2 ++ ...uxRequestExecutingMessageHandlerTests.java | 20 ++++++++++--- 6 files changed, 74 insertions(+), 6 deletions(-) diff --git a/spring-integration-webflux/src/main/java/org/springframework/integration/webflux/config/WebFluxOutboundChannelAdapterParser.java b/spring-integration-webflux/src/main/java/org/springframework/integration/webflux/config/WebFluxOutboundChannelAdapterParser.java index 0072cf69af8..156f75f1ebc 100644 --- a/spring-integration-webflux/src/main/java/org/springframework/integration/webflux/config/WebFluxOutboundChannelAdapterParser.java +++ b/spring-integration-webflux/src/main/java/org/springframework/integration/webflux/config/WebFluxOutboundChannelAdapterParser.java @@ -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. @@ -79,6 +79,17 @@ else if (hasTypeExpression) { .getBeanDefinition()); } + String attributeVariablesExpression = element.getAttribute("attribute-variables-expression"); + boolean hasAttibuteVariablesExpression = StringUtils.hasText(attributeVariablesExpression); + + if (hasAttibuteVariablesExpression) { + builder.addPropertyValue("attributeVariablesExpression", + BeanDefinitionBuilder.rootBeanDefinition(ExpressionFactoryBean.class) + .addConstructorArgValue(attributeVariablesExpression) + .getBeanDefinition()); + } + + return builder; } diff --git a/spring-integration-webflux/src/main/java/org/springframework/integration/webflux/outbound/WebFluxRequestExecutingMessageHandler.java b/spring-integration-webflux/src/main/java/org/springframework/integration/webflux/outbound/WebFluxRequestExecutingMessageHandler.java index 076a57f2b85..2da55ec1bc7 100644 --- a/spring-integration-webflux/src/main/java/org/springframework/integration/webflux/outbound/WebFluxRequestExecutingMessageHandler.java +++ b/spring-integration-webflux/src/main/java/org/springframework/integration/webflux/outbound/WebFluxRequestExecutingMessageHandler.java @@ -23,10 +23,12 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import org.springframework.beans.factory.BeanFactory; import org.springframework.core.ParameterizedTypeReference; import org.springframework.core.io.Resource; import org.springframework.expression.Expression; import org.springframework.expression.common.LiteralExpression; +import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.http.HttpEntity; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatusCode; @@ -35,6 +37,7 @@ import org.springframework.http.ResponseEntity; import org.springframework.http.client.reactive.ClientHttpRequest; import org.springframework.http.client.reactive.ClientHttpResponse; +import org.springframework.integration.expression.ExpressionUtils; import org.springframework.integration.expression.ValueExpression; import org.springframework.integration.http.outbound.AbstractHttpRequestExecutingMessageHandler; import org.springframework.lang.Nullable; @@ -75,6 +78,11 @@ public class WebFluxRequestExecutingMessageHandler extends AbstractHttpRequestEx private Expression publisherElementTypeExpression; + private Expression attributeVariablesExpression; + + private StandardEvaluationContext evaluationContext; + + /** * Create a handler that will send requests to the provided URI. * @param uri The URI. @@ -193,11 +201,22 @@ public void setPublisherElementTypeExpression(Expression publisherElementTypeExp this.publisherElementTypeExpression = publisherElementTypeExpression; } + public void setAttributeVariablesExpression(Expression attributeVariablesExpression) { + Assert.notNull(attributeVariablesExpression, "'attributeVariablesExpression' must not be null"); + this.attributeVariablesExpression = attributeVariablesExpression; + } + @Override public String getComponentType() { return (isExpectReply() ? "webflux:outbound-gateway" : "webflux:outbound-channel-adapter"); } + @Override + protected final void doInit() { + BeanFactory beanFactory = getBeanFactory(); + this.evaluationContext = ExpressionUtils.createStandardEvaluationContext(beanFactory); + } + @Override @Nullable protected Object exchange(Object uri, HttpMethod httpMethod, HttpEntity httpRequest, @@ -230,6 +249,12 @@ private WebClient.RequestBodySpec createRequestBodySpec(Object uri, HttpMethod h } requestSpec = requestSpec.headers(headers -> headers.putAll(httpRequest.getHeaders())); + + if(attributeVariablesExpression != null) { + Map attributeMap = evaluateAttributeVariables(requestMessage); + requestSpec = requestSpec.attributes(map -> map.putAll(attributeMap)); + } + BodyInserter inserter = buildBodyInserterForRequest(requestMessage, httpRequest); if (inserter != null) { requestSpec.body(inserter); @@ -369,4 +394,7 @@ private Object createReplyFromResponse(Mono>> respon .map(this::getReply); } + private Map evaluateAttributeVariables(Message requestMessage){ + return this.attributeVariablesExpression.getValue(this.evaluationContext, requestMessage, Map.class); + } } diff --git a/spring-integration-webflux/src/main/resources/org/springframework/integration/webflux/config/spring-integration-webflux.xsd b/spring-integration-webflux/src/main/resources/org/springframework/integration/webflux/config/spring-integration-webflux.xsd index bb07ef4908b..d2a04069c6d 100644 --- a/spring-integration-webflux/src/main/resources/org/springframework/integration/webflux/config/spring-integration-webflux.xsd +++ b/spring-integration-webflux/src/main/resources/org/springframework/integration/webflux/config/spring-integration-webflux.xsd @@ -419,6 +419,13 @@ + + + + + @@ -592,6 +599,13 @@ + + + + + diff --git a/spring-integration-webflux/src/test/java/org/springframework/integration/webflux/config/WebFluxOutboundGatewayParserTests-context.xml b/spring-integration-webflux/src/test/java/org/springframework/integration/webflux/config/WebFluxOutboundGatewayParserTests-context.xml index cbe48c001e5..b78b84d2104 100644 --- a/spring-integration-webflux/src/test/java/org/springframework/integration/webflux/config/WebFluxOutboundGatewayParserTests-context.xml +++ b/spring-integration-webflux/src/test/java/org/springframework/integration/webflux/config/WebFluxOutboundGatewayParserTests-context.xml @@ -39,7 +39,8 @@ reply-payload-to-flux="true" body-extractor="bodyExtractor" publisher-element-type-expression="headers.elementType" - extract-response-body="false"> + extract-response-body="false" + attribute-variables-expression="{name:{first:'Nikola',last:'Tesla'},dob:{day:10,month:'July',year:1856}}"> diff --git a/spring-integration-webflux/src/test/java/org/springframework/integration/webflux/config/WebFluxOutboundGatewayParserTests.java b/spring-integration-webflux/src/test/java/org/springframework/integration/webflux/config/WebFluxOutboundGatewayParserTests.java index 0887625592b..f6b2c4a9503 100644 --- a/spring-integration-webflux/src/test/java/org/springframework/integration/webflux/config/WebFluxOutboundGatewayParserTests.java +++ b/spring-integration-webflux/src/test/java/org/springframework/integration/webflux/config/WebFluxOutboundGatewayParserTests.java @@ -129,6 +129,8 @@ public void reactiveFullConfig() { .isEqualTo("headers.elementType"); assertThat(handlerAccessor.getPropertyValue("extractResponseBody")) .isEqualTo(false); + assertThat(handlerAccessor.getPropertyValue("attributeVariablesExpression.expression")) + .isEqualTo("{name:{first:'Nikola',last:'Tesla'},dob:{day:10,month:'July',year:1856}}"); } } diff --git a/spring-integration-webflux/src/test/java/org/springframework/integration/webflux/outbound/WebFluxRequestExecutingMessageHandlerTests.java b/spring-integration-webflux/src/test/java/org/springframework/integration/webflux/outbound/WebFluxRequestExecutingMessageHandlerTests.java index 99b9ad2cf2f..2bd9e1a67ce 100644 --- a/spring-integration-webflux/src/test/java/org/springframework/integration/webflux/outbound/WebFluxRequestExecutingMessageHandlerTests.java +++ b/spring-integration-webflux/src/test/java/org/springframework/integration/webflux/outbound/WebFluxRequestExecutingMessageHandlerTests.java @@ -16,17 +16,19 @@ package org.springframework.integration.webflux.outbound; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + import java.nio.charset.StandardCharsets; import java.time.Duration; import org.junit.jupiter.api.Test; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; -import reactor.test.StepVerifier; +import org.springframework.beans.factory.BeanFactory; import org.springframework.core.io.buffer.DataBuffer; import org.springframework.core.io.buffer.DataBufferFactory; import org.springframework.core.io.buffer.DataBufferLimitException; +import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.client.reactive.ClientHttpConnector; @@ -44,7 +46,9 @@ import org.springframework.web.reactive.function.client.WebClient; import org.springframework.web.reactive.function.client.WebClientResponseException; -import static org.assertj.core.api.Assertions.assertThat; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; /** * @author Shiliang Li @@ -214,6 +218,10 @@ void testFluxReply() { reactiveHandler.setExpectedResponseType(String.class); reactiveHandler.setReplyPayloadToFlux(true); + reactiveHandler.setAttributeVariablesExpression(new SpelExpressionParser().parseExpression("{name:{first:'Nikola',last:'Tesla'},dob:{day:10,month:'July',year:1856}}")); + setBeanFactory(reactiveHandler); + reactiveHandler.afterPropertiesSet(); + reactiveHandler.handleMessage(MessageBuilder.withPayload(Mono.just("hello, world")).build()); Message receive = replyChannel.receive(10_000); @@ -376,4 +384,8 @@ void testMaxInMemorySizeExceeded() { .isEqualTo("Exceeded limit on max bytes to buffer : 1"); } + private void setBeanFactory(WebFluxRequestExecutingMessageHandler handler) { + handler.setBeanFactory(mock(BeanFactory.class)); + } + } From 7483e14ab8392f742ef38541c7d3c44c2cb3c992 Mon Sep 17 00:00:00 2001 From: Jatin Saxena Date: Tue, 15 Nov 2022 23:15:02 -0600 Subject: [PATCH 2/6] Add author name --- .../webflux/config/WebFluxOutboundChannelAdapterParser.java | 2 +- .../webflux/outbound/WebFluxRequestExecutingMessageHandler.java | 1 + .../webflux/config/WebFluxOutboundGatewayParserTests.java | 1 + .../outbound/WebFluxRequestExecutingMessageHandlerTests.java | 2 +- 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/spring-integration-webflux/src/main/java/org/springframework/integration/webflux/config/WebFluxOutboundChannelAdapterParser.java b/spring-integration-webflux/src/main/java/org/springframework/integration/webflux/config/WebFluxOutboundChannelAdapterParser.java index 156f75f1ebc..56a5f3b205f 100644 --- a/spring-integration-webflux/src/main/java/org/springframework/integration/webflux/config/WebFluxOutboundChannelAdapterParser.java +++ b/spring-integration-webflux/src/main/java/org/springframework/integration/webflux/config/WebFluxOutboundChannelAdapterParser.java @@ -31,7 +31,7 @@ * Parser for the 'outbound-channel-adapter' element of the webflux namespace. * * @author Artem Bilan - * + * @author Jatin Saxena * @since 5.0 */ public class WebFluxOutboundChannelAdapterParser extends HttpOutboundChannelAdapterParser { diff --git a/spring-integration-webflux/src/main/java/org/springframework/integration/webflux/outbound/WebFluxRequestExecutingMessageHandler.java b/spring-integration-webflux/src/main/java/org/springframework/integration/webflux/outbound/WebFluxRequestExecutingMessageHandler.java index 2da55ec1bc7..66e1ac3a29c 100644 --- a/spring-integration-webflux/src/main/java/org/springframework/integration/webflux/outbound/WebFluxRequestExecutingMessageHandler.java +++ b/spring-integration-webflux/src/main/java/org/springframework/integration/webflux/outbound/WebFluxRequestExecutingMessageHandler.java @@ -60,6 +60,7 @@ * @author Artem Bilan * @author Gary Russell * @author David Graff + * @author Jatin Saxena * * @since 5.0 * diff --git a/spring-integration-webflux/src/test/java/org/springframework/integration/webflux/config/WebFluxOutboundGatewayParserTests.java b/spring-integration-webflux/src/test/java/org/springframework/integration/webflux/config/WebFluxOutboundGatewayParserTests.java index f6b2c4a9503..ce1d22ade15 100644 --- a/spring-integration-webflux/src/test/java/org/springframework/integration/webflux/config/WebFluxOutboundGatewayParserTests.java +++ b/spring-integration-webflux/src/test/java/org/springframework/integration/webflux/config/WebFluxOutboundGatewayParserTests.java @@ -40,6 +40,7 @@ /** * @author Artem Bilan + * @author Jatin Saxena * * @since 5.0 */ diff --git a/spring-integration-webflux/src/test/java/org/springframework/integration/webflux/outbound/WebFluxRequestExecutingMessageHandlerTests.java b/spring-integration-webflux/src/test/java/org/springframework/integration/webflux/outbound/WebFluxRequestExecutingMessageHandlerTests.java index 2bd9e1a67ce..20061b9cc63 100644 --- a/spring-integration-webflux/src/test/java/org/springframework/integration/webflux/outbound/WebFluxRequestExecutingMessageHandlerTests.java +++ b/spring-integration-webflux/src/test/java/org/springframework/integration/webflux/outbound/WebFluxRequestExecutingMessageHandlerTests.java @@ -54,7 +54,7 @@ * @author Shiliang Li * @author Artem Bilan * @author David Graff - * + * @author Jatin Saxena * @since 5.0 */ class WebFluxRequestExecutingMessageHandlerTests { From 4209c2e06508978540580cc9d646a88820f2e48d Mon Sep 17 00:00:00 2001 From: Jatin Saxena Date: Thu, 17 Nov 2022 23:53:33 -0600 Subject: [PATCH 3/6] Changes for review comments --- .../WebFluxOutboundChannelAdapterParser.java | 13 ++- ...WebFluxRequestExecutingMessageHandler.java | 4 +- ...uxRequestExecutingMessageHandlerTests.java | 81 ++++++++++++++++--- src/reference/asciidoc/webflux.adoc | 5 ++ src/reference/asciidoc/whats-new.adoc | 8 ++ 5 files changed, 88 insertions(+), 23 deletions(-) diff --git a/spring-integration-webflux/src/main/java/org/springframework/integration/webflux/config/WebFluxOutboundChannelAdapterParser.java b/spring-integration-webflux/src/main/java/org/springframework/integration/webflux/config/WebFluxOutboundChannelAdapterParser.java index 56a5f3b205f..33ec0903141 100644 --- a/spring-integration-webflux/src/main/java/org/springframework/integration/webflux/config/WebFluxOutboundChannelAdapterParser.java +++ b/spring-integration-webflux/src/main/java/org/springframework/integration/webflux/config/WebFluxOutboundChannelAdapterParser.java @@ -18,6 +18,7 @@ import org.w3c.dom.Element; +import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.RuntimeBeanReference; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.xml.ParserContext; @@ -79,17 +80,13 @@ else if (hasTypeExpression) { .getBeanDefinition()); } - String attributeVariablesExpression = element.getAttribute("attribute-variables-expression"); - boolean hasAttibuteVariablesExpression = StringUtils.hasText(attributeVariablesExpression); + BeanDefinition attributeVariablesExpressionDef = IntegrationNamespaceUtils + .createExpressionDefIfAttributeDefined("attribute-variables-expression", element); - if (hasAttibuteVariablesExpression) { - builder.addPropertyValue("attributeVariablesExpression", - BeanDefinitionBuilder.rootBeanDefinition(ExpressionFactoryBean.class) - .addConstructorArgValue(attributeVariablesExpression) - .getBeanDefinition()); + if (attributeVariablesExpressionDef != null) { + builder.addPropertyValue("attributeVariablesExpression", attributeVariablesExpressionDef); } - return builder; } diff --git a/spring-integration-webflux/src/main/java/org/springframework/integration/webflux/outbound/WebFluxRequestExecutingMessageHandler.java b/spring-integration-webflux/src/main/java/org/springframework/integration/webflux/outbound/WebFluxRequestExecutingMessageHandler.java index 66e1ac3a29c..86d6f3b8ec8 100644 --- a/spring-integration-webflux/src/main/java/org/springframework/integration/webflux/outbound/WebFluxRequestExecutingMessageHandler.java +++ b/spring-integration-webflux/src/main/java/org/springframework/integration/webflux/outbound/WebFluxRequestExecutingMessageHandler.java @@ -23,7 +23,6 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; -import org.springframework.beans.factory.BeanFactory; import org.springframework.core.ParameterizedTypeReference; import org.springframework.core.io.Resource; import org.springframework.expression.Expression; @@ -214,8 +213,7 @@ public String getComponentType() { @Override protected final void doInit() { - BeanFactory beanFactory = getBeanFactory(); - this.evaluationContext = ExpressionUtils.createStandardEvaluationContext(beanFactory); + this.evaluationContext = ExpressionUtils.createStandardEvaluationContext(getBeanFactory()); } @Override diff --git a/spring-integration-webflux/src/test/java/org/springframework/integration/webflux/outbound/WebFluxRequestExecutingMessageHandlerTests.java b/spring-integration-webflux/src/test/java/org/springframework/integration/webflux/outbound/WebFluxRequestExecutingMessageHandlerTests.java index 20061b9cc63..c2d34e58971 100644 --- a/spring-integration-webflux/src/test/java/org/springframework/integration/webflux/outbound/WebFluxRequestExecutingMessageHandlerTests.java +++ b/spring-integration-webflux/src/test/java/org/springframework/integration/webflux/outbound/WebFluxRequestExecutingMessageHandlerTests.java @@ -16,18 +16,21 @@ package org.springframework.integration.webflux.outbound; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; - import java.nio.charset.StandardCharsets; import java.time.Duration; +import java.util.Map; +import java.util.Optional; import org.junit.jupiter.api.Test; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; import org.springframework.beans.factory.BeanFactory; import org.springframework.core.io.buffer.DataBuffer; import org.springframework.core.io.buffer.DataBufferFactory; import org.springframework.core.io.buffer.DataBufferLimitException; +import org.springframework.expression.Expression; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; @@ -42,13 +45,16 @@ import org.springframework.messaging.MessageHandlingException; import org.springframework.messaging.support.ErrorMessage; import org.springframework.test.web.reactive.server.HttpHandlerConnector; +import org.springframework.web.reactive.function.client.ClientRequest; +import org.springframework.web.reactive.function.client.ClientResponse; +import org.springframework.web.reactive.function.client.ExchangeFilterFunction; +import org.springframework.web.reactive.function.client.ExchangeFunction; import org.springframework.web.reactive.function.client.ExchangeStrategies; import org.springframework.web.reactive.function.client.WebClient; import org.springframework.web.reactive.function.client.WebClientResponseException; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; -import reactor.test.StepVerifier; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; /** * @author Shiliang Li @@ -218,10 +224,6 @@ void testFluxReply() { reactiveHandler.setExpectedResponseType(String.class); reactiveHandler.setReplyPayloadToFlux(true); - reactiveHandler.setAttributeVariablesExpression(new SpelExpressionParser().parseExpression("{name:{first:'Nikola',last:'Tesla'},dob:{day:10,month:'July',year:1856}}")); - setBeanFactory(reactiveHandler); - reactiveHandler.afterPropertiesSet(); - reactiveHandler.handleMessage(MessageBuilder.withPayload(Mono.just("hello, world")).build()); Message receive = replyChannel.receive(10_000); @@ -384,8 +386,63 @@ void testMaxInMemorySizeExceeded() { .isEqualTo("Exceeded limit on max bytes to buffer : 1"); } - private void setBeanFactory(WebFluxRequestExecutingMessageHandler handler) { - handler.setBeanFactory(mock(BeanFactory.class)); + @Test + @SuppressWarnings("unchecked") + void testFluxReplyWithRequestAttribute() { + ClientHttpConnector httpConnector = new HttpHandlerConnector((request, response) -> { + response.setStatusCode(HttpStatus.OK); + response.getHeaders().setContentType(MediaType.TEXT_PLAIN); + + DataBufferFactory bufferFactory = response.bufferFactory(); + + Mono data = Mono.just(bufferFactory.wrap("foo\nbar\nbaz".getBytes())); + + return response.writeWith(data) + .then(Mono.defer(response::setComplete)); + }); + + class AttributeFilter implements ExchangeFilterFunction { + + Optional attributeValueName; + + @Override + public Mono filter(ClientRequest request, ExchangeFunction next) { + this.attributeValueName = request.attribute("name"); + return next.exchange(request); + } + } + + AttributeFilter attributeFilter = new AttributeFilter(); + WebClient webClient = WebClient.builder() + .clientConnector(httpConnector) + .filter(attributeFilter) + .build(); + + String destinationUri = "https://www.springsource.org/spring-integration"; + WebFluxRequestExecutingMessageHandler reactiveHandler = + new WebFluxRequestExecutingMessageHandler(destinationUri, webClient); + + QueueChannel replyChannel = new QueueChannel(); + reactiveHandler.setOutputChannel(replyChannel); + reactiveHandler.setExpectedResponseType(String.class); + reactiveHandler.setReplyPayloadToFlux(true); + Expression expr = new SpelExpressionParser().parseExpression("{name:{first:'Nikola'}}"); + reactiveHandler.setAttributeVariablesExpression(expr); + reactiveHandler.setBeanFactory(mock(BeanFactory.class)); + reactiveHandler.afterPropertiesSet(); + + reactiveHandler.handleMessage(MessageBuilder.withPayload(Mono.just("hello, world")).build()); + + Message receive = replyChannel.receive(10_000); + + assertThat(attributeFilter.attributeValueName).isPresent(); + + Map attributeValueNameMap = (Map) attributeFilter.attributeValueName.get(); + + assertThat(attributeValueNameMap.get("first")).isEqualTo("Nikola"); + + assertThat(receive).isNotNull(); + } } diff --git a/src/reference/asciidoc/webflux.adoc b/src/reference/asciidoc/webflux.adoc index 8edba5b95d0..44aca918abb 100644 --- a/src/reference/asciidoc/webflux.adoc +++ b/src/reference/asciidoc/webflux.adoc @@ -319,3 +319,8 @@ See <<./http.adoc#http-outbound,HTTP Outbound Components>> for more possible con Since WebFlux components are fully based on the HTTP protocol, there is no difference in the HTTP headers mapping. See <<./http.adoc#http-header-mapping,HTTP Header Mappings>> for more possible options and components to use for mapping headers. + +[[webflux-request-attribute]] +=== WebFlux Request Attribute + +Starting with Version 6, Webflux outbound request can have request attribute which can be specified in `attribute-variables-expression` attribute. This attribute will take an `expression` that should be evaluated in `Map`. \ No newline at end of file diff --git a/src/reference/asciidoc/whats-new.adoc b/src/reference/asciidoc/whats-new.adoc index ec7befe0729..1604a1a849d 100644 --- a/src/reference/asciidoc/whats-new.adoc +++ b/src/reference/asciidoc/whats-new.adoc @@ -186,3 +186,11 @@ See <<./jms.adoc#jms,JMS Support>> for more information. The `ChannelSecurityInterceptor` and its annotation `@SecuredChannel` and XML `` configurations have been deprecated in favor of `AuthorizationChannelInterceptor`. See <<./security.adoc#security,Security Support>> for more information. + +[[x6.0-webflux]] + +=== Webflux request attribute support +Webclient Request attribute support has been added for outbound request.See <<./webflux.adoc#webflux-request-attribute,WebFlux Request Attribute>> for more information. + + + From 8237a99cb2ca0613c825a65c0760117c0c8201f4 Mon Sep 17 00:00:00 2001 From: Jatin Saxena Date: Fri, 18 Nov 2022 12:45:55 -0600 Subject: [PATCH 4/6] Changes for review comments --- .../WebFluxRequestExecutingMessageHandler.java | 15 ++++++++++++--- ...bFluxRequestExecutingMessageHandlerTests.java | 16 ++++++++-------- src/reference/asciidoc/webflux.adoc | 3 ++- src/reference/asciidoc/whats-new.adoc | 5 +++-- 4 files changed, 25 insertions(+), 14 deletions(-) diff --git a/spring-integration-webflux/src/main/java/org/springframework/integration/webflux/outbound/WebFluxRequestExecutingMessageHandler.java b/spring-integration-webflux/src/main/java/org/springframework/integration/webflux/outbound/WebFluxRequestExecutingMessageHandler.java index 86d6f3b8ec8..10a1c619273 100644 --- a/spring-integration-webflux/src/main/java/org/springframework/integration/webflux/outbound/WebFluxRequestExecutingMessageHandler.java +++ b/spring-integration-webflux/src/main/java/org/springframework/integration/webflux/outbound/WebFluxRequestExecutingMessageHandler.java @@ -201,6 +201,12 @@ public void setPublisherElementTypeExpression(Expression publisherElementTypeExp this.publisherElementTypeExpression = publisherElementTypeExpression; } + /** + * Configure expression to evaluate request attribute which will be added to webclient request attribute. + * @param attributeVariablesExpression the expression to evaluate request attribute. + * @since 6.0 + * @see WebFluxRequestExecutingMessageHandler#evaluateAttributeVariables(Message) + */ public void setAttributeVariablesExpression(Expression attributeVariablesExpression) { Assert.notNull(attributeVariablesExpression, "'attributeVariablesExpression' must not be null"); this.attributeVariablesExpression = attributeVariablesExpression; @@ -249,9 +255,11 @@ private WebClient.RequestBodySpec createRequestBodySpec(Object uri, HttpMethod h requestSpec = requestSpec.headers(headers -> headers.putAll(httpRequest.getHeaders())); - if(attributeVariablesExpression != null) { + if (this.attributeVariablesExpression != null) { Map attributeMap = evaluateAttributeVariables(requestMessage); - requestSpec = requestSpec.attributes(map -> map.putAll(attributeMap)); + if (attributeMap != null && !attributeMap.isEmpty()) { + requestSpec = requestSpec.attributes(map -> map.putAll(attributeMap)); + } } BodyInserter inserter = buildBodyInserterForRequest(requestMessage, httpRequest); @@ -393,7 +401,8 @@ private Object createReplyFromResponse(Mono>> respon .map(this::getReply); } - private Map evaluateAttributeVariables(Message requestMessage){ + @SuppressWarnings("unchecked") + private Map evaluateAttributeVariables(Message requestMessage) { return this.attributeVariablesExpression.getValue(this.evaluationContext, requestMessage, Map.class); } } diff --git a/spring-integration-webflux/src/test/java/org/springframework/integration/webflux/outbound/WebFluxRequestExecutingMessageHandlerTests.java b/spring-integration-webflux/src/test/java/org/springframework/integration/webflux/outbound/WebFluxRequestExecutingMessageHandlerTests.java index c2d34e58971..df3c7c91951 100644 --- a/spring-integration-webflux/src/test/java/org/springframework/integration/webflux/outbound/WebFluxRequestExecutingMessageHandlerTests.java +++ b/spring-integration-webflux/src/test/java/org/springframework/integration/webflux/outbound/WebFluxRequestExecutingMessageHandlerTests.java @@ -401,16 +401,16 @@ void testFluxReplyWithRequestAttribute() { .then(Mono.defer(response::setComplete)); }); - class AttributeFilter implements ExchangeFilterFunction { + class AttributeFilter implements ExchangeFilterFunction { Optional attributeValueName; - @Override - public Mono filter(ClientRequest request, ExchangeFunction next) { - this.attributeValueName = request.attribute("name"); - return next.exchange(request); - } - } + @Override + public Mono filter(ClientRequest request, ExchangeFunction next) { + this.attributeValueName = request.attribute("name"); + return next.exchange(request); + } + } AttributeFilter attributeFilter = new AttributeFilter(); WebClient webClient = WebClient.builder() @@ -437,7 +437,7 @@ public Mono filter(ClientRequest request, ExchangeFunction next) assertThat(attributeFilter.attributeValueName).isPresent(); - Map attributeValueNameMap = (Map) attributeFilter.attributeValueName.get(); + Map attributeValueNameMap = (Map) attributeFilter.attributeValueName.get(); assertThat(attributeValueNameMap.get("first")).isEqualTo("Nikola"); diff --git a/src/reference/asciidoc/webflux.adoc b/src/reference/asciidoc/webflux.adoc index 44aca918abb..03d1329178e 100644 --- a/src/reference/asciidoc/webflux.adoc +++ b/src/reference/asciidoc/webflux.adoc @@ -323,4 +323,5 @@ See <<./http.adoc#http-header-mapping,HTTP Header Mappings>> for more possible o [[webflux-request-attribute]] === WebFlux Request Attribute -Starting with Version 6, Webflux outbound request can have request attribute which can be specified in `attribute-variables-expression` attribute. This attribute will take an `expression` that should be evaluated in `Map`. \ No newline at end of file +Starting with version 6.0, Webflux outbound request `WebFluxRequestExecutingMessageHandler` can have request attribute which can be specified in `setAttributeVariablesExpression()`. +This will take an `expression` that should be evaluated in `Map`. \ No newline at end of file diff --git a/src/reference/asciidoc/whats-new.adoc b/src/reference/asciidoc/whats-new.adoc index 1604a1a849d..804231cc5dd 100644 --- a/src/reference/asciidoc/whats-new.adoc +++ b/src/reference/asciidoc/whats-new.adoc @@ -188,9 +188,10 @@ The `ChannelSecurityInterceptor` and its annotation `@SecuredChannel` and XML `< See <<./security.adoc#security,Security Support>> for more information. [[x6.0-webflux]] - === Webflux request attribute support -Webclient Request attribute support has been added for outbound request.See <<./webflux.adoc#webflux-request-attribute,WebFlux Request Attribute>> for more information. + +Webclient Request attribute support has been added for outbound request. +See <<./webflux.adoc#webflux-request-attribute,WebFlux Request Attribute>> for more information. From 8d051e334dec87def93eae88a6ea95e4cadea972 Mon Sep 17 00:00:00 2001 From: Jatin Saxena Date: Fri, 18 Nov 2022 13:06:04 -0600 Subject: [PATCH 5/6] Changes for review comments --- .../outbound/WebFluxRequestExecutingMessageHandler.java | 3 ++- src/reference/asciidoc/webflux.adoc | 6 +++--- src/reference/asciidoc/whats-new.adoc | 6 +++--- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/spring-integration-webflux/src/main/java/org/springframework/integration/webflux/outbound/WebFluxRequestExecutingMessageHandler.java b/spring-integration-webflux/src/main/java/org/springframework/integration/webflux/outbound/WebFluxRequestExecutingMessageHandler.java index 10a1c619273..b923d171ce2 100644 --- a/spring-integration-webflux/src/main/java/org/springframework/integration/webflux/outbound/WebFluxRequestExecutingMessageHandler.java +++ b/spring-integration-webflux/src/main/java/org/springframework/integration/webflux/outbound/WebFluxRequestExecutingMessageHandler.java @@ -205,7 +205,7 @@ public void setPublisherElementTypeExpression(Expression publisherElementTypeExp * Configure expression to evaluate request attribute which will be added to webclient request attribute. * @param attributeVariablesExpression the expression to evaluate request attribute. * @since 6.0 - * @see WebFluxRequestExecutingMessageHandler#evaluateAttributeVariables(Message) + * @see WebClient.RequestBodySpec#attributes */ public void setAttributeVariablesExpression(Expression attributeVariablesExpression) { Assert.notNull(attributeVariablesExpression, "'attributeVariablesExpression' must not be null"); @@ -405,4 +405,5 @@ private Object createReplyFromResponse(Mono>> respon private Map evaluateAttributeVariables(Message requestMessage) { return this.attributeVariablesExpression.getValue(this.evaluationContext, requestMessage, Map.class); } + } diff --git a/src/reference/asciidoc/webflux.adoc b/src/reference/asciidoc/webflux.adoc index 03d1329178e..6ba24873959 100644 --- a/src/reference/asciidoc/webflux.adoc +++ b/src/reference/asciidoc/webflux.adoc @@ -320,8 +320,8 @@ See <<./http.adoc#http-outbound,HTTP Outbound Components>> for more possible con Since WebFlux components are fully based on the HTTP protocol, there is no difference in the HTTP headers mapping. See <<./http.adoc#http-header-mapping,HTTP Header Mappings>> for more possible options and components to use for mapping headers. -[[webflux-request-attribute]] -=== WebFlux Request Attribute +[[webflux-request-attributes]] +=== WebFlux Request Attributes -Starting with version 6.0, Webflux outbound request `WebFluxRequestExecutingMessageHandler` can have request attribute which can be specified in `setAttributeVariablesExpression()`. +Starting with version 6.0, Webflux outbound request `WebFluxRequestExecutingMessageHandler` can have request attributes which can be specified in `setAttributeVariablesExpression()`. This will take an `expression` that should be evaluated in `Map`. \ No newline at end of file diff --git a/src/reference/asciidoc/whats-new.adoc b/src/reference/asciidoc/whats-new.adoc index 804231cc5dd..20a56e93246 100644 --- a/src/reference/asciidoc/whats-new.adoc +++ b/src/reference/asciidoc/whats-new.adoc @@ -188,10 +188,10 @@ The `ChannelSecurityInterceptor` and its annotation `@SecuredChannel` and XML `< See <<./security.adoc#security,Security Support>> for more information. [[x6.0-webflux]] -=== Webflux request attribute support +=== Webflux Request Attributes Support -Webclient Request attribute support has been added for outbound request. -See <<./webflux.adoc#webflux-request-attribute,WebFlux Request Attribute>> for more information. +Webclient Request attributes support has been added for `WebFluxRequestExecutingMessageHandler`. +See <<./webflux.adoc#webflux-request-attributes,WebFlux Request Attributes>> for more information. From c60c3b82ad1ab4ab5a1369db32605a33344c5cda Mon Sep 17 00:00:00 2001 From: Jatin Saxena Date: Fri, 18 Nov 2022 14:11:23 -0600 Subject: [PATCH 6/6] Changes for review comments --- .../outbound/WebFluxRequestExecutingMessageHandler.java | 4 +++- src/reference/asciidoc/webflux.adoc | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/spring-integration-webflux/src/main/java/org/springframework/integration/webflux/outbound/WebFluxRequestExecutingMessageHandler.java b/spring-integration-webflux/src/main/java/org/springframework/integration/webflux/outbound/WebFluxRequestExecutingMessageHandler.java index b923d171ce2..3354728a336 100644 --- a/spring-integration-webflux/src/main/java/org/springframework/integration/webflux/outbound/WebFluxRequestExecutingMessageHandler.java +++ b/spring-integration-webflux/src/main/java/org/springframework/integration/webflux/outbound/WebFluxRequestExecutingMessageHandler.java @@ -42,6 +42,7 @@ import org.springframework.lang.Nullable; import org.springframework.messaging.Message; import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; import org.springframework.util.MultiValueMap; import org.springframework.web.reactive.function.BodyExtractor; import org.springframework.web.reactive.function.BodyExtractors; @@ -219,6 +220,7 @@ public String getComponentType() { @Override protected final void doInit() { + super.doInit(); this.evaluationContext = ExpressionUtils.createStandardEvaluationContext(getBeanFactory()); } @@ -257,7 +259,7 @@ private WebClient.RequestBodySpec createRequestBodySpec(Object uri, HttpMethod h if (this.attributeVariablesExpression != null) { Map attributeMap = evaluateAttributeVariables(requestMessage); - if (attributeMap != null && !attributeMap.isEmpty()) { + if (!CollectionUtils.isEmpty(attributeMap)) { requestSpec = requestSpec.attributes(map -> map.putAll(attributeMap)); } } diff --git a/src/reference/asciidoc/webflux.adoc b/src/reference/asciidoc/webflux.adoc index 6ba24873959..389e50ed870 100644 --- a/src/reference/asciidoc/webflux.adoc +++ b/src/reference/asciidoc/webflux.adoc @@ -324,4 +324,5 @@ See <<./http.adoc#http-header-mapping,HTTP Header Mappings>> for more possible o === WebFlux Request Attributes Starting with version 6.0, Webflux outbound request `WebFluxRequestExecutingMessageHandler` can have request attributes which can be specified in `setAttributeVariablesExpression()`. -This will take an `expression` that should be evaluated in `Map`. \ No newline at end of file +This will take an `expression` that should be evaluated in `Map`. +This will be helpful if an information in form of key-value object needs be passed from `Message` to request and downstream filter will get access to this attribute for further processing. \ No newline at end of file