Skip to content

Commit 35c6384

Browse files
committed
Avoids NPE in MvcUtils
This was caused if vanilla RouterFunctions.route() was used rather than GatewayRouterFunctions Fixes gh-3265
1 parent d76a48d commit 35c6384

File tree

2 files changed

+87
-1
lines changed

2 files changed

+87
-1
lines changed

spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/MvcUtils.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import java.util.Arrays;
2525
import java.util.Collection;
2626
import java.util.Collections;
27+
import java.util.HashMap;
2728
import java.util.List;
2829
import java.util.Map;
2930
import java.util.Optional;
@@ -157,7 +158,9 @@ public static <T> T getAttribute(ServerRequest request, String key) {
157158
public static Map<String, Object> getGatewayAttributes(ServerRequest request) {
158159
// This map is made in GatewayDelegatingRouterFunction.route() and persists across
159160
// attribute resetting in RequestPredicates
160-
Map<String, Object> attributes = (Map<String, Object>) request.attributes().get(GATEWAY_ATTRIBUTES_ATTR);
161+
// computeIfAbsent if the used vanilla RouterFunctions.route()
162+
Map<String, Object> attributes = (Map<String, Object>) request.attributes()
163+
.computeIfAbsent(GATEWAY_ATTRIBUTES_ATTR, s -> new HashMap<String, Object>());
161164
return attributes;
162165
}
163166

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*
2+
* Copyright 2013-2023 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.cloud.gateway.server.mvc;
18+
19+
import java.util.Map;
20+
21+
import org.junit.jupiter.api.Test;
22+
23+
import org.springframework.beans.factory.annotation.Autowired;
24+
import org.springframework.boot.SpringBootConfiguration;
25+
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
26+
import org.springframework.boot.test.context.SpringBootTest;
27+
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
28+
import org.springframework.boot.test.web.server.LocalServerPort;
29+
import org.springframework.cloud.gateway.server.mvc.test.HttpbinTestcontainers;
30+
import org.springframework.cloud.gateway.server.mvc.test.HttpbinUriResolver;
31+
import org.springframework.cloud.gateway.server.mvc.test.TestLoadBalancerConfig;
32+
import org.springframework.cloud.gateway.server.mvc.test.client.TestRestClient;
33+
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient;
34+
import org.springframework.context.annotation.Bean;
35+
import org.springframework.test.context.ContextConfiguration;
36+
import org.springframework.web.servlet.function.RouterFunction;
37+
import org.springframework.web.servlet.function.RouterFunctions;
38+
import org.springframework.web.servlet.function.ServerResponse;
39+
40+
import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.modifyRequestBody;
41+
import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http;
42+
import static org.springframework.cloud.gateway.server.mvc.predicate.GatewayRequestPredicates.host;
43+
44+
@SuppressWarnings("unchecked")
45+
@SpringBootTest(properties = { "spring.cloud.gateway.mvc.http-client.type=jdk" },
46+
webEnvironment = WebEnvironment.RANDOM_PORT)
47+
@ContextConfiguration(initializers = HttpbinTestcontainers.class)
48+
public class VanillaRouterFunctionTests {
49+
50+
@LocalServerPort
51+
int port;
52+
53+
@Autowired
54+
TestRestClient restClient;
55+
56+
@SuppressWarnings("rawtypes")
57+
@Test
58+
public void routerFunctionsRouteWorks() {
59+
restClient.post().uri("/anything/routerfunctionsroute").header("Host", "www.routerfunctionsroute.org")
60+
.bodyValue("hello").exchange().expectStatus().isOk().expectBody(Map.class).consumeWith(result -> {
61+
System.out.println();
62+
});
63+
}
64+
65+
@SpringBootConfiguration
66+
@EnableAutoConfiguration
67+
@LoadBalancerClient(name = "httpbin", configuration = TestLoadBalancerConfig.Httpbin.class)
68+
protected static class TestConfiguration {
69+
70+
@Bean
71+
public RouterFunction<ServerResponse> routerFunctionsRoute() {
72+
// @formatter:off
73+
return RouterFunctions.route()
74+
.POST("/anything/routerfunctionsroute", host("**.routerfunctionsroute.org"), http())
75+
.before(modifyRequestBody(String.class, String.class, null, (request, s) -> s.toUpperCase()))
76+
.before(new HttpbinUriResolver())
77+
.build();
78+
// @formatter:on
79+
}
80+
81+
}
82+
83+
}

0 commit comments

Comments
 (0)