Make HTTP modules as auto-configuration
* Fix all the Checkstyle violations and compiler warnings
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2018-2022 the original author or authors.
|
||||
* Copyright 2018-2024 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.
|
||||
@@ -20,34 +20,37 @@ import java.time.Duration;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.integration.config.IntegrationConverter;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
import org.springframework.web.util.DefaultUriBuilderFactory;
|
||||
import org.springframework.web.util.UriBuilderFactory;
|
||||
|
||||
/**
|
||||
* Configuration for a {@link Function} that makes HTTP requests to a resource and for
|
||||
* each request, returns a {@link ResponseEntity}.
|
||||
* Auto-configuration for a {@link Function} that makes HTTP requests to a resource and
|
||||
* for each request, returns a {@link ResponseEntity}.
|
||||
*
|
||||
* @author David Turanski
|
||||
* @author Sunny Hemdev
|
||||
* @author Corneil du Plessis
|
||||
**/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@AutoConfiguration
|
||||
@EnableConfigurationProperties(HttpRequestFunctionProperties.class)
|
||||
public class HttpRequestFunctionConfiguration {
|
||||
|
||||
@Bean
|
||||
public HttpRequestFunction httpRequestFunction(WebClient.Builder webClientBuilder,
|
||||
HttpRequestFunctionProperties properties) {
|
||||
|
||||
return new HttpRequestFunction(webClientBuilder.build(), properties);
|
||||
}
|
||||
|
||||
@@ -77,37 +80,39 @@ public class HttpRequestFunctionConfiguration {
|
||||
@Override
|
||||
public Object apply(Message<?> message) {
|
||||
return this.webClient.method(resolveHttpMethod(message))
|
||||
.uri(uriBuilderFactory.uriString(resolveUrl(message)).build())
|
||||
.uri(this.uriBuilderFactory.uriString(resolveUrl(message)).build())
|
||||
.bodyValue(resolveBody(message))
|
||||
.headers(httpHeaders -> httpHeaders.addAll(resolveHeaders(message)))
|
||||
.headers((httpHeaders) -> httpHeaders.addAll(resolveHeaders(message)))
|
||||
.retrieve()
|
||||
.toEntity(properties.getExpectedResponseType())
|
||||
.map(responseEntity -> properties.getReplyExpression().getValue(responseEntity))
|
||||
.timeout(Duration.ofMillis(properties.getTimeout()))
|
||||
.toEntity(this.properties.getExpectedResponseType())
|
||||
.map((responseEntity) -> this.properties.getReplyExpression().getValue(responseEntity))
|
||||
.timeout(Duration.ofMillis(this.properties.getTimeout()))
|
||||
.block();
|
||||
}
|
||||
|
||||
private String resolveUrl(Message<?> message) {
|
||||
return properties.getUrlExpression().getValue(message, String.class);
|
||||
return this.properties.getUrlExpression().getValue(message, String.class);
|
||||
}
|
||||
|
||||
private HttpMethod resolveHttpMethod(Message<?> message) {
|
||||
return properties.getHttpMethodExpression().getValue(message, HttpMethod.class);
|
||||
return this.properties.getHttpMethodExpression().getValue(message, HttpMethod.class);
|
||||
}
|
||||
|
||||
private Object resolveBody(Message<?> message) {
|
||||
return properties.getBodyExpression() != null ? properties.getBodyExpression().getValue(message)
|
||||
return (this.properties.getBodyExpression() != null) ? this.properties.getBodyExpression().getValue(message)
|
||||
: message.getPayload();
|
||||
}
|
||||
|
||||
private HttpHeaders resolveHeaders(Message<?> message) {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
if (properties.getHeadersExpression() != null) {
|
||||
Map<?, ?> headersMap = properties.getHeadersExpression().getValue(message, Map.class);
|
||||
for (Map.Entry<?, ?> header : headersMap.entrySet()) {
|
||||
if (header.getKey() != null && header.getValue() != null) {
|
||||
headers.add(header.getKey().toString(), header.getValue().toString());
|
||||
}
|
||||
Expression headersExpression = this.properties.getHeadersExpression();
|
||||
if (headersExpression != null) {
|
||||
Map<?, ?> headersMap = headersExpression.getValue(message, Map.class);
|
||||
if (!CollectionUtils.isEmpty(headersMap)) {
|
||||
headersMap.entrySet()
|
||||
.stream()
|
||||
.filter((entry) -> entry.getKey() != null && entry.getValue() != null)
|
||||
.forEach((entry) -> headers.add(entry.getKey().toString(), entry.getValue().toString()));
|
||||
}
|
||||
}
|
||||
return headers;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015-2022 the original author or authors.
|
||||
* Copyright 2015-2024 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.
|
||||
@@ -60,7 +60,7 @@ public class HttpRequestFunctionProperties {
|
||||
/**
|
||||
* A SpEL expression to derive the request method from the incoming message.
|
||||
*/
|
||||
private Expression httpMethodExpression = new ValueExpression(HttpMethod.GET);
|
||||
private Expression httpMethodExpression = new ValueExpression<>(HttpMethod.GET);
|
||||
|
||||
/**
|
||||
* A SpEL expression to derive the request body from the incoming message.
|
||||
@@ -74,13 +74,13 @@ public class HttpRequestFunctionProperties {
|
||||
|
||||
/**
|
||||
* A SpEL expression used to compute the final result, applied against the whole http
|
||||
* {@link org.springframework.http.ResponseEntity}.
|
||||
* {@link ResponseEntity}.
|
||||
*/
|
||||
private Expression replyExpression = new FunctionExpression<ResponseEntity>(ResponseEntity::getBody);
|
||||
private Expression replyExpression = new FunctionExpression<ResponseEntity<?>>(ResponseEntity::getBody);
|
||||
|
||||
@NotNull
|
||||
public Expression getUrlExpression() {
|
||||
return urlExpression;
|
||||
return this.urlExpression;
|
||||
}
|
||||
|
||||
public void setUrlExpression(Expression urlExpression) {
|
||||
@@ -88,7 +88,7 @@ public class HttpRequestFunctionProperties {
|
||||
}
|
||||
|
||||
public Expression getHttpMethodExpression() {
|
||||
return httpMethodExpression;
|
||||
return this.httpMethodExpression;
|
||||
}
|
||||
|
||||
public void setHttpMethodExpression(Expression httpMethodExpression) {
|
||||
@@ -97,7 +97,7 @@ public class HttpRequestFunctionProperties {
|
||||
|
||||
@NotNull
|
||||
public Class<?> getExpectedResponseType() {
|
||||
return expectedResponseType;
|
||||
return this.expectedResponseType;
|
||||
}
|
||||
|
||||
public void setExpectedResponseType(Class<?> expectedResponseType) {
|
||||
@@ -113,7 +113,7 @@ public class HttpRequestFunctionProperties {
|
||||
}
|
||||
|
||||
public Expression getBodyExpression() {
|
||||
return bodyExpression;
|
||||
return this.bodyExpression;
|
||||
}
|
||||
|
||||
public void setBodyExpression(Expression bodyExpression) {
|
||||
@@ -121,7 +121,7 @@ public class HttpRequestFunctionProperties {
|
||||
}
|
||||
|
||||
public Expression getHeadersExpression() {
|
||||
return headersExpression;
|
||||
return this.headersExpression;
|
||||
}
|
||||
|
||||
public void setHeadersExpression(Expression headersExpression) {
|
||||
@@ -130,7 +130,7 @@ public class HttpRequestFunctionProperties {
|
||||
|
||||
@NotNull
|
||||
public Expression getReplyExpression() {
|
||||
return replyExpression;
|
||||
return this.replyExpression;
|
||||
}
|
||||
|
||||
public void setReplyExpression(Expression replyExpression) {
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* The HTTP function auto-configuration.
|
||||
*/
|
||||
package org.springframework.cloud.fn.http.request;
|
||||
@@ -0,0 +1 @@
|
||||
org.springframework.cloud.fn.http.request.HttpRequestFunctionConfiguration
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2020-2020 the original author or authors.
|
||||
* Copyright 2020-2024 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.
|
||||
@@ -40,11 +40,11 @@ import org.springframework.messaging.support.GenericMessage;
|
||||
import org.springframework.messaging.support.MessageBuilder;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
|
||||
public class HttpRequestFunctionTestApplicationTests {
|
||||
public class HttpRequestFunctionTests {
|
||||
|
||||
private MockWebServer server = new MockWebServer();
|
||||
private final MockWebServer server = new MockWebServer();
|
||||
|
||||
private ApplicationContextRunner runner;
|
||||
|
||||
@@ -56,13 +56,12 @@ public class HttpRequestFunctionTestApplicationTests {
|
||||
|
||||
@Test
|
||||
void shouldReturnString() {
|
||||
|
||||
server.enqueue(new MockResponse().setResponseCode(HttpStatus.OK.value()).setBody("hello"));
|
||||
|
||||
runner.withPropertyValues("http.request.http-method-expression='POST'").run(context -> {
|
||||
runner.withPropertyValues("http.request.http-method-expression='POST'").run((context) -> {
|
||||
HttpRequestFunction httpRequestFunction = context.getBean(HttpRequestFunction.class);
|
||||
Message<?> message = MessageBuilder.withPayload("").build();
|
||||
ResponseEntity r = (ResponseEntity) httpRequestFunction.apply(message);
|
||||
ResponseEntity<?> r = (ResponseEntity<?>) httpRequestFunction.apply(message);
|
||||
assertThat(r.getBody()).isEqualTo("hello");
|
||||
assertThat(r.getStatusCode().is2xxSuccessful()).isTrue();
|
||||
});
|
||||
@@ -70,7 +69,6 @@ public class HttpRequestFunctionTestApplicationTests {
|
||||
|
||||
@Test
|
||||
void shouldPostJson() {
|
||||
|
||||
server.setDispatcher(new Dispatcher() {
|
||||
@Override
|
||||
public MockResponse dispatch(RecordedRequest recordedRequest) {
|
||||
@@ -84,11 +82,11 @@ public class HttpRequestFunctionTestApplicationTests {
|
||||
runner
|
||||
.withPropertyValues("http.request.http-method-expression='POST'",
|
||||
"http.request.headers-expression={'Content-Type':'application/json'}")
|
||||
.run(context -> {
|
||||
.run((context) -> {
|
||||
HttpRequestFunction httpRequestFunction = context.getBean(HttpRequestFunction.class);
|
||||
String json = "{\"hello\":\"world\"}";
|
||||
Message<?> message = MessageBuilder.withPayload(json).build();
|
||||
ResponseEntity r = (ResponseEntity) httpRequestFunction.apply(message);
|
||||
ResponseEntity<?> r = (ResponseEntity<?>) httpRequestFunction.apply(message);
|
||||
assertThat(r.getBody()).isEqualTo(json);
|
||||
assertThat(r.getStatusCode().is2xxSuccessful()).isTrue();
|
||||
assertThat(r.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_JSON);
|
||||
@@ -113,11 +111,11 @@ public class HttpRequestFunctionTestApplicationTests {
|
||||
runner
|
||||
.withPropertyValues("http.request.http-method-expression='POST'",
|
||||
"http.request.expected-response-type=" + Map.class.getName())
|
||||
.run(context -> {
|
||||
.run((context) -> {
|
||||
HttpRequestFunction httpRequestFunction = context.getBean(HttpRequestFunction.class);
|
||||
Map<String, String> json = Collections.singletonMap("hello", "world");
|
||||
Message<?> message = MessageBuilder.withPayload(json).build();
|
||||
ResponseEntity r = (ResponseEntity) httpRequestFunction.apply(message);
|
||||
ResponseEntity<?> r = (ResponseEntity<?>) httpRequestFunction.apply(message);
|
||||
assertThat(r.getBody()).isEqualTo(json);
|
||||
assertThat(r.getStatusCode().is2xxSuccessful()).isTrue();
|
||||
assertThat(r.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_JSON);
|
||||
@@ -141,10 +139,10 @@ public class HttpRequestFunctionTestApplicationTests {
|
||||
runner
|
||||
.withPropertyValues("http.request.http-method-expression='DELETE'",
|
||||
"http.request.expected-response-type=" + Void.class.getName())
|
||||
.run(context -> {
|
||||
.run((context) -> {
|
||||
HttpRequestFunction httpRequestFunction = context.getBean(HttpRequestFunction.class);
|
||||
Message<?> message = MessageBuilder.withPayload("").build();
|
||||
ResponseEntity r = (ResponseEntity) httpRequestFunction.apply(message);
|
||||
ResponseEntity<?> r = (ResponseEntity<?>) httpRequestFunction.apply(message);
|
||||
assertThat(r.getBody()).isNull();
|
||||
assertThat(r.getStatusCode().is2xxSuccessful()).isTrue();
|
||||
RecordedRequest request = server.takeRequest(100, TimeUnit.MILLISECONDS);
|
||||
@@ -155,15 +153,11 @@ public class HttpRequestFunctionTestApplicationTests {
|
||||
@Test
|
||||
void shouldThrowErrorIfCannotConnect() throws IOException {
|
||||
server.shutdown();
|
||||
runner.run(context -> {
|
||||
runner.run((context) -> {
|
||||
HttpRequestFunction httpRequestFunction = context.getBean(HttpRequestFunction.class);
|
||||
try {
|
||||
httpRequestFunction.apply(new GenericMessage(""));
|
||||
fail("Expected exception");
|
||||
}
|
||||
catch (Throwable throwable) {
|
||||
assertThat(throwable.getMessage()).contains("Connection refused");
|
||||
}
|
||||
assertThatExceptionOfType(Throwable.class)
|
||||
.isThrownBy(() -> httpRequestFunction.apply(new GenericMessage<>("")))
|
||||
.withMessageContaining("Connection refused");
|
||||
});
|
||||
}
|
||||
|
||||
@@ -182,7 +176,7 @@ public class HttpRequestFunctionTestApplicationTests {
|
||||
runner.withPropertyValues("http.request.url-expression=headers['url']",
|
||||
"http.request.http-method-expression=headers['method']", "http.request.body-expression=headers['body']",
|
||||
"http.request.headers-expression={Accept:'application/json'}")
|
||||
.run(context -> {
|
||||
.run((context) -> {
|
||||
Message<?> message = MessageBuilder.withPayload("")
|
||||
.setHeader("url", url())
|
||||
.setHeader("method", "POST")
|
||||
@@ -190,7 +184,7 @@ public class HttpRequestFunctionTestApplicationTests {
|
||||
.build();
|
||||
|
||||
HttpRequestFunction httpRequestFunction = context.getBean(HttpRequestFunction.class);
|
||||
ResponseEntity responseEntity = (ResponseEntity) httpRequestFunction.apply(message);
|
||||
ResponseEntity<?> responseEntity = (ResponseEntity<?>) httpRequestFunction.apply(message);
|
||||
assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(responseEntity.getBody()).isEqualTo(message.getHeaders().get("body"));
|
||||
assertThat(responseEntity.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_JSON);
|
||||
@@ -212,10 +206,10 @@ public class HttpRequestFunctionTestApplicationTests {
|
||||
.withPropertyValues("http.request..http-method-expression='POST'",
|
||||
"http.request.headers-expression={'Content-Type':'application/octet-stream'}",
|
||||
"http.request.expected-response-type=byte[]")
|
||||
.run(context -> {
|
||||
.run((context) -> {
|
||||
Message<?> message = MessageBuilder.withPayload("hello").build();
|
||||
HttpRequestFunction httpRequestFunction = context.getBean(HttpRequestFunction.class);
|
||||
ResponseEntity responseEntity = (ResponseEntity) httpRequestFunction.apply(message);
|
||||
ResponseEntity<?> responseEntity = (ResponseEntity<?>) httpRequestFunction.apply(message);
|
||||
assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(responseEntity.getBody()).isEqualTo("hello".getBytes());
|
||||
assertThat(responseEntity.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_OCTET_STREAM);
|
||||
@@ -233,11 +227,11 @@ public class HttpRequestFunctionTestApplicationTests {
|
||||
}
|
||||
});
|
||||
runner.withPropertyValues("http.request.http-method-expression=#jsonPath(payload,'$.myMethod')")
|
||||
.run(context -> {
|
||||
.run((context) -> {
|
||||
Message<?> message = MessageBuilder.withPayload("{\"name\":\"Fred\",\"age\":41, \"myMethod\":\"POST\"}")
|
||||
.build();
|
||||
HttpRequestFunction httpRequestFunction = context.getBean(HttpRequestFunction.class);
|
||||
ResponseEntity responseEntity = (ResponseEntity) httpRequestFunction.apply(message);
|
||||
ResponseEntity<?> responseEntity = (ResponseEntity<?>) httpRequestFunction.apply(message);
|
||||
assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(responseEntity.getBody()).isEqualTo(message.getPayload());
|
||||
});
|
||||
Reference in New Issue
Block a user