Skip to content

Commit 4d76aa9

Browse files
committed
NullAway changes for server-webmvc
1 parent 7e9825d commit 4d76aa9

32 files changed

+236
-119
lines changed

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,8 @@ public int getOrder() {
8585
}
8686

8787
@Override
88-
// TODO remove this suppress warnings once the commons changes are merged in for CompletionContext
88+
// TODO remove this suppress warnings once the commons changes are merged in for
89+
// CompletionContext
8990
@SuppressWarnings("NullAway")
9091
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
9192
URI url = exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR);

spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfiguration.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package org.springframework.cloud.gateway.server.mvc;
1818

1919
import java.util.Map;
20+
import java.util.Objects;
2021

2122
import org.springframework.beans.factory.BeanFactory;
2223
import org.springframework.beans.factory.ObjectProvider;
@@ -130,6 +131,7 @@ public FormFilter formFilter() {
130131
@ConditionalOnMissingBean
131132
@Conditional(TrustedProxies.ForwardedTrustedProxiesCondition.class)
132133
public ForwardedRequestHeadersFilter forwardedRequestHeadersFilter(GatewayMvcProperties properties) {
134+
Objects.requireNonNull(properties.getTrustedProxies(), "trustedProxies must not be null");
133135
return new ForwardedRequestHeadersFilter(properties.getTrustedProxies());
134136
}
135137

@@ -207,6 +209,7 @@ public WeightCalculatorFilter weightCalculatorFilter() {
207209
@Conditional(TrustedProxies.XForwardedTrustedProxiesCondition.class)
208210
public XForwardedRequestHeadersFilter xForwardedRequestHeadersFilter(XForwardedRequestHeadersFilterProperties props,
209211
GatewayMvcProperties gatewayMvcProperties) {
212+
Objects.requireNonNull(gatewayMvcProperties.getTrustedProxies(), "trustedProxies must not be null");
210213
return new XForwardedRequestHeadersFilter(props, gatewayMvcProperties.getTrustedProxies());
211214
}
212215

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

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,11 @@ public static String expand(ServerRequest request, String template) {
152152
}
153153
Map<String, Object> variables = getUriTemplateVariables(request);
154154
try {
155-
return UriComponentsBuilder.fromPath(template).build().expand(variables).getPath();
155+
String path = UriComponentsBuilder.fromPath(template).build().expand(variables).getPath();
156+
if (path == null) {
157+
return template;
158+
}
159+
return path;
156160
}
157161
catch (IllegalArgumentException e) {
158162
log.trace(LogMessage.format("unable to find substitution for %s", template), e);
@@ -207,8 +211,15 @@ public static Map<String, Object> getUriTemplateVariables(ServerRequest request)
207211
}
208212

209213
public static void putAttribute(ServerRequest request, String key, @Nullable Object value) {
210-
request.attributes().put(key, value);
211-
getGatewayAttributes(request).put(key, value);
214+
if (value == null) {
215+
request.attributes().remove(key);
216+
getGatewayAttributes(request).remove(key);
217+
}
218+
else {
219+
request.attributes().put(key, value);
220+
getGatewayAttributes(request).put(key, value);
221+
}
222+
212223
}
213224

214225
@SuppressWarnings("unchecked")
@@ -219,7 +230,7 @@ public static void putUriTemplateVariables(ServerRequest request, Map<String, St
219230
}
220231

221232
// TODO: replace with CollectionUtils.compositeMap in 4.2.x (Framework 6.2, boot 3.4)
222-
public static <K, V> Map<K, V> mergeMaps(Map<K, V> left, Map<K, V> right) {
233+
public static <K, V> Map<K, V> mergeMaps(@Nullable Map<K, V> left, @Nullable Map<K, V> right) {
223234
if (CollectionUtils.isEmpty(left)) {
224235
if (CollectionUtils.isEmpty(right)) {
225236
return Collections.emptyMap();
@@ -259,9 +270,15 @@ public static <T> Optional<T> readBody(ServerRequest request, ByteArrayInputStre
259270
return Optional.empty();
260271
}
261272

262-
public static void setRouteId(ServerRequest request, String routeId) {
263-
request.attributes().put(GATEWAY_ROUTE_ID_ATTR, routeId);
264-
request.servletRequest().setAttribute(GATEWAY_ROUTE_ID_ATTR, routeId);
273+
public static void setRouteId(ServerRequest request, @Nullable String routeId) {
274+
if (routeId == null) {
275+
request.attributes().remove(GATEWAY_ROUTE_ID_ATTR);
276+
request.servletRequest().removeAttribute(GATEWAY_ROUTE_ID_ATTR);
277+
}
278+
else {
279+
request.attributes().put(GATEWAY_ROUTE_ID_ATTR, routeId);
280+
request.servletRequest().setAttribute(GATEWAY_ROUTE_ID_ATTR, routeId);
281+
}
265282
}
266283

267284
public static void setRequestUrl(ServerRequest request, URI url) {

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public class WeightConfig {
3232
public static final String CONFIG_PREFIX = "weight";
3333

3434
@NotEmpty
35-
private String group;
35+
private @Nullable String group;
3636

3737
private @Nullable String routeId;
3838

@@ -52,7 +52,7 @@ public WeightConfig(String routeId) {
5252
this.routeId = routeId;
5353
}
5454

55-
public String getGroup() {
55+
public @Nullable String getGroup() {
5656
return group;
5757
}
5858

spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/FilterProperties.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.util.Objects;
2222

2323
import jakarta.validation.constraints.NotNull;
24+
import org.jspecify.annotations.Nullable;
2425

2526
import org.springframework.cloud.gateway.server.mvc.common.NameUtils;
2627
import org.springframework.validation.annotation.Validated;
@@ -34,7 +35,7 @@
3435
public class FilterProperties {
3536

3637
@NotNull
37-
private String name;
38+
private @Nullable String name;
3839

3940
private Map<String, String> args = new LinkedHashMap<>();
4041

@@ -56,7 +57,7 @@ public FilterProperties(String text) {
5657
}
5758
}
5859

59-
public String getName() {
60+
public @Nullable String getName() {
6061
return name;
6162
}
6263

spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/GatewayMvcProperties.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
import jakarta.validation.Valid;
2525
import jakarta.validation.constraints.NotNull;
26+
import org.jspecify.annotations.Nullable;
2627

2728
import org.springframework.boot.context.properties.ConfigurationProperties;
2829
import org.springframework.core.style.ToStringCreator;
@@ -66,7 +67,7 @@ public class GatewayMvcProperties {
6667
* Regular expression defining proxies that are trusted when they appear in a
6768
* Forwarded of X-Forwarded header.
6869
*/
69-
private String trustedProxies;
70+
private @Nullable String trustedProxies;
7071

7172
/**
7273
* In the case where Spring Retry is on the classpath but you still want to use Spring
@@ -114,7 +115,7 @@ public void setStreamingBufferSize(int streamingBufferSize) {
114115
this.streamingBufferSize = streamingBufferSize;
115116
}
116117

117-
public String getTrustedProxies() {
118+
public @Nullable String getTrustedProxies() {
118119
return trustedProxies;
119120
}
120121

spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/GatewayMvcRuntimeHintsProcessor.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
import org.apache.commons.logging.Log;
2929
import org.apache.commons.logging.LogFactory;
30+
import org.jspecify.annotations.Nullable;
3031

3132
import org.springframework.aot.hint.MemberCategory;
3233
import org.springframework.aot.hint.ReflectionHints;
@@ -106,7 +107,7 @@ private static Set<Class<?>> getTypesToRegister(String packageName) {
106107
return classesToAdd.stream().filter(Objects::nonNull).collect(Collectors.toSet());
107108
}
108109

109-
private static void addEnclosingClassesForClass(Set<Class<?>> enclosingClasses, Class<?> clazz) {
110+
private static void addEnclosingClassesForClass(Set<Class<?>> enclosingClasses, @Nullable Class<?> clazz) {
110111
if (clazz == null) {
111112
return;
112113
}

spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/PredicateProperties.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
import jakarta.validation.ValidationException;
2424
import jakarta.validation.constraints.NotNull;
25+
import org.jspecify.annotations.Nullable;
2526

2627
import org.springframework.cloud.gateway.server.mvc.common.NameUtils;
2728
import org.springframework.validation.annotation.Validated;
@@ -35,7 +36,7 @@
3536
public class PredicateProperties {
3637

3738
@NotNull
38-
private String name;
39+
private @Nullable String name;
3940

4041
private Map<String, String> args = new LinkedHashMap<>();
4142

@@ -57,7 +58,7 @@ public PredicateProperties(String text) {
5758
}
5859
}
5960

60-
public String getName() {
61+
public @Nullable String getName() {
6162
return name;
6263
}
6364

spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/RouteProperties.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import jakarta.validation.ValidationException;
2828
import jakarta.validation.constraints.NotEmpty;
2929
import jakarta.validation.constraints.NotNull;
30+
import org.jspecify.annotations.Nullable;
3031

3132
import org.springframework.validation.annotation.Validated;
3233

@@ -41,7 +42,7 @@ public class RouteProperties {
4142
/**
4243
* The Route ID.
4344
*/
44-
private String id;
45+
private @Nullable String id;
4546

4647
/**
4748
* List of predicates for matching the Route.
@@ -60,7 +61,7 @@ public class RouteProperties {
6061
* The destination URI.
6162
*/
6263
@NotNull
63-
private URI uri;
64+
private @Nullable URI uri;
6465

6566
/**
6667
* Metadata associated with the Route.
@@ -93,7 +94,7 @@ public RouteProperties(String text) {
9394
}
9495
}
9596

96-
public String getId() {
97+
public @Nullable String getId() {
9798
return id;
9899
}
99100

@@ -117,7 +118,7 @@ public void setFilters(List<FilterProperties> filters) {
117118
this.filters = filters;
118119
}
119120

120-
public URI getUri() {
121+
public @Nullable URI getUri() {
121122
return uri;
122123
}
123124

spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/RouterFunctionHolderFactory.java

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,15 @@
2525
import java.util.List;
2626
import java.util.Locale;
2727
import java.util.Map;
28+
import java.util.Objects;
2829
import java.util.Optional;
2930
import java.util.concurrent.atomic.AtomicReference;
3031
import java.util.function.Consumer;
3132
import java.util.function.Function;
3233

3334
import org.apache.commons.logging.Log;
3435
import org.apache.commons.logging.LogFactory;
36+
import org.jspecify.annotations.Nullable;
3537

3638
import org.springframework.beans.factory.BeanFactory;
3739
import org.springframework.beans.factory.BeanNotOfRequiredTypeException;
@@ -153,6 +155,7 @@ private GatewayMvcPropertiesBeanDefinitionRegistrar.RouterFunctionHolder routerF
153155

154156
Map<String, RouterFunction> routerFunctions = new LinkedHashMap<>();
155157
properties.getRoutes().forEach(routeProperties -> {
158+
Objects.requireNonNull(routeProperties.getId(), "Route id is required");
156159
routerFunctions.put(routeProperties.getId(), getRouterFunction(routeProperties, routeProperties.getId()));
157160
});
158161
properties.getRoutesMap().forEach((routeId, routeProperties) -> {
@@ -171,6 +174,7 @@ private GatewayMvcPropertiesBeanDefinitionRegistrar.RouterFunctionHolder routerF
171174
routerFunction = routerFunctions.values().stream().reduce(RouterFunction::andOther).orElse(null);
172175
// puts the map of configured RouterFunctions in an attribute. Makes testing
173176
// easy.
177+
Objects.requireNonNull(routerFunction, "Unable to create RouterFunction");
174178
routerFunction = routerFunction.withAttribute("gatewayRouterFunctions", routerFunctions);
175179
}
176180
log.trace(LogMessage.format("RouterFunctionHolder initialized %s", routerFunction.toString()));
@@ -186,7 +190,11 @@ private RouterFunction getRouterFunction(RouteProperties routeProperties, String
186190
MultiValueMap<String, OperationMethod> handlerOperations = handlerDiscoverer.getOperations();
187191
// TODO: cache?
188192
// translate handlerFunction
189-
String scheme = routeProperties.getUri().getScheme();
193+
194+
String scheme = "http";
195+
if (routeProperties.getUri() != null && routeProperties.getUri().getScheme() != null) {
196+
scheme = routeProperties.getUri().getScheme();
197+
}
190198

191199
// filters added by HandlerDiscoverer need to go last, so save them
192200
HandlerFunction<ServerResponse> handlerFunction = null;
@@ -246,7 +254,7 @@ else if (response instanceof HandlerDiscoverer.Result result) {
246254
predicateOperations.addAll(predicateBeanFactoryDiscoverer.getOperations());
247255
}
248256
predicateOperations.addAll(predicateDiscoverer.getOperations());
249-
final AtomicReference<RequestPredicate> predicate = new AtomicReference<>();
257+
final AtomicReference<@Nullable RequestPredicate> predicate = new AtomicReference<>();
250258

251259
routeProperties.getPredicates().forEach(predicateProperties -> {
252260
Map<String, Object> args = new LinkedHashMap<>(predicateProperties.getArgs());
@@ -265,7 +273,8 @@ else if (response instanceof HandlerDiscoverer.Result result) {
265273
});
266274

267275
// combine predicate and handlerFunction
268-
builder.route(predicate.get(), handlerFunction);
276+
RequestPredicate check = Objects.requireNonNull(predicate.get(), "Unable to create RequestPredicate");
277+
builder.route(check, handlerFunction);
269278
predicate.set(null);
270279

271280
// HandlerDiscoverer filters needing lower priority, so put them first
@@ -290,9 +299,12 @@ else if (response instanceof HandlerDiscoverer.Result result) {
290299
return builder.build();
291300
}
292301

293-
private <T> void translate(MultiValueMap<String, OperationMethod> operations, String operationName,
302+
private <T> void translate(MultiValueMap<String, OperationMethod> operations, @Nullable String operationName,
294303
Map<String, Object> operationArgs, Class<T> returnType, Consumer<T> operationHandler) {
295-
String normalizedName = StringUtils.uncapitalize(operationName);
304+
String normalizedName = operationName;
305+
if (operationName != null) {
306+
normalizedName = StringUtils.uncapitalize(operationName);
307+
}
296308
Optional<NormalizedOperationMethod> operationMethod = findOperation(operations, normalizedName, operationArgs);
297309
if (operationMethod.isPresent()) {
298310
NormalizedOperationMethod opMethod = operationMethod.get();
@@ -313,7 +325,7 @@ private <T> void translate(MultiValueMap<String, OperationMethod> operations, St
313325
}
314326

315327
private Optional<NormalizedOperationMethod> findOperation(MultiValueMap<String, OperationMethod> operations,
316-
String operationName, Map<String, Object> operationArgs) {
328+
@Nullable String operationName, Map<String, Object> operationArgs) {
317329
return operations.getOrDefault(operationName, Collections.emptyList())
318330
.stream()
319331
.sorted(Comparator.comparing(OperationMethod::isConfigurable))
@@ -381,7 +393,7 @@ public boolean canResolve(Class<?> type) {
381393
}
382394

383395
@Override
384-
public <T> T resolve(Class<T> type) {
396+
public @Nullable <T> T resolve(Class<T> type) {
385397
return null;
386398
}
387399

0 commit comments

Comments
 (0)