Skip to content

Commit edc7993

Browse files
authored
Merge pull request #4063 from ryanjbaxter/handle-null-body-in-RewriteFunction
2 parents 767fcdb + 34c22e1 commit edc7993

6 files changed

Lines changed: 36 additions & 1 deletion

File tree

spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RemoveJsonAttributesResponseBodyGatewayFilterFactory.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ public GatewayFilter apply(FieldListConfiguration config) {
7272
modifyResponseBodyConfig.setOutClass(String.class);
7373

7474
RewriteFunction<String, String> rewriteFunction = (exchange, body) -> {
75+
if (body == null) {
76+
return Mono.just("");
77+
}
7578
if (MediaType.APPLICATION_JSON.isCompatibleWith(exchange.getResponse().getHeaders().getContentType())) {
7679
try {
7780
JsonNode jsonNode = mapper.readValue(body, JsonNode.class);

spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/rewrite/ModifyRequestBodyGatewayFilterFactory.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@
4545

4646
/**
4747
* GatewayFilter that modifies the request body.
48+
* <p>
49+
* When the request has no body, the {@link RewriteFunction} is invoked with {@code null}
50+
* for the body parameter. Implementations (including Kotlin with a nullable parameter)
51+
* must handle this case.
4852
*/
4953
public class ModifyRequestBodyGatewayFilterFactory
5054
extends AbstractGatewayFilterFactory<ModifyRequestBodyGatewayFilterFactory.Config> {

spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/rewrite/ModifyResponseBodyGatewayFilterFactory.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@
5454

5555
/**
5656
* GatewayFilter that modifies the response body.
57+
* <p>
58+
* When the response has no body, the {@link RewriteFunction} is invoked with {@code null}
59+
* for the body parameter. Implementations (including Kotlin with a nullable parameter)
60+
* must handle this case.
5761
*/
5862
public class ModifyResponseBodyGatewayFilterFactory
5963
extends AbstractGatewayFilterFactory<ModifyResponseBodyGatewayFilterFactory.Config> {

spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/rewrite/RewriteFunction.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,20 @@
1818

1919
import java.util.function.BiFunction;
2020

21+
import org.jspecify.annotations.Nullable;
2122
import org.reactivestreams.Publisher;
2223

2324
import org.springframework.web.server.ServerWebExchange;
2425

2526
/**
2627
* This interface is BETA and may be subject to change in a future release.
2728
*
28-
* @param <T> the type of the first argument to the function
29+
* @param <T> the type of the request/response body (may be null when there is no body)
2930
* @param <R> the type of element signaled by the {@link Publisher}
3031
*/
3132
public interface RewriteFunction<T, R> extends BiFunction<ServerWebExchange, T, Publisher<R>> {
3233

34+
@Override
35+
Publisher<R> apply(ServerWebExchange exchange, @Nullable T body);
36+
3337
}

spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/route/builder/GatewayFilterSpec.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,9 @@ public GatewayFilterSpec mapRequestHeader(String fromHeader, String toHeader) {
307307

308308
/**
309309
* A filter that can be used to modify the request body.
310+
* <p>
311+
* The rewrite function may receive {@code null} for the body when the request has no
312+
* body; implementations must handle this (e.g. use a nullable type in Kotlin).
310313
* @param inClass the class to convert the incoming request body to
311314
* @param outClass the class the Gateway will add to the request before it is routed
312315
* @param rewriteFunction the {@link RewriteFunction} that transforms the request body

spring-cloud-gateway-server-webflux/src/test/java/org/springframework/cloud/gateway/route/builder/GatewayFilterSpecTests.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
2626
import org.springframework.cloud.gateway.filter.NettyWriteResponseFilter;
2727
import org.springframework.cloud.gateway.filter.OrderedGatewayFilter;
28+
import org.springframework.cloud.gateway.filter.factory.rewrite.ModifyRequestBodyGatewayFilterFactory;
2829
import org.springframework.cloud.gateway.filter.factory.rewrite.ModifyResponseBodyGatewayFilterFactory;
2930
import org.springframework.cloud.gateway.route.Route;
3031
import org.springframework.context.ConfigurableApplicationContext;
@@ -104,6 +105,22 @@ public void testFilters() {
104105
assertFilter(route.getFilters().get(1), MyOrderedFilter.class, 1000);
105106
}
106107

108+
@Test
109+
public void shouldSetModifyBodyRequestFilterWithRewriteFunctionAndEmptyBodySupplier() {
110+
ConfigurableApplicationContext context = mock(ConfigurableApplicationContext.class);
111+
Route.AsyncBuilder routeBuilder = Route.async().id("123").uri("abc:123").predicate(exchange -> true);
112+
113+
when(context.getBean(ModifyRequestBodyGatewayFilterFactory.class))
114+
.thenReturn(new ModifyRequestBodyGatewayFilterFactory());
115+
116+
RouteLocatorBuilder.Builder routes = new RouteLocatorBuilder(context).routes();
117+
GatewayFilterSpec spec = new GatewayFilterSpec(routeBuilder, routes);
118+
spec.modifyRequestBody(String.class, String.class, (exchange, s) -> Mono.just(s == null ? "emptybody" : s));
119+
120+
Route route = routeBuilder.build();
121+
assertThat(route.getFilters()).hasSize(1);
122+
}
123+
107124
@Test
108125
public void shouldSetModifyBodyResponseFilterWithRewriteFunction() {
109126
ConfigurableApplicationContext context = mock(ConfigurableApplicationContext.class);

0 commit comments

Comments
 (0)