From 7e9825d9839483b9941032ae083a09f2ac9c2288 Mon Sep 17 00:00:00 2001 From: Ryan Baxter Date: Wed, 19 Nov 2025 20:22:11 -0500 Subject: [PATCH 1/3] NullAway changes for webflux-server More nullaway changes Fix mroe changes More changes Null changes More null changes Next commit Next batch --- .mvn/maven.config | 1 + pom.xml | 1 - .../cloud/gateway/webflux/ProxyExchange.java | 57 ++++++---- .../cloud/gateway/mvc/ProxyExchange.java | 105 +++++++++++++----- .../config/ProxyExchangeArgumentResolver.java | 18 ++- ...DiscoveryClientRouteDefinitionLocator.java | 32 ++++-- .../discovery/DiscoveryLocatorProperties.java | 6 +- .../gateway/event/RefreshRoutesEvent.java | 3 +- .../event/RefreshRoutesResultEvent.java | 6 +- .../filter/AdaptCachedBodyGlobalFilter.java | 7 +- .../gateway/filter/FilterDefinition.java | 7 +- .../gateway/filter/ForwardPathFilter.java | 15 ++- .../gateway/filter/ForwardRoutingFilter.java | 12 +- ...adBalancerServiceInstanceCookieFilter.java | 9 +- .../gateway/filter/NettyRoutingFilter.java | 17 +-- .../filter/NettyWriteResponseFilter.java | 6 +- .../ReactiveLoadBalancerClientFilter.java | 4 + .../filter/WebsocketRoutingFilter.java | 7 +- .../filter/WeightCalculatorWebFilter.java | 3 +- .../CorsGatewayFilterApplicationListener.java | 7 +- .../factory/AbstractGatewayFilterFactory.java | 12 +- ...AbstractNameValueGatewayFilterFactory.java | 9 +- .../AddRequestHeaderGatewayFilterFactory.java | 12 +- ...dRequestParameterGatewayFilterFactory.java | 11 +- ...AddResponseHeaderGatewayFilterFactory.java | 19 ++-- .../CacheRequestBodyGatewayFilterFactory.java | 9 +- ...upeResponseHeaderGatewayFilterFactory.java | 3 +- .../FallbackHeadersGatewayFilterFactory.java | 17 ++- .../filter/factory/GatewayFilterFactory.java | 6 +- .../JsonToGrpcGatewayFilterFactory.java | 20 ++-- .../MapRequestHeaderGatewayFilterFactory.java | 28 +++-- .../PrefixPathGatewayFilterFactory.java | 9 +- .../RedirectToGatewayFilterFactory.java | 14 ++- ...butesResponseBodyGatewayFilterFactory.java | 10 +- ...moveRequestHeaderGatewayFilterFactory.java | 7 +- ...oveResponseHeaderGatewayFilterFactory.java | 7 +- ...RequestHeaderSizeGatewayFilterFactory.java | 5 +- ...eaderToRequestUriGatewayFilterFactory.java | 8 +- ...equestRateLimiterGatewayFilterFactory.java | 27 +++-- .../factory/RetryGatewayFilterFactory.java | 24 ++-- ...ionResponseHeaderGatewayFilterFactory.java | 5 +- .../RewritePathGatewayFilterFactory.java | 19 ++-- ...eRequestParameterGatewayFilterFactory.java | 22 ++-- ...iteResponseHeaderGatewayFilterFactory.java | 18 +-- .../SecureHeadersGatewayFilterFactory.java | 66 +++++------ .../factory/SetPathGatewayFilterFactory.java | 9 +- .../SetRequestHeaderGatewayFilterFactory.java | 9 +- ...RequestHostHeaderGatewayFilterFactory.java | 9 +- .../SetRequestUriGatewayFilterFactory.java | 12 +- ...SetResponseHeaderGatewayFilterFactory.java | 9 +- .../SetStatusGatewayFilterFactory.java | 15 ++- ...pringCloudCircuitBreakerFilterFactory.java | 30 ++--- .../TokenRelayGatewayFilterFactory.java | 5 +- .../filter/factory/cache/CachedResponse.java | 4 +- ...ocalResponseCacheGatewayFilterFactory.java | 19 ++-- .../cache/LocalResponseCacheProperties.java | 7 +- .../factory/cache/ResponseCacheManager.java | 5 +- .../rewrite/CachedBodyOutputMessage.java | 3 +- ...ModifyRequestBodyGatewayFilterFactory.java | 33 +++--- ...odifyResponseBodyGatewayFilterFactory.java | 44 ++++---- .../headers/ForwardedHeadersFilter.java | 29 +++-- .../headers/GRPCRequestHeadersFilter.java | 4 +- .../headers/GRPCResponseHeadersFilter.java | 3 +- .../filter/headers/HttpHeadersFilter.java | 6 +- .../headers/XForwardedHeadersFilter.java | 16 ++- .../DefaultGatewayObservationConvention.java | 17 ++- .../ObservedRequestHttpHeadersFilter.java | 1 + .../filter/ratelimit/AbstractRateLimiter.java | 6 +- .../filter/ratelimit/Bucket4jRateLimiter.java | 15 +-- .../filter/ratelimit/RedisRateLimiter.java | 16 ++- .../handler/RoutePredicateHandlerMapping.java | 7 +- .../predicate/AfterRoutePredicateFactory.java | 5 +- .../BeforeRoutePredicateFactory.java | 5 +- .../BetweenRoutePredicateFactory.java | 10 +- .../CookieRoutePredicateFactory.java | 11 +- .../HeaderRoutePredicateFactory.java | 14 ++- .../predicate/HostRoutePredicateFactory.java | 4 + .../MethodRoutePredicateFactory.java | 4 +- .../predicate/PathRoutePredicateFactory.java | 4 +- .../predicate/PredicateDefinition.java | 7 +- .../predicate/QueryRoutePredicateFactory.java | 17 +-- .../ReadBodyRoutePredicateFactory.java | 20 ++-- .../VersionRoutePredicateFactory.java | 23 ++-- .../WeightRoutePredicateFactory.java | 7 +- ...wardedRemoteAddrRoutePredicateFactory.java | 5 +- .../gateway/route/CachingRouteLocator.java | 6 +- .../route/RedisRouteDefinitionRepository.java | 24 ++-- .../cloud/gateway/route/Route.java | 36 ++++-- .../cloud/gateway/route/RouteDefinition.java | 11 +- .../route/RouteDefinitionRouteLocator.java | 10 +- .../ratelimit/RedisRateLimiterUnitTests.java | 4 - .../application-disable-components.yml | 6 +- .../application-netty-routing-filter.yml | 7 +- .../src/test/resources/application.yml | 7 +- 94 files changed, 811 insertions(+), 479 deletions(-) diff --git a/.mvn/maven.config b/.mvn/maven.config index a682990566..2231dc03c1 100644 --- a/.mvn/maven.config +++ b/.mvn/maven.config @@ -1 +1,2 @@ +-Djspecify.enabled=true -P spring diff --git a/pom.xml b/pom.xml index 959e8164a8..10771fd98f 100644 --- a/pom.xml +++ b/pom.xml @@ -62,7 +62,6 @@ UTF-8 UTF-8 - true 8.15.0 1.0.8.RELEASE 17 diff --git a/spring-cloud-gateway-proxyexchange-webflux/src/main/java/org/springframework/cloud/gateway/webflux/ProxyExchange.java b/spring-cloud-gateway-proxyexchange-webflux/src/main/java/org/springframework/cloud/gateway/webflux/ProxyExchange.java index 8f2673ed72..820011b25a 100644 --- a/spring-cloud-gateway-proxyexchange-webflux/src/main/java/org/springframework/cloud/gateway/webflux/ProxyExchange.java +++ b/spring-cloud-gateway-proxyexchange-webflux/src/main/java/org/springframework/cloud/gateway/webflux/ProxyExchange.java @@ -27,6 +27,7 @@ import java.util.function.Function; import java.util.stream.Collectors; +import org.jspecify.annotations.Nullable; import org.reactivestreams.Publisher; import reactor.core.publisher.Mono; @@ -40,6 +41,7 @@ import org.springframework.http.RequestEntity.BodyBuilder; import org.springframework.http.ResponseEntity; import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.util.Assert; import org.springframework.util.StringUtils; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.RequestBody; @@ -121,11 +123,11 @@ public class ProxyExchange { private HttpMethod httpMethod; - private URI uri; + private @Nullable URI uri; private WebClient rest; - private Publisher body; + private @Nullable Publisher body; private boolean hasBody = false; @@ -133,7 +135,7 @@ public class ProxyExchange { private BindingContext bindingContext; - private Set excluded; + private @Nullable Set excluded; private HttpHeaders headers = new HttpHeaders(); @@ -244,6 +246,7 @@ public String path(String prefix) { } public Mono> get() { + Assert.notNull(uri, "URI must not be null"); RequestEntity requestEntity = headers((BodyBuilder) RequestEntity.get(uri)).build(); return exchange(requestEntity); } @@ -253,6 +256,7 @@ public Mono> get(Function, ResponseEntit } public Mono> head() { + Assert.notNull(uri, "URI must not be null"); RequestEntity requestEntity = headers((BodyBuilder) RequestEntity.head(uri)).build(); return exchange(requestEntity); } @@ -262,6 +266,7 @@ public Mono> head(Function, ResponseEnti } public Mono> options() { + Assert.notNull(uri, "URI must not be null"); RequestEntity requestEntity = headers((BodyBuilder) RequestEntity.options(uri)).build(); return exchange(requestEntity); } @@ -271,8 +276,7 @@ public Mono> options(Function, ResponseE } public Mono> post() { - RequestEntity requestEntity = headers(RequestEntity.post(uri)).body(body()); - return exchange(requestEntity); + return doExchange(RequestEntity::post); } public Mono> post(Function, ResponseEntity> converter) { @@ -280,8 +284,7 @@ public Mono> post(Function, ResponseEnti } public Mono> delete() { - RequestEntity requestEntity = headers((BodyBuilder) RequestEntity.delete(uri)).body(body()); - return exchange(requestEntity); + return doExchange(uri -> (BodyBuilder) RequestEntity.delete(uri)); } public Mono> delete(Function, ResponseEntity> converter) { @@ -289,7 +292,14 @@ public Mono> delete(Function, ResponseEn } public Mono> put() { - RequestEntity requestEntity = headers(RequestEntity.put(uri)).body(body()); + return doExchange(RequestEntity::put); + } + + private Mono> doExchange(Function getBodyBuilder) { + Assert.notNull(uri, "URI must not be null"); + BodyBuilder bodyBuilder = headers(getBodyBuilder.apply(uri)); + Publisher body = body(); + RequestEntity requestEntity = body != null ? bodyBuilder.body(body) : bodyBuilder.build(); return exchange(requestEntity); } @@ -298,8 +308,7 @@ public Mono> put(Function, ResponseEntit } public Mono> patch() { - RequestEntity requestEntity = headers(RequestEntity.patch(uri)).body(body()); - return exchange(requestEntity); + return doExchange(RequestEntity::patch); } public Mono> patch(Function, ResponseEntity> converter) { @@ -360,6 +369,7 @@ else if (httpMethod.equals(HttpMethod.PATCH)) { private Mono> exchange(RequestEntity requestEntity) { Type type = this.responseType; + Assert.notNull(requestEntity.getMethod(), "Method must not be null"); RequestBodySpec builder = rest.method(requestEntity.getMethod()) .uri(requestEntity.getUrl()) .headers(headers -> addHeaders(headers, requestEntity.getHeaders())); @@ -388,9 +398,12 @@ else if (requestEntity.getBody() != null) { private void addHeaders(HttpHeaders headers, HttpHeaders toAdd) { Set filteredKeys = filterHeaderKeys(toAdd); - filteredKeys.stream() - .filter(key -> !headers.containsHeader(key)) - .forEach(header -> headers.addAll(header, toAdd.get(header))); + filteredKeys.stream().filter(key -> !headers.containsHeader(key)).forEach(header -> { + java.util.List headerValues = toAdd.get(header); + if (headerValues != null) { + headers.addAll(header, headerValues); + } + }); } private Set filterHeaderKeys(HttpHeaders headers) { @@ -404,7 +417,10 @@ private Set filterHeaderKeys(HttpHeaders headers) { private BodyBuilder headers(BodyBuilder builder) { proxy(); for (String name : filterHeaderKeys(headers)) { - builder.header(name, headers.get(name).toArray(new String[0])); + java.util.List headerValues = headers.get(name); + if (headerValues != null) { + builder.header(name, headerValues.toArray(new String[0])); + } } return builder; } @@ -443,7 +459,7 @@ private void appendForwarded(URI uri) { headers.set("forwarded", forwarded); } - private String forwarded(URI uri, String hostHeader) { + private String forwarded(URI uri, @Nullable String hostHeader) { if (StringUtils.hasText(hostHeader)) { return "host=" + hostHeader; } @@ -453,7 +469,7 @@ private String forwarded(URI uri, String hostHeader) { return String.format("host=%s;proto=%s", uri.getHost(), uri.getScheme()); } - private Publisher body() { + private @Nullable Publisher body() { Publisher body = this.body; if (body != null) { return body; @@ -469,11 +485,14 @@ private Publisher body() { * that it would have been for a @RequestBody. * @return the request body */ - private Mono getRequestBody() { + private @Nullable Mono getRequestBody() { for (String key : bindingContext.getModel().asMap().keySet()) { if (key.startsWith(BindingResult.MODEL_KEY_PREFIX)) { BindingResult result = (BindingResult) bindingContext.getModel().asMap().get(key); - return Mono.just(result.getTarget()); + Object target = result.getTarget(); + if (target != null) { + return Mono.just(target); + } } } return null; @@ -490,7 +509,7 @@ public Publisher body(@RequestBody Publisher body) { protected static class BodySender { @ResponseBody - public Publisher body() { + public @Nullable Publisher body() { return null; } diff --git a/spring-cloud-gateway-proxyexchange-webmvc/src/main/java/org/springframework/cloud/gateway/mvc/ProxyExchange.java b/spring-cloud-gateway-proxyexchange-webmvc/src/main/java/org/springframework/cloud/gateway/mvc/ProxyExchange.java index 90904a69a4..df2400f497 100644 --- a/spring-cloud-gateway-proxyexchange-webmvc/src/main/java/org/springframework/cloud/gateway/mvc/ProxyExchange.java +++ b/spring-cloud-gateway-proxyexchange-webmvc/src/main/java/org/springframework/cloud/gateway/mvc/ProxyExchange.java @@ -45,6 +45,7 @@ import jakarta.servlet.http.HttpServletRequestWrapper; import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponseWrapper; +import org.jspecify.annotations.Nullable; import org.springframework.core.Conventions; import org.springframework.core.MethodParameter; @@ -55,6 +56,7 @@ import org.springframework.http.ResponseEntity; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.HttpMessageNotWritableException; +import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; import org.springframework.validation.BindingResult; @@ -138,11 +140,11 @@ */ public class ProxyExchange { - private URI uri; + private @Nullable URI uri; private RestTemplate rest; - private Object body; + private @Nullable Object body; private RequestResponseBodyMethodProcessor delegate; @@ -152,7 +154,7 @@ public class ProxyExchange { private WebDataBinderFactory binderFactory; - private Set excluded; + private @Nullable Set excluded; private HttpHeaders headers = new HttpHeaders(); @@ -246,13 +248,16 @@ public ProxyExchange uri(String uri) { } } - public String path() { + public @Nullable String path() { return (String) this.webRequest.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, WebRequest.SCOPE_REQUEST); } - public String path(String prefix) { + public @Nullable String path(String prefix) { String path = path(); + if (path == null) { + return null; + } if (!path.startsWith(prefix)) { throw new IllegalArgumentException("Path does not start with prefix (" + prefix + "): " + path); } @@ -263,6 +268,8 @@ public void forward(String path) { HttpServletRequest request = this.webRequest.getNativeRequest(HttpServletRequest.class); HttpServletResponse response = this.webRequest.getNativeResponse(HttpServletResponse.class); try { + Assert.notNull(request, "HttpServletRequest is required"); + Assert.notNull(response, "HttpServletResponse is required"); request.getRequestDispatcher(path) .forward(new BodyForwardingHttpServletRequest(request, response), response); } @@ -272,8 +279,15 @@ public void forward(String path) { } public ResponseEntity get() { - RequestEntity requestEntity = headers((BodyBuilder) RequestEntity.get(uri)).body(body()); - return exchange(requestEntity); + Assert.notNull(this.uri, "URI is required"); + Object body = body(); + BodyBuilder builder = headers((BodyBuilder) RequestEntity.get(uri)); + if (body != null) { + return exchange(builder.body(body)); + } + else { + return exchange(builder.build()); + } } public ResponseEntity get(Function, ResponseEntity> converter) { @@ -281,6 +295,7 @@ public ResponseEntity get(Function, ResponseEntity> } public ResponseEntity head() { + Assert.notNull(this.uri, "URI is required"); RequestEntity requestEntity = headers((BodyBuilder) RequestEntity.head(uri)).build(); return exchange(requestEntity); } @@ -290,6 +305,7 @@ public ResponseEntity head(Function, ResponseEntity> } public ResponseEntity options() { + Assert.notNull(this.uri, "URI is required"); RequestEntity requestEntity = headers((BodyBuilder) RequestEntity.options(uri)).build(); return exchange(requestEntity); } @@ -299,8 +315,15 @@ public ResponseEntity options(Function, ResponseEntity< } public ResponseEntity post() { - RequestEntity requestEntity = headers(RequestEntity.post(uri)).body(body()); - return exchange(requestEntity); + Assert.notNull(this.uri, "URI is required"); + Object body = body(); + BodyBuilder builder = headers(RequestEntity.post(uri)); + if (body != null) { + return exchange(builder.body(body)); + } + else { + return exchange(builder.build()); + } } public ResponseEntity post(Function, ResponseEntity> converter) { @@ -308,8 +331,15 @@ public ResponseEntity post(Function, ResponseEntity> } public ResponseEntity delete() { - RequestEntity requestEntity = headers((BodyBuilder) RequestEntity.delete(uri)).body(body()); - return exchange(requestEntity); + Assert.notNull(this.uri, "URI is required"); + Object body = body(); + BodyBuilder builder = headers((BodyBuilder) RequestEntity.delete(uri)); + if (body != null) { + return exchange(builder.body(body)); + } + else { + return exchange(builder.build()); + } } public ResponseEntity delete(Function, ResponseEntity> converter) { @@ -317,8 +347,15 @@ public ResponseEntity delete(Function, ResponseEntity put() { - RequestEntity requestEntity = headers(RequestEntity.put(uri)).body(body()); - return exchange(requestEntity); + Assert.notNull(this.uri, "URI is required"); + Object body = body(); + BodyBuilder builder = headers(RequestEntity.put(uri)); + if (body != null) { + return exchange(builder.body(body)); + } + else { + return exchange(builder.build()); + } } public ResponseEntity put(Function, ResponseEntity> converter) { @@ -326,8 +363,15 @@ public ResponseEntity put(Function, ResponseEntity> } public ResponseEntity patch() { - RequestEntity requestEntity = headers(RequestEntity.patch(uri)).body(body()); - return exchange(requestEntity); + Assert.notNull(this.uri, "URI is required"); + Object body = body(); + BodyBuilder builder = headers(RequestEntity.patch(uri)); + if (body != null) { + return exchange(builder.body(body)); + } + else { + return exchange(builder.build()); + } } public ResponseEntity patch(Function, ResponseEntity> converter) { @@ -354,7 +398,10 @@ private void addHeaders(HttpHeaders headers) { private BodyBuilder headers(BodyBuilder builder) { proxy(); for (String name : filterHeaderKeys(headers)) { - builder.header(name, headers.get(name).toArray(new String[0])); + List values = headers.get(name); + if (values != null) { + builder.header(name, values.toArray(new String[0])); + } } builder.headers(this::addHeaders); return builder; @@ -372,14 +419,15 @@ private Set filterHeaderKeys(Collection headerNames) { } private void proxy() { + HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); + Assert.notNull(request, "Request is required"); try { - URI uri = new URI(webRequest.getNativeRequest(HttpServletRequest.class).getRequestURL().toString()); + URI uri = new URI(request.getRequestURL().toString()); appendForwarded(uri); appendXForwarded(uri); } catch (URISyntaxException e) { - throw new IllegalStateException("Cannot create URI for request: " - + webRequest.getNativeRequest(HttpServletRequest.class).getRequestURL()); + throw new IllegalStateException("Cannot create URI for request: " + request.getRequestURL()); } } @@ -407,7 +455,10 @@ private void appendForwarded(URI uri) { else { forwarded = ""; } - forwarded = forwarded + forwarded(uri, webRequest.getHeader("host")); + String forwardedHeader = webRequest.getHeader("host"); + if (forwardedHeader != null) { + forwarded = forwarded + forwarded(uri, forwardedHeader); + } headers.set("forwarded", forwarded); } @@ -421,7 +472,7 @@ private String forwarded(URI uri, String hostHeader) { return String.format("host=%s;proto=%s", uri.getHost(), uri.getScheme()); } - private Object body() { + private @Nullable Object body() { if (body != null) { return body; } @@ -435,7 +486,7 @@ private Object body() { * that it would have been for a @RequestBody. * @return the request body */ - private Object getRequestBody() { + private @Nullable Object getRequestBody() { for (String key : mavContainer.getModel().keySet()) { if (key.startsWith(BindingResult.MODEL_KEY_PREFIX)) { BindingResult result = (BindingResult) mavContainer.getModel().get(key); @@ -451,6 +502,9 @@ private Object getRequestBody() { } String name = Conventions.getVariableNameForParameter(input); BindingResult result = (BindingResult) mavContainer.getModel().get(BindingResult.MODEL_KEY_PREFIX + name); + if (result == null) { + return null; + } return result.getTarget(); } @@ -465,7 +519,7 @@ public Object body(@RequestBody(required = false) Object body) { protected static class BodySender { @ResponseBody - public Object body() { + public @Nullable Object body() { return null; } @@ -489,9 +543,8 @@ class BodyForwardingHttpServletRequest extends HttpServletRequestWrapper { this.response = response; } - private List header(String name) { - List list = headers.get(name); - return list; + private @Nullable List header(String name) { + return headers.get(name); } @Override diff --git a/spring-cloud-gateway-proxyexchange-webmvc/src/main/java/org/springframework/cloud/gateway/mvc/config/ProxyExchangeArgumentResolver.java b/spring-cloud-gateway-proxyexchange-webmvc/src/main/java/org/springframework/cloud/gateway/mvc/config/ProxyExchangeArgumentResolver.java index 4d85ca734f..646e5d1bf5 100644 --- a/spring-cloud-gateway-proxyexchange-webmvc/src/main/java/org/springframework/cloud/gateway/mvc/config/ProxyExchangeArgumentResolver.java +++ b/spring-cloud-gateway-proxyexchange-webmvc/src/main/java/org/springframework/cloud/gateway/mvc/config/ProxyExchangeArgumentResolver.java @@ -29,6 +29,7 @@ import org.springframework.cloud.gateway.mvc.ProxyExchange; import org.springframework.core.MethodParameter; import org.springframework.http.HttpHeaders; +import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.client.RestTemplate; @@ -75,8 +76,10 @@ public boolean supportsParameter(MethodParameter parameter) { } @Override - public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, - NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { + public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, + NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception { + Assert.notNull(binderFactory, "WebDataBinderFactory is required"); + Assert.notNull(mavContainer, "ModelAndViewContainer is required"); ProxyExchange proxy = new ProxyExchange<>(rest, webRequest, mavContainer, binderFactory, type(parameter)); configureHeaders(proxy); configureAutoForwardedHeaders(proxy, webRequest); @@ -94,12 +97,15 @@ private Type type(MethodParameter parameter) { private HttpHeaders extractAutoForwardedHeaders(NativeWebRequest webRequest) { HttpServletRequest nativeRequest = webRequest.getNativeRequest(HttpServletRequest.class); + Assert.notNull(nativeRequest, "HttpServletRequest is required"); Enumeration headerNames = nativeRequest.getHeaderNames(); HttpHeaders headers = new HttpHeaders(); - while (headerNames.hasMoreElements()) { - String header = headerNames.nextElement(); - if (this.autoForwardedHeaders.contains(header.toLowerCase(Locale.ROOT))) { - headers.addAll(header, Collections.list(nativeRequest.getHeaders(header))); + if (headerNames != null && autoForwardedHeaders != null) { + while (headerNames.hasMoreElements()) { + String header = headerNames.nextElement(); + if (this.autoForwardedHeaders.contains(header.toLowerCase(Locale.ROOT))) { + headers.addAll(header, Collections.list(nativeRequest.getHeaders(header))); + } } } return headers; diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/discovery/DiscoveryClientRouteDefinitionLocator.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/discovery/DiscoveryClientRouteDefinitionLocator.java index a8fe2d4e14..e5889313c7 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/discovery/DiscoveryClientRouteDefinitionLocator.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/discovery/DiscoveryClientRouteDefinitionLocator.java @@ -21,10 +21,12 @@ import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Objects; import java.util.function.Predicate; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Flux; import org.springframework.cloud.client.ServiceInstance; @@ -56,7 +58,7 @@ public class DiscoveryClientRouteDefinitionLocator implements RouteDefinitionLoc private final SimpleEvaluationContext evalCtxt; - private Flux> serviceInstances; + private @Nullable Flux> serviceInstances; public DiscoveryClientRouteDefinitionLocator(ReactiveDiscoveryClient discoveryClient, DiscoveryLocatorProperties properties) { @@ -96,7 +98,7 @@ public Flux getRouteDefinitions() { return include; }; } - + Objects.requireNonNull(serviceInstances, "serviceInstances must be set"); return serviceInstances.filter(instances -> !instances.isEmpty()) .flatMap(Flux::fromIterable) .filter(includePredicate) @@ -110,20 +112,28 @@ public Flux getRouteDefinitions() { for (PredicateDefinition original : this.properties.getPredicates()) { PredicateDefinition predicate = new PredicateDefinition(); - predicate.setName(original.getName()); + if (original.getName() != null) { + predicate.setName(original.getName()); + } for (Map.Entry entry : original.getArgs().entrySet()) { String value = getValueFromExpr(evalCtxt, parser, instanceForEval, entry); - predicate.addArg(entry.getKey(), value); + if (value != null) { + predicate.addArg(entry.getKey(), value); + } } routeDefinition.getPredicates().add(predicate); } for (FilterDefinition original : this.properties.getFilters()) { FilterDefinition filter = new FilterDefinition(); - filter.setName(original.getName()); + if (original.getName() != null) { + filter.setName(original.getName()); + } for (Map.Entry entry : original.getArgs().entrySet()) { String value = getValueFromExpr(evalCtxt, parser, instanceForEval, entry); - filter.addArg(entry.getKey(), value); + if (value != null) { + filter.addArg(entry.getKey(), value); + } } routeDefinition.getFilters().add(filter); } @@ -137,14 +147,16 @@ protected RouteDefinition buildRouteDefinition(Expression urlExpr, ServiceInstan RouteDefinition routeDefinition = new RouteDefinition(); routeDefinition.setId(this.routeIdPrefix + serviceId); String uri = urlExpr.getValue(this.evalCtxt, serviceInstance, String.class); - routeDefinition.setUri(URI.create(uri)); + if (uri != null) { + routeDefinition.setUri(URI.create(uri)); + } // add instance metadata routeDefinition.setMetadata(new LinkedHashMap<>(serviceInstance.getMetadata())); return routeDefinition; } - String getValueFromExpr(SimpleEvaluationContext evalCtxt, SpelExpressionParser parser, ServiceInstance instance, - Map.Entry entry) { + private @Nullable String getValueFromExpr(SimpleEvaluationContext evalCtxt, SpelExpressionParser parser, + ServiceInstance instance, Map.Entry entry) { try { Expression valueExpr = parser.parseExpression(entry.getValue()); return valueExpr.getValue(evalCtxt, instance, String.class); @@ -202,7 +214,7 @@ public Map getMetadata() { } @Override - public String getScheme() { + public @Nullable String getScheme() { return delegate.getScheme(); } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/discovery/DiscoveryLocatorProperties.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/discovery/DiscoveryLocatorProperties.java index 278264f543..e291f1080b 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/discovery/DiscoveryLocatorProperties.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/discovery/DiscoveryLocatorProperties.java @@ -19,6 +19,8 @@ import java.util.ArrayList; import java.util.List; +import org.jspecify.annotations.Nullable; + import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.cloud.gateway.filter.FilterDefinition; import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition; @@ -34,7 +36,7 @@ public class DiscoveryLocatorProperties { * The prefix for the routeId, defaults to discoveryClient.getClass().getSimpleName() * + "_". Service Id will be appended to create the routeId. */ - private String routeIdPrefix; + private @Nullable String routeIdPrefix; /** * SpEL expression that will evaluate whether to include a service in gateway @@ -66,7 +68,7 @@ public void setEnabled(boolean enabled) { this.enabled = enabled; } - public String getRouteIdPrefix() { + public @Nullable String getRouteIdPrefix() { return routeIdPrefix; } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/event/RefreshRoutesEvent.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/event/RefreshRoutesEvent.java index f02118af98..44f53faa30 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/event/RefreshRoutesEvent.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/event/RefreshRoutesEvent.java @@ -33,7 +33,8 @@ public class RefreshRoutesEvent extends ApplicationEvent { * @param source the object on which the event initially occurred (never {@code null}) */ public RefreshRoutesEvent(Object source) { - this(source, null); + super(source); + metadata = Map.of(); } /** diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/event/RefreshRoutesResultEvent.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/event/RefreshRoutesResultEvent.java index 941498f4a7..2e6046814e 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/event/RefreshRoutesResultEvent.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/event/RefreshRoutesResultEvent.java @@ -16,6 +16,8 @@ package org.springframework.cloud.gateway.event; +import org.jspecify.annotations.Nullable; + import org.springframework.context.ApplicationEvent; /** @@ -23,7 +25,7 @@ */ public class RefreshRoutesResultEvent extends ApplicationEvent { - private Throwable throwable; + private @Nullable Throwable throwable; public RefreshRoutesResultEvent(Object source, Throwable throwable) { super(source); @@ -34,7 +36,7 @@ public RefreshRoutesResultEvent(Object source) { super(source); } - public Throwable getThrowable() { + public @Nullable Throwable getThrowable() { return throwable; } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/AdaptCachedBodyGlobalFilter.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/AdaptCachedBodyGlobalFilter.java index 8f1bb6b2cb..d9fb877e3d 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/AdaptCachedBodyGlobalFilter.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/AdaptCachedBodyGlobalFilter.java @@ -48,18 +48,17 @@ public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { // the cached ServerHttpRequest is used when the ServerWebExchange can not be // mutated, for example, during a predicate where the body is read, but still // needs to be cached. - ServerHttpRequest cachedRequest = exchange.getAttributeOrDefault(CACHED_SERVER_HTTP_REQUEST_DECORATOR_ATTR, - null); + ServerHttpRequest cachedRequest = exchange.getAttribute(CACHED_SERVER_HTTP_REQUEST_DECORATOR_ATTR); if (cachedRequest != null) { exchange.getAttributes().remove(CACHED_SERVER_HTTP_REQUEST_DECORATOR_ATTR); return chain.filter(exchange.mutate().request(cachedRequest).build()); } // - DataBuffer body = exchange.getAttributeOrDefault(CACHED_REQUEST_BODY_ATTR, null); + DataBuffer body = exchange.getAttribute(CACHED_REQUEST_BODY_ATTR); Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR); - if (body != null || !this.routesToCache.containsKey(route.getId())) { + if (body != null || route == null || !this.routesToCache.containsKey(route.getId())) { return chain.filter(exchange); } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/FilterDefinition.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/FilterDefinition.java index ad281c62a5..aac106ce1b 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/FilterDefinition.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/FilterDefinition.java @@ -20,7 +20,7 @@ import java.util.Map; import java.util.Objects; -import jakarta.validation.constraints.NotNull; +import org.jspecify.annotations.Nullable; import org.springframework.cloud.gateway.support.NameUtils; import org.springframework.validation.annotation.Validated; @@ -33,8 +33,7 @@ @Validated public class FilterDefinition { - @NotNull - private String name; + private @Nullable String name; private Map args = new LinkedHashMap<>(); @@ -56,7 +55,7 @@ public FilterDefinition(String text) { } } - public String getName() { + public @Nullable String getName() { return name; } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/ForwardPathFilter.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/ForwardPathFilter.java index 4e12457c14..227b8791e8 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/ForwardPathFilter.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/ForwardPathFilter.java @@ -38,12 +38,17 @@ public class ForwardPathFilter implements GlobalFilter, Ordered { @Override public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR); - URI routeUri = route.getUri(); - String scheme = routeUri.getScheme(); - if (isAlreadyRouted(exchange) || !"forward".equals(scheme)) { - return chain.filter(exchange); + if (route != null) { + URI routeUri = route.getUri(); + String scheme = routeUri.getScheme(); + if (isAlreadyRouted(exchange) || !"forward".equals(scheme)) { + return chain.filter(exchange); + } + exchange = exchange.mutate() + .request(exchange.getRequest().mutate().path(routeUri.getPath()).build()) + .build(); + } - exchange = exchange.mutate().request(exchange.getRequest().mutate().path(routeUri.getPath()).build()).build(); return chain.filter(exchange); } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/ForwardRoutingFilter.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/ForwardRoutingFilter.java index 9b150daaef..18c37fb155 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/ForwardRoutingFilter.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/ForwardRoutingFilter.java @@ -20,10 +20,12 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Mono; import org.springframework.beans.factory.ObjectProvider; import org.springframework.core.Ordered; +import org.springframework.util.Assert; import org.springframework.web.reactive.DispatcherHandler; import org.springframework.web.server.ServerWebExchange; @@ -38,17 +40,16 @@ public class ForwardRoutingFilter implements GlobalFilter, Ordered { private final ObjectProvider dispatcherHandlerProvider; // do not use this dispatcherHandler directly, use getDispatcherHandler() instead. - private volatile DispatcherHandler dispatcherHandler; + private @Nullable volatile DispatcherHandler dispatcherHandler; public ForwardRoutingFilter(ObjectProvider dispatcherHandlerProvider) { this.dispatcherHandlerProvider = dispatcherHandlerProvider; } - private DispatcherHandler getDispatcherHandler() { + private @Nullable DispatcherHandler getDispatcherHandler() { if (dispatcherHandler == null) { dispatcherHandler = dispatcherHandlerProvider.getIfAvailable(); } - return dispatcherHandler; } @@ -71,8 +72,9 @@ public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { if (log.isTraceEnabled()) { log.trace("Forwarding to URI: " + requestUrl); } - - return handle(this.getDispatcherHandler(), exchange); + DispatcherHandler handler = getDispatcherHandler(); + Assert.notNull(handler, "DispatcherHandler must not be null"); + return handle(handler, exchange); } } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/LoadBalancerServiceInstanceCookieFilter.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/LoadBalancerServiceInstanceCookieFilter.java index 78d6ce21c3..c89b01d3ec 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/LoadBalancerServiceInstanceCookieFilter.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/LoadBalancerServiceInstanceCookieFilter.java @@ -18,7 +18,9 @@ import java.util.ArrayList; import java.util.List; +import java.util.Objects; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Mono; import org.springframework.cloud.client.ServiceInstance; @@ -44,9 +46,9 @@ */ public class LoadBalancerServiceInstanceCookieFilter implements GlobalFilter, Ordered { - private LoadBalancerProperties loadBalancerProperties; + private @Nullable LoadBalancerProperties loadBalancerProperties; - private ReactiveLoadBalancer.Factory loadBalancerClientFactory; + private ReactiveLoadBalancer.@Nullable Factory loadBalancerClientFactory; LoadBalancerServiceInstanceCookieFilter(LoadBalancerProperties loadBalancerProperties) { this.loadBalancerProperties = loadBalancerProperties; @@ -66,7 +68,8 @@ public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { LoadBalancerProperties properties = loadBalancerClientFactory != null ? loadBalancerClientFactory.getProperties(serviceInstanceResponse.getServer().getServiceId()) : loadBalancerProperties; - if (!properties.getStickySession().isAddServiceInstanceCookie()) { + Objects.requireNonNull(properties, "LoadBalancerProperties must not be null"); + if (properties.getStickySession() != null && !properties.getStickySession().isAddServiceInstanceCookie()) { return chain.filter(exchange); } String instanceIdCookieName = properties.getStickySession().getInstanceIdCookieName(); diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/NettyRoutingFilter.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/NettyRoutingFilter.java index 64cfa12843..124c2ce238 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/NettyRoutingFilter.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/NettyRoutingFilter.java @@ -19,6 +19,7 @@ import java.net.URI; import java.time.Duration; import java.util.List; +import java.util.Objects; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; @@ -27,6 +28,7 @@ import io.netty.handler.codec.http.HttpMethod; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.netty.http.client.HttpClient; @@ -85,7 +87,7 @@ public class NettyRoutingFilter implements GlobalFilter, Ordered { private final HttpClientProperties properties; // do not use this headersFilters directly, use getHeadersFilters() instead. - private volatile List headersFilters; + private volatile @Nullable List headersFilters; public NettyRoutingFilter(HttpClient httpClient, ObjectProvider> headersFiltersProvider, HttpClientProperties properties) { @@ -94,7 +96,7 @@ public NettyRoutingFilter(HttpClient httpClient, ObjectProvider getHeadersFilters() { + public @Nullable List getHeadersFilters() { if (headersFilters == null) { headersFilters = headersFiltersProvider.getIfAvailable(); } @@ -129,7 +131,7 @@ public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { boolean preserveHost = exchange.getAttributeOrDefault(PRESERVE_HOST_HEADER_ATTRIBUTE, false); Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR); - + Objects.requireNonNull(route, "route must not be null"); Flux responseFlux = getHttpClientMono(route, exchange) .flatMapMany(httpClient -> httpClient.headers(headers -> { headers.add(httpHeaders); @@ -257,13 +259,14 @@ protected HttpClient getHttpClient(Route route, ServerWebExchange exchange) { Object connectTimeoutAttr = route.getMetadata().get(CONNECT_TIMEOUT_ATTR) != null ? route.getMetadata().get(CONNECT_TIMEOUT_ATTR) : properties.getConnectTimeout(); if (connectTimeoutAttr != null) { - Integer connectTimeout = getInteger(connectTimeoutAttr); + Integer connectTimeout = java.util.Objects.requireNonNull(getInteger(connectTimeoutAttr), + "connectTimeout must not be null"); return this.httpClient.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, connectTimeout); } return httpClient; } - static Integer getInteger(Object connectTimeoutAttr) { + static @Nullable Integer getInteger(Object connectTimeoutAttr) { Integer connectTimeout; if (connectTimeoutAttr instanceof Integer) { connectTimeout = (Integer) connectTimeoutAttr; @@ -274,7 +277,7 @@ static Integer getInteger(Object connectTimeoutAttr) { return connectTimeout; } - private Duration getResponseTimeout(Route route) { + private @Nullable Duration getResponseTimeout(Route route) { try { if (route.getMetadata().containsKey(RESPONSE_TIMEOUT_ATTR)) { Long routeResponseTimeout = getLong(route.getMetadata().get(RESPONSE_TIMEOUT_ATTR)); @@ -292,7 +295,7 @@ private Duration getResponseTimeout(Route route) { return properties.getResponseTimeout(); } - static Long getLong(Object responseTimeoutAttr) { + static @Nullable Long getLong(Object responseTimeoutAttr) { Long responseTimeout = null; if (responseTimeoutAttr instanceof Number) { responseTimeout = ((Number) responseTimeoutAttr).longValue(); diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/NettyWriteResponseFilter.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/NettyWriteResponseFilter.java index 790875ecaa..c3e3bae49f 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/NettyWriteResponseFilter.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/NettyWriteResponseFilter.java @@ -21,6 +21,7 @@ import io.netty.buffer.ByteBuf; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.core.publisher.SignalType; @@ -37,7 +38,6 @@ import org.springframework.core.io.buffer.NettyDataBufferFactory; import org.springframework.http.MediaType; import org.springframework.http.server.reactive.ServerHttpResponse; -import org.springframework.lang.Nullable; import org.springframework.web.server.ServerWebExchange; import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR; @@ -60,7 +60,7 @@ public class NettyWriteResponseFilter implements GlobalFilter, Ordered { private final ObjectProvider> headersFiltersProvider; // do not use this headersFilters directly, use getHeadersFilters() instead. - private volatile List headersFilters; + private volatile @Nullable List headersFilters; public NettyWriteResponseFilter(List streamingMediaTypes, ObjectProvider> headersFiltersProvider) { @@ -68,7 +68,7 @@ public NettyWriteResponseFilter(List streamingMediaTypes, this.headersFiltersProvider = headersFiltersProvider; } - public List getHeadersFilters() { + public @Nullable List getHeadersFilters() { if (headersFilters == null) { headersFilters = headersFiltersProvider == null ? List.of() : headersFiltersProvider.getIfAvailable(); } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/ReactiveLoadBalancerClientFilter.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/ReactiveLoadBalancerClientFilter.java index 12cc037e4d..902e09773f 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/ReactiveLoadBalancerClientFilter.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/ReactiveLoadBalancerClientFilter.java @@ -18,6 +18,7 @@ import java.net.URI; import java.util.Map; +import java.util.Objects; import java.util.Set; import org.apache.commons.logging.Log; @@ -84,6 +85,8 @@ public int getOrder() { } @Override + // TODO remove this suppress warnings once the commons changes are merged in for CompletionContext + @SuppressWarnings("NullAway") public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { URI url = exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR); String schemePrefix = exchange.getAttribute(GATEWAY_SCHEME_PREFIX_ATTR); @@ -98,6 +101,7 @@ public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { } URI requestUri = exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR); + Objects.requireNonNull(requestUri, "requestUri can not be null"); String serviceId = requestUri.getHost(); Set supportedLifecycleProcessors = LoadBalancerLifecycleValidator .getSupportedLifecycleProcessors(clientFactory.getInstances(serviceId, LoadBalancerLifecycle.class), diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/WebsocketRoutingFilter.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/WebsocketRoutingFilter.java index 4433db627a..946b3acdfe 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/WebsocketRoutingFilter.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/WebsocketRoutingFilter.java @@ -26,6 +26,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Mono; import org.springframework.beans.factory.ObjectProvider; @@ -69,7 +70,7 @@ public class WebsocketRoutingFilter implements GlobalFilter, Ordered { private final ObjectProvider> headersFiltersProvider; // do not use this headersFilters directly, use getHeadersFilters() instead. - private volatile List headersFilters; + private volatile @Nullable List headersFilters; public WebsocketRoutingFilter(WebSocketClient webSocketClient, WebSocketService webSocketService, ObjectProvider> headersFiltersProvider) { @@ -111,7 +112,7 @@ public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { new ProxyWebSocketHandler(requestUrl, this.webSocketClient, filtered, protocols)); } - /* for testing */ List getProtocols(HttpHeaders headers) { + /* for testing */ static @Nullable List getProtocols(HttpHeaders headers) { List protocols = headers.get(SEC_WEBSOCKET_PROTOCOL); if (protocols != null) { ArrayList updatedProtocols = new ArrayList<>(); @@ -182,7 +183,7 @@ private static class ProxyWebSocketHandler implements WebSocketHandler { private final List subProtocols; - ProxyWebSocketHandler(URI url, WebSocketClient client, HttpHeaders headers, List protocols) { + ProxyWebSocketHandler(URI url, WebSocketClient client, HttpHeaders headers, @Nullable List protocols) { this.client = client; this.url = url; this.headers = headers; diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/WeightCalculatorWebFilter.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/WeightCalculatorWebFilter.java index 87cf7fc509..fd6feff88f 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/WeightCalculatorWebFilter.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/WeightCalculatorWebFilter.java @@ -29,6 +29,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Mono; import org.springframework.beans.factory.ObjectProvider; @@ -125,7 +126,7 @@ public boolean supportsEventType(Class eventType) { } @Override - public boolean supportsSourceType(Class sourceType) { + public boolean supportsSourceType(@Nullable Class sourceType) { return true; } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/cors/CorsGatewayFilterApplicationListener.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/cors/CorsGatewayFilterApplicationListener.java index 5a7b050306..8d1a25f9b0 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/cors/CorsGatewayFilterApplicationListener.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/cors/CorsGatewayFilterApplicationListener.java @@ -116,12 +116,13 @@ private String getPathPredicate(Route route) { predicate.accept(p -> { if (p.getConfig() instanceof PathRoutePredicateFactory.Config pathConfig) { if (!pathConfig.getPatterns().isEmpty()) { - pathPatterns.compareAndSet(null, pathConfig.getPatterns().get(0)); + pathPatterns.set(pathConfig.getPatterns().get(0)); } } }); - if (pathPatterns.get() != null) { - return pathPatterns.get(); + String result = pathPatterns.get(); + if (result != null) { + return result; } return ALL_PATHS; } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/AbstractGatewayFilterFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/AbstractGatewayFilterFactory.java index 8f966ee0fe..f4a50764c4 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/AbstractGatewayFilterFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/AbstractGatewayFilterFactory.java @@ -16,6 +16,8 @@ package org.springframework.cloud.gateway.filter.factory; +import org.jspecify.annotations.Nullable; + import org.springframework.cloud.gateway.event.EnableBodyCachingEvent; import org.springframework.cloud.gateway.support.AbstractConfigurable; import org.springframework.context.ApplicationEventPublisher; @@ -29,7 +31,7 @@ public abstract class AbstractGatewayFilterFactory extends AbstractConfigurable implements GatewayFilterFactory, ApplicationEventPublisherAware { - private ApplicationEventPublisher publisher; + private @Nullable ApplicationEventPublisher publisher; @SuppressWarnings("unchecked") public AbstractGatewayFilterFactory() { @@ -40,11 +42,11 @@ public AbstractGatewayFilterFactory(Class configClass) { super(configClass); } - protected ApplicationEventPublisher getPublisher() { + protected @Nullable ApplicationEventPublisher getPublisher() { return this.publisher; } - protected void enableBodyCaching(String routeId) { + protected void enableBodyCaching(@Nullable String routeId) { if (routeId != null && getPublisher() != null) { // send an event to enable caching getPublisher().publishEvent(new EnableBodyCachingEvent(this, routeId)); @@ -58,9 +60,9 @@ public void setApplicationEventPublisher(ApplicationEventPublisher publisher) { public static class NameConfig { - private String name; + private @Nullable String name; - public String getName() { + public @Nullable String getName() { return name; } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/AbstractNameValueGatewayFilterFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/AbstractNameValueGatewayFilterFactory.java index ff2bbe5980..f919a292a8 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/AbstractNameValueGatewayFilterFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/AbstractNameValueGatewayFilterFactory.java @@ -20,6 +20,7 @@ import java.util.List; import jakarta.validation.constraints.NotEmpty; +import org.jspecify.annotations.Nullable; import org.springframework.cloud.gateway.filter.GatewayFilter; import org.springframework.core.style.ToStringCreator; @@ -41,12 +42,12 @@ public List shortcutFieldOrder() { public static class NameValueConfig { @NotEmpty - protected String name; + protected @Nullable String name; @NotEmpty - protected String value; + protected @Nullable String value; - public String getName() { + public @Nullable String getName() { return name; } @@ -55,7 +56,7 @@ public NameValueConfig setName(String name) { return this; } - public String getValue() { + public @Nullable String getValue() { return value; } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/AddRequestHeaderGatewayFilterFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/AddRequestHeaderGatewayFilterFactory.java index 3a8fed2022..34afa484fe 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/AddRequestHeaderGatewayFilterFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/AddRequestHeaderGatewayFilterFactory.java @@ -16,6 +16,8 @@ package org.springframework.cloud.gateway.filter.factory; +import java.util.Objects; + import reactor.core.publisher.Mono; import org.springframework.cloud.gateway.filter.GatewayFilter; @@ -36,10 +38,12 @@ public GatewayFilter apply(NameValueConfig config) { return new GatewayFilter() { @Override public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { - String value = ServerWebExchangeUtils.expand(exchange, config.getValue()); + String name = Objects.requireNonNull(config.getName(), "name must not be null"); + String rawValue = Objects.requireNonNull(config.getValue(), "value must not be null"); + String value = ServerWebExchangeUtils.expand(exchange, rawValue); ServerHttpRequest request = exchange.getRequest() .mutate() - .headers(httpHeaders -> httpHeaders.add(config.getName(), value)) + .headers(httpHeaders -> httpHeaders.add(name, value)) .build(); return chain.filter(exchange.mutate().request(request).build()); @@ -47,8 +51,10 @@ public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { @Override public String toString() { + String name = config.getName(); + String value = config.getValue(); return filterToStringCreator(AddRequestHeaderGatewayFilterFactory.this) - .append(config.getName(), config.getValue()) + .append(name != null ? name : "", value != null ? value : "") .toString(); } }; diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/AddRequestParameterGatewayFilterFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/AddRequestParameterGatewayFilterFactory.java index 7189d4f811..3e159f1282 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/AddRequestParameterGatewayFilterFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/AddRequestParameterGatewayFilterFactory.java @@ -17,6 +17,7 @@ package org.springframework.cloud.gateway.filter.factory; import java.net.URI; +import java.util.Objects; import reactor.core.publisher.Mono; @@ -41,6 +42,8 @@ public GatewayFilter apply(NameValueConfig config) { return new GatewayFilter() { @Override public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { + String name = Objects.requireNonNull(config.getName(), "name must not be null"); + String rawValue = Objects.requireNonNull(config.getValue(), "value must not be null"); URI uri = exchange.getRequest().getURI(); StringBuilder query = new StringBuilder(); String originalQuery = uri.getRawQuery(); @@ -52,9 +55,9 @@ public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { } } - String value = ServerWebExchangeUtils.expand(exchange, config.getValue()); + String value = ServerWebExchangeUtils.expand(exchange, rawValue); // TODO urlencode? - query.append(config.getName()); + query.append(name); query.append('='); query.append(value); @@ -76,8 +79,10 @@ public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { @Override public String toString() { + String name = config.getName(); + String value = config.getValue(); return filterToStringCreator(AddRequestParameterGatewayFilterFactory.this) - .append(config.getName(), config.getValue()) + .append(name != null ? name : "", value != null ? value : "") .toString(); } }; diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/AddResponseHeaderGatewayFilterFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/AddResponseHeaderGatewayFilterFactory.java index 38ac5b7141..3c492dff52 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/AddResponseHeaderGatewayFilterFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/AddResponseHeaderGatewayFilterFactory.java @@ -18,6 +18,7 @@ import java.util.Arrays; import java.util.List; +import java.util.Objects; import reactor.core.publisher.Mono; @@ -63,15 +64,17 @@ public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { @Override public String toString() { + String name = config.getName(); + String value = config.getValue(); if (config instanceof Config) { return filterToStringCreator(AddResponseHeaderGatewayFilterFactory.this) - .append(GatewayFilter.NAME_KEY, config.getName()) - .append(GatewayFilter.VALUE_KEY, config.getValue()) + .append(GatewayFilter.NAME_KEY, name != null ? name : "") + .append(GatewayFilter.VALUE_KEY, value != null ? value : "") .append(OVERRIDE_KEY, ((Config) config).isOverride()) .toString(); } return filterToStringCreator(AddResponseHeaderGatewayFilterFactory.this) - .append(config.getName(), config.getValue()) + .append(name != null ? name : "", value != null ? value : "") .toString(); } }; @@ -80,7 +83,9 @@ public String toString() { void addHeader(ServerWebExchange exchange, NameValueConfig config) { // if response has been commited, no more response headers will bee added. if (!exchange.getResponse().isCommitted()) { - final String value = ServerWebExchangeUtils.expand(exchange, config.getValue()); + String name = Objects.requireNonNull(config.getName(), "name must not be null"); + String rawValue = Objects.requireNonNull(config.getValue(), "value must not be null"); + final String value = ServerWebExchangeUtils.expand(exchange, rawValue); HttpHeaders headers = exchange.getResponse().getHeaders(); boolean override = true; // default is true @@ -89,14 +94,14 @@ void addHeader(ServerWebExchange exchange, NameValueConfig config) { } if (override) { - headers.add(config.getName(), value); + headers.add(name, value); } else { - boolean headerIsMissingOrBlank = headers.getOrEmpty(config.getName()) + boolean headerIsMissingOrBlank = headers.getOrEmpty(name) .stream() .allMatch(h -> !StringUtils.hasText(h)); if (headerIsMissingOrBlank) { - headers.add(config.getName(), value); + headers.add(name, value); } } } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/CacheRequestBodyGatewayFilterFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/CacheRequestBodyGatewayFilterFactory.java index 7519f5284a..01c923dacb 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/CacheRequestBodyGatewayFilterFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/CacheRequestBodyGatewayFilterFactory.java @@ -18,7 +18,9 @@ import java.net.URI; import java.util.List; +import java.util.Objects; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Mono; import org.springframework.cloud.gateway.filter.GatewayFilter; @@ -78,7 +80,8 @@ public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { return ServerWebExchangeUtils.cacheRequestBodyAndRequest(exchange, (serverHttpRequest) -> { final ServerRequest serverRequest = ServerRequest .create(exchange.mutate().request(serverHttpRequest).build(), messageReaders); - return serverRequest.bodyToMono((config.getBodyClass())).doOnNext(objectValue -> { + Class bodyClass = Objects.requireNonNull(config.getBodyClass(), "bodyClass must not be null"); + return serverRequest.bodyToMono(bodyClass).doOnNext(objectValue -> { Object previousCachedBody = exchange.getAttributes() .put(ServerWebExchangeUtils.CACHED_REQUEST_BODY_ATTR, objectValue); if (previousCachedBody != null) { @@ -113,9 +116,9 @@ public String toString() { public static class Config { - private Class bodyClass; + private @Nullable Class bodyClass; - public Class getBodyClass() { + public @Nullable Class getBodyClass() { return bodyClass; } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/DedupeResponseHeaderGatewayFilterFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/DedupeResponseHeaderGatewayFilterFactory.java index 32705277e3..2594dbefe0 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/DedupeResponseHeaderGatewayFilterFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/DedupeResponseHeaderGatewayFilterFactory.java @@ -98,8 +98,9 @@ public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { @Override public String toString() { + String name = config.getName(); return filterToStringCreator(DedupeResponseHeaderGatewayFilterFactory.this) - .append(config.getName(), config.getStrategy()) + .append(name != null ? name : "", config.getStrategy()) .toString(); } }; diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/FallbackHeadersGatewayFilterFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/FallbackHeadersGatewayFilterFactory.java index 3c0059b823..33eb980d8e 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/FallbackHeadersGatewayFilterFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/FallbackHeadersGatewayFilterFactory.java @@ -19,6 +19,8 @@ import java.util.ArrayList; import java.util.List; +import org.jspecify.annotations.Nullable; + import org.springframework.cloud.gateway.filter.GatewayFilter; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.web.server.ServerWebExchange; @@ -59,18 +61,23 @@ public GatewayFilter apply(Config config) { private ServerWebExchange addFallbackHeaders(Config config, ServerWebExchange exchange, Throwable executionException) { + ServerHttpRequest.Builder requestBuilder = exchange.getRequest().mutate(); - requestBuilder.header(config.executionExceptionTypeHeaderName, executionException.getClass().getName()); - requestBuilder.header(config.executionExceptionMessageHeaderName, executionException.getMessage()); + requestBuilder.header(config.getExecutionExceptionMessageHeaderName(), executionException.getClass().getName()); + String executionMessage = executionException.getMessage(); + requestBuilder.header(config.getExecutionExceptionMessageHeaderName(), + executionMessage != null ? executionMessage : ""); Throwable rootCause = getRootCause(executionException); if (rootCause != null) { - requestBuilder.header(config.rootCauseExceptionTypeHeaderName, rootCause.getClass().getName()); - requestBuilder.header(config.rootCauseExceptionMessageHeaderName, rootCause.getMessage()); + requestBuilder.header(config.getRootCauseExceptionTypeHeaderName(), rootCause.getClass().getName()); + String rootCauseMessage = rootCause.getMessage(); + requestBuilder.header(config.getRootCauseExceptionMessageHeaderName(), + rootCauseMessage != null ? rootCauseMessage : ""); } return exchange.mutate().request(requestBuilder.build()).build(); } - private static Throwable getRootCause(final Throwable throwable) { + private static @Nullable Throwable getRootCause(final Throwable throwable) { final List list = getThrowableList(throwable); return list.isEmpty() ? null : list.get(list.size() - 1); } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/GatewayFilterFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/GatewayFilterFactory.java index 97f7446bc1..63bf8fa21e 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/GatewayFilterFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/GatewayFilterFactory.java @@ -18,6 +18,8 @@ import java.util.function.Consumer; +import org.jspecify.annotations.Nullable; + import org.springframework.cloud.gateway.filter.GatewayFilter; import org.springframework.cloud.gateway.support.Configurable; import org.springframework.cloud.gateway.support.HasRouteId; @@ -41,7 +43,7 @@ public interface GatewayFilterFactory extends ShortcutConfigurable, Configura String VALUE_KEY = "value"; // useful for javadsl - default GatewayFilter apply(String routeId, Consumer consumer) { + default GatewayFilter apply(@Nullable String routeId, Consumer consumer) { C config = newConfig(); consumer.accept(config); return apply(routeId, config); @@ -64,7 +66,7 @@ default C newConfig() { GatewayFilter apply(C config); - default GatewayFilter apply(String routeId, C config) { + default GatewayFilter apply(@Nullable String routeId, C config) { if (config instanceof HasRouteId) { HasRouteId hasRouteId = (HasRouteId) config; hasRouteId.setRouteId(routeId); diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/JsonToGrpcGatewayFilterFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/JsonToGrpcGatewayFilterFactory.java index 3942bd96a8..55d6689f1e 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/JsonToGrpcGatewayFilterFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/JsonToGrpcGatewayFilterFactory.java @@ -44,6 +44,7 @@ import io.grpc.protobuf.ProtoUtils; import io.grpc.stub.ClientCalls; import io.netty.buffer.PooledByteBufAllocator; +import org.jspecify.annotations.Nullable; import org.reactivestreams.Publisher; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -68,6 +69,7 @@ import org.springframework.core.io.buffer.NettyDataBufferFactory; import org.springframework.http.codec.json.JacksonJsonDecoder; import org.springframework.http.server.reactive.ServerHttpResponseDecorator; +import org.springframework.util.Assert; import org.springframework.web.server.ServerWebExchange; import static org.springframework.cloud.gateway.support.GatewayToStringStyler.filterToStringCreator; @@ -123,13 +125,13 @@ public String toString() { public static class Config { - private String protoDescriptor; + private @Nullable String protoDescriptor; - private String service; + private @Nullable String service; - private String method; + private @Nullable String method; - public String getProtoDescriptor() { + public @Nullable String getProtoDescriptor() { return protoDescriptor; } @@ -138,7 +140,7 @@ public Config setProtoDescriptor(String protoDescriptor) { return this; } - public String getService() { + public @Nullable String getService() { return service; } @@ -147,7 +149,7 @@ public Config setService(String service) { return this; } - public String getMethod() { + public @Nullable String getMethod() { return method; } @@ -222,6 +224,7 @@ private ClientCall createClientCallForType(Confi private Descriptors.MethodDescriptor getMethodDescriptor(Config config) throws IOException, Descriptors.DescriptorValidationException { + Assert.notNull(config.getProtoDescriptor(), "Proto Descriptor must not be null"); Resource descriptorFile = resourceLoader.getResource(config.getProtoDescriptor()); DescriptorProtos.FileDescriptorSet fileDescriptorSet = DescriptorProtos.FileDescriptorSet .parseFrom(descriptorFile.getInputStream()); @@ -260,7 +263,7 @@ private FileDescriptor[] dependencies(FileDescriptorSet input, ProtocolStringLis return deps; } - private FileDescriptorProto findFileByName(FileDescriptorSet input, String name) { + private @Nullable FileDescriptorProto findFileByName(FileDescriptorSet input, String name) { for (FileDescriptorProto file : input.getFileList()) { if (file.getName().equals(name)) { return file; @@ -270,7 +273,8 @@ private FileDescriptorProto findFileByName(FileDescriptorSet input, String name) } private ManagedChannel createChannel() { - URI requestURI = ((Route) exchange.getAttributes().get(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR)).getUri(); + Route route = (Route) exchange.getAttributes().get(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR); + URI requestURI = Objects.requireNonNull(route, "Route not found in exchange attributes").getUri(); return createChannelChannel(requestURI.getHost(), requestURI.getPort()); } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/MapRequestHeaderGatewayFilterFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/MapRequestHeaderGatewayFilterFactory.java index 3f7f2d35a0..23d8ba5be9 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/MapRequestHeaderGatewayFilterFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/MapRequestHeaderGatewayFilterFactory.java @@ -18,7 +18,9 @@ import java.util.Arrays; import java.util.List; +import java.util.Objects; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Mono; import org.springframework.cloud.gateway.filter.GatewayFilter; @@ -59,14 +61,20 @@ public GatewayFilter apply(MapRequestHeaderGatewayFilterFactory.Config config) { return new GatewayFilter() { @Override public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { - if (!exchange.getRequest().getHeaders().containsHeader(config.getFromHeader())) { + String fromHeader = Objects.requireNonNull(config.getFromHeader(), "fromHeader must be set"); + String toHeader = Objects.requireNonNull(config.getToHeader(), "toHeader must be set"); + if (!exchange.getRequest().getHeaders().containsHeader(fromHeader)) { + return chain.filter(exchange); + } + List headerValues = exchange.getRequest().getHeaders().get(fromHeader); + + if (headerValues == null) { return chain.filter(exchange); } - List headerValues = exchange.getRequest().getHeaders().get(config.getFromHeader()); ServerHttpRequest request = exchange.getRequest() .mutate() - .headers(i -> i.addAll(config.getToHeader(), headerValues)) + .headers(i -> i.addAll(toHeader, headerValues)) .build(); return chain.filter(exchange.mutate().request(request).build()); @@ -75,9 +83,11 @@ public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { @Override public String toString() { // @formatter:off + String fromHeader = config.getFromHeader(); + String toHeader = config.getToHeader(); return filterToStringCreator(MapRequestHeaderGatewayFilterFactory.this) - .append(FROM_HEADER_KEY, config.getFromHeader()) - .append(TO_HEADER_KEY, config.getToHeader()) + .append(FROM_HEADER_KEY, fromHeader != null ? fromHeader : "") + .append(TO_HEADER_KEY, toHeader != null ? toHeader : "") .toString(); // @formatter:on } @@ -86,11 +96,11 @@ public String toString() { public static class Config { - private String fromHeader; + private @Nullable String fromHeader; - private String toHeader; + private @Nullable String toHeader; - public String getFromHeader() { + public @Nullable String getFromHeader() { return this.fromHeader; } @@ -99,7 +109,7 @@ public Config setFromHeader(String fromHeader) { return this; } - public String getToHeader() { + public @Nullable String getToHeader() { return this.toHeader; } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/PrefixPathGatewayFilterFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/PrefixPathGatewayFilterFactory.java index 1277ce0449..1c35c0bc85 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/PrefixPathGatewayFilterFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/PrefixPathGatewayFilterFactory.java @@ -20,9 +20,11 @@ import java.util.Arrays; import java.util.List; import java.util.Map; +import java.util.Objects; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Mono; import org.springframework.cloud.gateway.filter.GatewayFilter; @@ -62,7 +64,8 @@ public List shortcutFieldOrder() { @Override public GatewayFilter apply(Config config) { return new GatewayFilter() { - final UriTemplate uriTemplate = new UriTemplate(config.prefix); + final UriTemplate uriTemplate = new UriTemplate( + Objects.requireNonNull(config.prefix, "prefix must not be null")); @Override public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { @@ -99,9 +102,9 @@ public String toString() { public static class Config { - private String prefix; + private @Nullable String prefix; - public String getPrefix() { + public @Nullable String getPrefix() { return prefix; } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RedirectToGatewayFilterFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RedirectToGatewayFilterFactory.java index ea38bea237..218bbc66ed 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RedirectToGatewayFilterFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RedirectToGatewayFilterFactory.java @@ -19,7 +19,9 @@ import java.net.URI; import java.util.Arrays; import java.util.List; +import java.util.Objects; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Mono; import org.springframework.cloud.gateway.filter.GatewayFilter; @@ -67,7 +69,9 @@ public List shortcutFieldOrder() { @Override public GatewayFilter apply(Config config) { - return apply(config.status, config.url, config.includeRequestParams); + String status = Objects.requireNonNull(config.status, "status must not be null"); + String url = Objects.requireNonNull(config.url, "url must not be null"); + return apply(status, url, config.includeRequestParams); } public GatewayFilter apply(String statusString, String urlString) { @@ -137,13 +141,13 @@ public String toString() { public static class Config { - String status; + private @Nullable String status; - String url; + private @Nullable String url; boolean includeRequestParams; - public String getStatus() { + public @Nullable String getStatus() { return status; } @@ -151,7 +155,7 @@ public void setStatus(String status) { this.status = status; } - public String getUrl() { + public @Nullable String getUrl() { return url; } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RemoveJsonAttributesResponseBodyGatewayFilterFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RemoveJsonAttributesResponseBodyGatewayFilterFactory.java index 2074f81353..602066579b 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RemoveJsonAttributesResponseBodyGatewayFilterFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RemoveJsonAttributesResponseBodyGatewayFilterFactory.java @@ -18,7 +18,9 @@ import java.util.Arrays; import java.util.List; +import java.util.Objects; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Mono; import tools.jackson.core.JacksonException; import tools.jackson.databind.JsonNode; @@ -74,7 +76,9 @@ public GatewayFilter apply(FieldListConfiguration config) { try { JsonNode jsonNode = mapper.readValue(body, JsonNode.class); - removeJsonAttributes(jsonNode, config.getFieldList(), config.isDeleteRecursively()); + List fieldList = Objects.requireNonNull(config.getFieldList(), + "fieldList must not be null"); + removeJsonAttributes(jsonNode, fieldList, config.isDeleteRecursively()); body = mapper.writeValueAsString(jsonNode); } @@ -104,7 +108,7 @@ private void removeJsonAttributes(JsonNode jsonNode, List fieldNames, bo public static class FieldListConfiguration { - private List fieldList; + private @Nullable List fieldList; private boolean deleteRecursively; @@ -117,7 +121,7 @@ public FieldListConfiguration setDeleteRecursively(boolean deleteRecursively) { return this; } - List getFieldList() { + public @Nullable List getFieldList() { return fieldList; } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RemoveRequestHeaderGatewayFilterFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RemoveRequestHeaderGatewayFilterFactory.java index 6e2208b9f5..dbd7a90a09 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RemoveRequestHeaderGatewayFilterFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RemoveRequestHeaderGatewayFilterFactory.java @@ -18,6 +18,7 @@ import java.util.Arrays; import java.util.List; +import java.util.Objects; import reactor.core.publisher.Mono; @@ -48,9 +49,10 @@ public GatewayFilter apply(NameConfig config) { return new GatewayFilter() { @Override public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { + String name = Objects.requireNonNull(config.getName(), "name must not be null"); ServerHttpRequest request = exchange.getRequest() .mutate() - .headers(httpHeaders -> httpHeaders.remove(config.getName())) + .headers(httpHeaders -> httpHeaders.remove(name)) .build(); return chain.filter(exchange.mutate().request(request).build()); @@ -58,8 +60,9 @@ public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { @Override public String toString() { + String name = config.getName(); return filterToStringCreator(RemoveRequestHeaderGatewayFilterFactory.this) - .append("name", config.getName()) + .append("name", name != null ? name : "") .toString(); } }; diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RemoveResponseHeaderGatewayFilterFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RemoveResponseHeaderGatewayFilterFactory.java index d6966c0506..33eefb660f 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RemoveResponseHeaderGatewayFilterFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RemoveResponseHeaderGatewayFilterFactory.java @@ -18,6 +18,7 @@ import java.util.Arrays; import java.util.List; +import java.util.Objects; import reactor.core.publisher.Mono; @@ -47,17 +48,19 @@ public GatewayFilter apply(NameConfig config) { return new GatewayFilter() { @Override public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { + String name = Objects.requireNonNull(config.getName(), "name must not be null"); return chain.filter(exchange).then(Mono.fromRunnable(() -> { if (!exchange.getResponse().isCommitted()) { - exchange.getResponse().getHeaders().remove(config.getName()); + exchange.getResponse().getHeaders().remove(name); } })); } @Override public String toString() { + String name = config.getName(); return filterToStringCreator(RemoveResponseHeaderGatewayFilterFactory.this) - .append("name", config.getName()) + .append("name", name != null ? name : "") .toString(); } }; diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RequestHeaderSizeGatewayFilterFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RequestHeaderSizeGatewayFilterFactory.java index eba18451b9..b2441ab9ee 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RequestHeaderSizeGatewayFilterFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RequestHeaderSizeGatewayFilterFactory.java @@ -21,6 +21,7 @@ import java.util.List; import java.util.Map; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Mono; import org.springframework.cloud.gateway.filter.GatewayFilter; @@ -113,7 +114,7 @@ public static class Config { private DataSize maxSize = DataSize.ofBytes(16000L); - private String errorHeaderName; + private @Nullable String errorHeaderName; public DataSize getMaxSize() { return maxSize; @@ -123,7 +124,7 @@ public void setMaxSize(DataSize maxSize) { this.maxSize = maxSize; } - public String getErrorHeaderName() { + public @Nullable String getErrorHeaderName() { return errorHeaderName; } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RequestHeaderToRequestUriGatewayFilterFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RequestHeaderToRequestUriGatewayFilterFactory.java index 70ac2d7bc6..464b69c959 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RequestHeaderToRequestUriGatewayFilterFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RequestHeaderToRequestUriGatewayFilterFactory.java @@ -20,6 +20,7 @@ import java.net.URI; import java.util.Arrays; import java.util.List; +import java.util.Objects; import java.util.Optional; import org.slf4j.Logger; @@ -58,8 +59,8 @@ public GatewayFilter apply(NameConfig config) { return new OrderedGatewayFilter(gatewayFilter, gatewayFilter.getOrder()) { @Override public String toString() { - return filterToStringCreator(RequestHeaderToRequestUriGatewayFilterFactory.this) - .append("name", config.getName()) + String name = Objects.requireNonNull(config.getName(), "name must not be null"); + return filterToStringCreator(RequestHeaderToRequestUriGatewayFilterFactory.this).append("name", name) .toString(); } }; @@ -67,7 +68,8 @@ public String toString() { @Override protected Optional determineRequestUri(ServerWebExchange exchange, NameConfig config) { - String requestUrl = exchange.getRequest().getHeaders().getFirst(config.getName()); + String name = Objects.requireNonNull(config.getName(), "name must not be null"); + String requestUrl = exchange.getRequest().getHeaders().getFirst(name); return Optional.ofNullable(requestUrl).map(url -> { try { URI uri = URI.create(url); diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RequestRateLimiterGatewayFilterFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RequestRateLimiterGatewayFilterFactory.java index 06f7ec5ad6..43a287ed31 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RequestRateLimiterGatewayFilterFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RequestRateLimiterGatewayFilterFactory.java @@ -17,6 +17,9 @@ package org.springframework.cloud.gateway.filter.factory; import java.util.Map; +import java.util.Objects; + +import org.jspecify.annotations.Nullable; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.cloud.gateway.filter.GatewayFilter; @@ -107,7 +110,7 @@ public GatewayFilter apply(Config config) { String routeId = config.getRouteId(); if (routeId == null) { Route route = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR); - routeId = route.getId(); + routeId = Objects.requireNonNull(route, "Route not found").getId(); } return limiter.isAllowed(routeId, key).flatMap(response -> { @@ -125,25 +128,25 @@ public GatewayFilter apply(Config config) { }); } - private T getOrDefault(T configValue, T defaultValue) { + private T getOrDefault(@Nullable T configValue, T defaultValue) { return (configValue != null) ? configValue : defaultValue; } public static class Config implements HasRouteId { - private KeyResolver keyResolver; + private @Nullable KeyResolver keyResolver; - private RateLimiter rateLimiter; + private @Nullable RateLimiter rateLimiter; private HttpStatus statusCode = HttpStatus.TOO_MANY_REQUESTS; - private Boolean denyEmptyKey; + private @Nullable Boolean denyEmptyKey; - private String emptyKeyStatus; + private @Nullable String emptyKeyStatus; - private String routeId; + private @Nullable String routeId; - public KeyResolver getKeyResolver() { + public @Nullable KeyResolver getKeyResolver() { return keyResolver; } @@ -152,7 +155,7 @@ public Config setKeyResolver(KeyResolver keyResolver) { return this; } - public RateLimiter getRateLimiter() { + public @Nullable RateLimiter getRateLimiter() { return rateLimiter; } @@ -170,7 +173,7 @@ public Config setStatusCode(HttpStatus statusCode) { return this; } - public Boolean getDenyEmptyKey() { + public @Nullable Boolean getDenyEmptyKey() { return denyEmptyKey; } @@ -179,7 +182,7 @@ public Config setDenyEmptyKey(Boolean denyEmptyKey) { return this; } - public String getEmptyKeyStatus() { + public @Nullable String getEmptyKeyStatus() { return emptyKeyStatus; } @@ -194,7 +197,7 @@ public void setRouteId(String routeId) { } @Override - public String getRouteId() { + public @Nullable String getRouteId() { return this.routeId; } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RetryGatewayFilterFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RetryGatewayFilterFactory.java index 28eaaa6cc8..12b02712a1 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RetryGatewayFilterFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RetryGatewayFilterFactory.java @@ -26,6 +26,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.reactivestreams.Publisher; import reactor.core.publisher.Mono; import reactor.netty.Connection; @@ -250,7 +251,8 @@ public void reset(ServerWebExchange exchange) { ServerWebExchangeUtils.reset(exchange); } - public GatewayFilter apply(String routeId, Repeat repeat, Retry retry) { + public GatewayFilter apply(@Nullable String routeId, @Nullable Repeat repeat, + @Nullable Retry retry) { enableBodyCaching(routeId); return (exchange, chain) -> { trace("Entering retry-filter"); @@ -300,7 +302,7 @@ private final void trace(String message, Supplier... argSuppliers) { @SuppressWarnings("unchecked") public static class RetryConfig implements HasRouteId { - private String routeId; + private @Nullable String routeId; private int retries = 3; @@ -312,11 +314,11 @@ public static class RetryConfig implements HasRouteId { private List> exceptions = toList(IOException.class, TimeoutException.class); - private BackoffConfig backoff; + private @Nullable BackoffConfig backoff; - private JitterConfig jitter; + private @Nullable JitterConfig jitter; - private Duration timeout; + private @Nullable Duration timeout; public RetryConfig allMethods() { return setMethods(HttpMethod.values()); @@ -338,7 +340,7 @@ public void validate() { } } - public Duration getTimeout() { + public @Nullable Duration getTimeout() { return timeout; } @@ -347,7 +349,7 @@ public RetryConfig setTimeout(Duration timeout) { return this; } - public JitterConfig getJitter() { + public @Nullable JitterConfig getJitter() { return jitter; } @@ -361,7 +363,7 @@ public RetryConfig setJitter(double randomFactor) { return this; } - public BackoffConfig getBackoff() { + public @Nullable BackoffConfig getBackoff() { return backoff; } @@ -382,7 +384,7 @@ public void setRouteId(String routeId) { } @Override - public String getRouteId() { + public @Nullable String getRouteId() { return this.routeId; } @@ -437,7 +439,7 @@ public static class BackoffConfig { private Duration firstBackoff = Duration.ofMillis(5); - private Duration maxBackoff; + private @Nullable Duration maxBackoff; private int factor = 2; @@ -465,7 +467,7 @@ public void setFirstBackoff(Duration firstBackoff) { this.firstBackoff = firstBackoff; } - public Duration getMaxBackoff() { + public @Nullable Duration getMaxBackoff() { return maxBackoff; } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RewriteLocationResponseHeaderGatewayFilterFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RewriteLocationResponseHeaderGatewayFilterFactory.java index 3aea0514fb..e3ce9e7d8a 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RewriteLocationResponseHeaderGatewayFilterFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RewriteLocationResponseHeaderGatewayFilterFactory.java @@ -20,6 +20,7 @@ import java.util.List; import java.util.regex.Pattern; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Mono; import org.springframework.cloud.gateway.filter.GatewayFilter; @@ -199,7 +200,7 @@ public static class Config { private String locationHeaderName = HttpHeaders.LOCATION; - private String hostValue; + private @Nullable String hostValue; private String protocols = DEFAULT_PROTOCOLS; @@ -225,7 +226,7 @@ public Config setLocationHeaderName(String locationHeaderName) { return this; } - public String getHostValue() { + public @Nullable String getHostValue() { return hostValue; } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RewritePathGatewayFilterFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RewritePathGatewayFilterFactory.java index 3475ffa18b..2907340bbb 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RewritePathGatewayFilterFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RewritePathGatewayFilterFactory.java @@ -18,8 +18,10 @@ import java.util.Arrays; import java.util.List; +import java.util.Objects; import java.util.regex.Pattern; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Mono; import org.springframework.cloud.gateway.filter.GatewayFilter; @@ -59,8 +61,10 @@ public List shortcutFieldOrder() { @Override public GatewayFilter apply(Config config) { - String replacement = config.replacement.replace("$\\", "$"); - Pattern pattern = Pattern.compile(config.regexp); + String replacementValue = Objects.requireNonNull(config.replacement, "replacement must not be null"); + String replacement = replacementValue.replace("$\\", "$"); + String regexpValue = Objects.requireNonNull(config.regexp, "regexp must not be null"); + Pattern pattern = Pattern.compile(regexpValue); return new GatewayFilter() { @Override public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { @@ -78,8 +82,9 @@ public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { @Override public String toString() { + String regexp = config.getRegexp(); return filterToStringCreator(RewritePathGatewayFilterFactory.this) - .append(config.getRegexp(), replacement) + .append(regexp != null ? regexp : "", replacement) .toString(); } }; @@ -87,11 +92,11 @@ public String toString() { public static class Config { - private String regexp; + private @Nullable String regexp; - private String replacement; + private @Nullable String replacement; - public String getRegexp() { + public @Nullable String getRegexp() { return regexp; } @@ -101,7 +106,7 @@ public Config setRegexp(String regexp) { return this; } - public String getReplacement() { + public @Nullable String getReplacement() { return replacement; } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RewriteRequestParameterGatewayFilterFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RewriteRequestParameterGatewayFilterFactory.java index 97bba6e355..e768dae743 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RewriteRequestParameterGatewayFilterFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RewriteRequestParameterGatewayFilterFactory.java @@ -19,14 +19,15 @@ import java.net.URI; import java.util.Arrays; import java.util.List; +import java.util.Objects; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Mono; import org.springframework.cloud.gateway.filter.GatewayFilter; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.support.ServerWebExchangeUtils; import org.springframework.http.server.reactive.ServerHttpRequest; -import org.springframework.util.Assert; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.web.server.ServerWebExchange; @@ -60,14 +61,17 @@ public GatewayFilter apply(Config config) { return new GatewayFilter() { @Override public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { + String name = Objects.requireNonNull(config.getName(), "name must not be null"); + String replacement = Objects.requireNonNull(config.getReplacement(), "replacement must not be null"); + ServerHttpRequest req = exchange.getRequest(); UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUri(req.getURI()); MultiValueMap queryParams = new LinkedMultiValueMap<>(req.getQueryParams()); - if (queryParams.containsKey(config.getName())) { - queryParams.remove(config.getName()); - queryParams.add(config.getName(), config.getReplacement()); + if (queryParams.containsKey(name)) { + queryParams.remove(name); + queryParams.add(name, replacement); } try { @@ -87,8 +91,9 @@ public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { @Override public String toString() { - return filterToStringCreator(RewriteRequestParameterGatewayFilterFactory.this) - .append(config.getName(), config.replacement) + String name = Objects.requireNonNull(config.getName(), "name must not be null"); + String replacement = Objects.requireNonNull(config.getReplacement(), "replacement must not be null"); + return filterToStringCreator(RewriteRequestParameterGatewayFilterFactory.this).append(name, replacement) .toString(); } }; @@ -96,14 +101,13 @@ public String toString() { public static class Config extends AbstractGatewayFilterFactory.NameConfig { - private String replacement; + private @Nullable String replacement; - public String getReplacement() { + public @Nullable String getReplacement() { return replacement; } public Config setReplacement(String replacement) { - Assert.notNull(replacement, "replacement must not be null"); this.replacement = replacement; return this; } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RewriteResponseHeaderGatewayFilterFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RewriteResponseHeaderGatewayFilterFactory.java index d709366863..f7f62d901a 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RewriteResponseHeaderGatewayFilterFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RewriteResponseHeaderGatewayFilterFactory.java @@ -19,7 +19,9 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Objects; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Mono; import org.springframework.cloud.gateway.filter.GatewayFilter; @@ -74,10 +76,10 @@ public String toString() { } protected void rewriteHeaders(ServerWebExchange exchange, Config config) { - final String name = config.getName(); + final String name = Objects.requireNonNull(config.getName(), "name must not be null"); final HttpHeaders responseHeaders = exchange.getResponse().getHeaders(); if (responseHeaders.get(name) != null) { - List oldValue = responseHeaders.get(name); + List oldValue = Objects.requireNonNull(responseHeaders.get(name), "oldValue must not be null"); List newValue = rewriteHeaders(config, oldValue); if (newValue != null) { responseHeaders.put(name, newValue); @@ -89,9 +91,11 @@ protected void rewriteHeaders(ServerWebExchange exchange, Config config) { } protected List rewriteHeaders(Config config, List headers) { + String regexp = Objects.requireNonNull(config.getRegexp(), "regexp must not be null"); + String replacement = Objects.requireNonNull(config.getReplacement(), "replacement must not be null"); ArrayList rewrittenHeaders = new ArrayList<>(); for (int i = 0; i < headers.size(); i++) { - String rewriten = rewrite(headers.get(i), config.getRegexp(), config.getReplacement()); + String rewriten = rewrite(headers.get(i), regexp, replacement); rewrittenHeaders.add(rewriten); } return rewrittenHeaders; @@ -103,11 +107,11 @@ String rewrite(String value, String regexp, String replacement) { public static class Config extends AbstractGatewayFilterFactory.NameConfig { - private String regexp; + private @Nullable String regexp; - private String replacement; + private @Nullable String replacement; - public String getRegexp() { + public @Nullable String getRegexp() { return regexp; } @@ -116,7 +120,7 @@ public Config setRegexp(String regexp) { return this; } - public String getReplacement() { + public @Nullable String getReplacement() { return replacement; } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersGatewayFilterFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersGatewayFilterFactory.java index 11a678d72c..40ba973c67 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersGatewayFilterFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersGatewayFilterFactory.java @@ -21,6 +21,7 @@ import java.util.Set; import java.util.stream.Collectors; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Mono; import org.springframework.cloud.gateway.filter.GatewayFilter; @@ -186,8 +187,8 @@ private Set assembleHeaders(Config config, SecureHeadersProperties prope } private void addHeaderIfEnabled(HttpHeaders headers, Set headersToAdd, String headerName, - String headerValue) { - if (headersToAdd.contains(headerName.toLowerCase(Locale.ROOT))) { + @Nullable String headerValue) { + if (headerValue != null && headersToAdd.contains(headerName.toLowerCase(Locale.ROOT))) { if (!headers.containsHeader(headerName)) { headers.add(headerName, headerValue); } @@ -203,27 +204,27 @@ public static class Config { private Set routeDisabledHeaders = new HashSet<>(); - private String routePermissionsPolicyHeaderValue; + private @Nullable String routePermissionsPolicyHeaderValue; private boolean routeFilterConfigProvided; - private String xssProtectionHeaderValue; + private @Nullable String xssProtectionHeaderValue; - private String strictTransportSecurityHeaderValue; + private @Nullable String strictTransportSecurityHeaderValue; - private String frameOptionsHeaderValue; + private @Nullable String frameOptionsHeaderValue; - private String contentTypeOptionsHeaderValue; + private @Nullable String contentTypeOptionsHeaderValue; - private String referrerPolicyHeaderValue; + private @Nullable String referrerPolicyHeaderValue; - private String contentSecurityPolicyHeaderValue; + private @Nullable String contentSecurityPolicyHeaderValue; - private String downloadOptionsHeaderValue; + private @Nullable String downloadOptionsHeaderValue; - private String permittedCrossDomainPoliciesHeaderValue; + private @Nullable String permittedCrossDomainPoliciesHeaderValue; - private String permissionPolicyHeaderValue; + private @Nullable String permissionPolicyHeaderValue; public Config withDefaults(SecureHeadersProperties properties) { Config config = new Config(); @@ -281,75 +282,76 @@ public Config withDefaults(SecureHeadersProperties properties) { return config; } - public String getXssProtectionHeaderValue() { + public @Nullable String getXssProtectionHeaderValue() { return xssProtectionHeaderValue; } - public void setXssProtectionHeaderValue(String xssProtectionHeaderHeaderValue) { + public void setXssProtectionHeaderValue(@Nullable String xssProtectionHeaderHeaderValue) { this.xssProtectionHeaderValue = xssProtectionHeaderHeaderValue; } - public String getStrictTransportSecurityHeaderValue() { + public @Nullable String getStrictTransportSecurityHeaderValue() { return strictTransportSecurityHeaderValue; } - public void setStrictTransportSecurityHeaderValue(String strictTransportSecurityHeaderValue) { + public void setStrictTransportSecurityHeaderValue(@Nullable String strictTransportSecurityHeaderValue) { this.strictTransportSecurityHeaderValue = strictTransportSecurityHeaderValue; } - public String getFrameOptionsHeaderValue() { + public @Nullable String getFrameOptionsHeaderValue() { return frameOptionsHeaderValue; } - public void setFrameOptionsHeaderValue(String frameOptionsHeaderValue) { + public void setFrameOptionsHeaderValue(@Nullable String frameOptionsHeaderValue) { this.frameOptionsHeaderValue = frameOptionsHeaderValue; } - public String getContentTypeOptionsHeaderValue() { + public @Nullable String getContentTypeOptionsHeaderValue() { return contentTypeOptionsHeaderValue; } - public void setContentTypeOptionsHeaderValue(String contentTypeOptionsHeaderValue) { + public void setContentTypeOptionsHeaderValue(@Nullable String contentTypeOptionsHeaderValue) { this.contentTypeOptionsHeaderValue = contentTypeOptionsHeaderValue; } - public String getReferrerPolicyHeaderValue() { + public @Nullable String getReferrerPolicyHeaderValue() { return referrerPolicyHeaderValue; } - public void setReferrerPolicyHeaderValue(String referrerPolicyHeaderValue) { + public void setReferrerPolicyHeaderValue(@Nullable String referrerPolicyHeaderValue) { this.referrerPolicyHeaderValue = referrerPolicyHeaderValue; } - public String getContentSecurityPolicyHeaderValue() { + public @Nullable String getContentSecurityPolicyHeaderValue() { return contentSecurityPolicyHeaderValue; } - public void setContentSecurityPolicyHeaderValue(String contentSecurityPolicyHeaderValue) { + public void setContentSecurityPolicyHeaderValue(@Nullable String contentSecurityPolicyHeaderValue) { this.contentSecurityPolicyHeaderValue = contentSecurityPolicyHeaderValue; } - public String getDownloadOptionsHeaderValue() { + public @Nullable String getDownloadOptionsHeaderValue() { return downloadOptionsHeaderValue; } - public void setDownloadOptionsHeaderValue(String downloadOptionHeaderValue) { + public void setDownloadOptionsHeaderValue(@Nullable String downloadOptionHeaderValue) { this.downloadOptionsHeaderValue = downloadOptionHeaderValue; } - public String getPermittedCrossDomainPoliciesHeaderValue() { + public @Nullable String getPermittedCrossDomainPoliciesHeaderValue() { return permittedCrossDomainPoliciesHeaderValue; } - public void setPermittedCrossDomainPoliciesHeaderValue(String permittedCrossDomainPoliciesHeaderValue) { + public void setPermittedCrossDomainPoliciesHeaderValue( + @Nullable String permittedCrossDomainPoliciesHeaderValue) { this.permittedCrossDomainPoliciesHeaderValue = permittedCrossDomainPoliciesHeaderValue; } - public String getPermissionPolicyHeaderValue() { + public @Nullable String getPermissionPolicyHeaderValue() { return permissionPolicyHeaderValue; } - public void setPermissionPolicyHeaderValue(String permissionPolicyHeaderValue) { + public void setPermissionPolicyHeaderValue(@Nullable String permissionPolicyHeaderValue) { this.permissionPolicyHeaderValue = permissionPolicyHeaderValue; } @@ -394,14 +396,14 @@ Set getRouteDisabledHeaders() { /** * @return the route specific/opt-out permission policies. */ - String getRoutePermissionsPolicyHeaderValue() { + protected @Nullable String getRoutePermissionsPolicyHeaderValue() { return routePermissionsPolicyHeaderValue; } /** * bind the route specific/opt-out permissions policy. */ - void setPermissionsPolicy(String permissionsPolicy) { + void setPermissionsPolicy(@Nullable String permissionsPolicy) { this.routeFilterConfigProvided = true; this.routePermissionsPolicyHeaderValue = permissionsPolicy; } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/SetPathGatewayFilterFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/SetPathGatewayFilterFactory.java index f98573be2b..2f5cb340e7 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/SetPathGatewayFilterFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/SetPathGatewayFilterFactory.java @@ -20,7 +20,9 @@ import java.util.Arrays; import java.util.List; import java.util.Map; +import java.util.Objects; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Mono; import org.springframework.cloud.gateway.filter.GatewayFilter; @@ -55,7 +57,8 @@ public List shortcutFieldOrder() { @Override public GatewayFilter apply(Config config) { - UriTemplate uriTemplate = new UriTemplate(config.template); + String template = Objects.requireNonNull(config.template, "template must not be null"); + UriTemplate uriTemplate = new UriTemplate(template); return new GatewayFilter() { @Override @@ -85,9 +88,9 @@ public String toString() { public static class Config { - private String template; + private @Nullable String template; - public String getTemplate() { + public @Nullable String getTemplate() { return template; } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/SetRequestHeaderGatewayFilterFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/SetRequestHeaderGatewayFilterFactory.java index b521e778ae..88517904e9 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/SetRequestHeaderGatewayFilterFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/SetRequestHeaderGatewayFilterFactory.java @@ -16,6 +16,8 @@ package org.springframework.cloud.gateway.filter.factory; +import java.util.Objects; + import reactor.core.publisher.Mono; import org.springframework.cloud.gateway.filter.GatewayFilter; @@ -37,9 +39,10 @@ public GatewayFilter apply(NameValueConfig config) { @Override public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { String value = ServerWebExchangeUtils.expand(exchange, config.getValue()); + String name = Objects.requireNonNull(config.name, "name must not be null"); ServerHttpRequest request = exchange.getRequest() .mutate() - .headers(httpHeaders -> httpHeaders.set(config.name, value)) + .headers(httpHeaders -> httpHeaders.set(name, value)) .build(); return chain.filter(exchange.mutate().request(request).build()); @@ -47,8 +50,10 @@ public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { @Override public String toString() { + String name = config.getName(); + String value = config.getValue(); return filterToStringCreator(SetRequestHeaderGatewayFilterFactory.this) - .append(config.getName(), config.getValue()) + .append(name != null ? name : "", value != null ? value : "") .toString(); } }; diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/SetRequestHostHeaderGatewayFilterFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/SetRequestHostHeaderGatewayFilterFactory.java index 2e1c605565..0cba8aaa6c 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/SetRequestHostHeaderGatewayFilterFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/SetRequestHostHeaderGatewayFilterFactory.java @@ -19,6 +19,7 @@ import java.util.Collections; import java.util.List; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Mono; import org.springframework.cloud.gateway.filter.GatewayFilter; @@ -65,7 +66,9 @@ public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { @Override public String toString() { - return filterToStringCreator(SetRequestHostHeaderGatewayFilterFactory.this).append(config.getHost()) + String host = config.getHost(); + return filterToStringCreator(SetRequestHostHeaderGatewayFilterFactory.this) + .append(host != null ? host : "") .toString(); } }; @@ -73,9 +76,9 @@ public String toString() { public static class Config { - private String host; + private @Nullable String host; - public String getHost() { + public @Nullable String getHost() { return host; } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/SetRequestUriGatewayFilterFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/SetRequestUriGatewayFilterFactory.java index 8f38148029..0a72709a26 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/SetRequestUriGatewayFilterFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/SetRequestUriGatewayFilterFactory.java @@ -20,8 +20,10 @@ import java.util.Arrays; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; +import org.jspecify.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -60,15 +62,15 @@ public GatewayFilter apply(Config config) { return new OrderedGatewayFilter(gatewayFilter, gatewayFilter.getOrder()) { @Override public String toString() { - return filterToStringCreator(SetRequestUriGatewayFilterFactory.this) - .append("template", config.getTemplate()) + String template = Objects.requireNonNull(config.getTemplate(), "template must not be null"); + return filterToStringCreator(SetRequestUriGatewayFilterFactory.this).append("template", template) .toString(); } }; } String getUri(ServerWebExchange exchange, Config config) { - String template = config.getTemplate(); + String template = Objects.requireNonNull(config.getTemplate(), "template must not be null"); if (template.indexOf('{') == -1) { return template; @@ -97,9 +99,9 @@ protected Optional determineRequestUri(ServerWebExchange exchange, Config c public static class Config { - private String template; + private @Nullable String template; - public String getTemplate() { + public @Nullable String getTemplate() { return template; } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/SetResponseHeaderGatewayFilterFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/SetResponseHeaderGatewayFilterFactory.java index 93b385bd17..01c401e601 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/SetResponseHeaderGatewayFilterFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/SetResponseHeaderGatewayFilterFactory.java @@ -16,6 +16,8 @@ package org.springframework.cloud.gateway.filter.factory; +import java.util.Objects; + import reactor.core.publisher.Mono; import org.springframework.cloud.gateway.filter.GatewayFilter; @@ -36,14 +38,17 @@ public GatewayFilter apply(NameValueConfig config) { @Override public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { String value = ServerWebExchangeUtils.expand(exchange, config.getValue()); + String name = Objects.requireNonNull(config.name, "name must not be null"); return chain.filter(exchange) - .then(Mono.fromRunnable(() -> exchange.getResponse().getHeaders().set(config.name, value))); + .then(Mono.fromRunnable(() -> exchange.getResponse().getHeaders().set(name, value))); } @Override public String toString() { + String name = config.getName(); + String value = config.getValue(); return filterToStringCreator(SetResponseHeaderGatewayFilterFactory.this) - .append(config.getName(), config.getValue()) + .append(name != null ? name : "", value != null ? value : "") .toString(); } }; diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/SetStatusGatewayFilterFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/SetStatusGatewayFilterFactory.java index 9c285218ca..5eaac43b6f 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/SetStatusGatewayFilterFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/SetStatusGatewayFilterFactory.java @@ -18,7 +18,9 @@ import java.util.Arrays; import java.util.List; +import java.util.Objects; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Mono; import org.springframework.boot.context.properties.ConfigurationProperties; @@ -46,7 +48,7 @@ public class SetStatusGatewayFilterFactory extends AbstractGatewayFilterFactory< /** * The name of the header which contains http code of the proxied request. */ - private String originalStatusHeaderName; + private @Nullable String originalStatusHeaderName; public SetStatusGatewayFilterFactory() { super(Config.class); @@ -59,7 +61,8 @@ public List shortcutFieldOrder() { @Override public GatewayFilter apply(Config config) { - HttpStatusHolder statusHolder = HttpStatusHolder.parse(config.status); + String status = Objects.requireNonNull(config.status, "status must not be null"); + HttpStatusHolder statusHolder = HttpStatusHolder.parse(status); return new GatewayFilter() { @Override @@ -77,7 +80,7 @@ public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { // but it's a good example HttpStatusCode statusCode = exchange.getResponse().getStatusCode(); boolean isStatusCodeUpdated = setResponseStatus(exchange, statusHolder); - if (isStatusCodeUpdated && originalStatusHeaderName != null) { + if (isStatusCodeUpdated && originalStatusHeaderName != null && statusCode != null) { exchange.getResponse() .getHeaders() .set(originalStatusHeaderName, singletonList(statusCode.value()).toString()); @@ -93,7 +96,7 @@ public String toString() { }; } - public String getOriginalStatusHeaderName() { + public @Nullable String getOriginalStatusHeaderName() { return originalStatusHeaderName; } @@ -104,9 +107,9 @@ public void setOriginalStatusHeaderName(String originalStatusHeaderName) { public static class Config { // TODO: relaxed HttpStatus converter - private String status; + private @Nullable String status; - public String getStatus() { + public @Nullable String getStatus() { return status; } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/SpringCloudCircuitBreakerFilterFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/SpringCloudCircuitBreakerFilterFactory.java index 0f8f3835f3..76858bbd98 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/SpringCloudCircuitBreakerFilterFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/SpringCloudCircuitBreakerFilterFactory.java @@ -22,6 +22,7 @@ import java.util.Set; import java.util.stream.Collectors; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Mono; import org.springframework.beans.factory.ObjectProvider; @@ -60,12 +61,12 @@ public abstract class SpringCloudCircuitBreakerFilterFactory private ReactiveCircuitBreakerFactory reactiveCircuitBreakerFactory; - private ReactiveCircuitBreaker cb; + private @Nullable ReactiveCircuitBreaker cb; private final ObjectProvider dispatcherHandlerProvider; // do not use this dispatcherHandler directly, use getDispatcherHandler() instead. - private volatile DispatcherHandler dispatcherHandler; + private volatile @Nullable DispatcherHandler dispatcherHandler; public SpringCloudCircuitBreakerFilterFactory(ReactiveCircuitBreakerFactory reactiveCircuitBreakerFactory, ObjectProvider dispatcherHandlerProvider) { @@ -74,7 +75,7 @@ public SpringCloudCircuitBreakerFilterFactory(ReactiveCircuitBreakerFactory reac this.dispatcherHandlerProvider = dispatcherHandlerProvider; } - private DispatcherHandler getDispatcherHandler() { + private @Nullable DispatcherHandler getDispatcherHandler() { if (dispatcherHandler == null) { dispatcherHandler = dispatcherHandlerProvider.getIfAvailable(); } @@ -105,7 +106,8 @@ public GatewayFilter apply(Config config) { public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { return cb.run(chain.filter(exchange).doOnSuccess(v -> { if (statuses.contains(exchange.getResponse().getStatusCode())) { - HttpStatusCode status = exchange.getResponse().getStatusCode(); + HttpStatusCode status = java.util.Objects.requireNonNull(exchange.getResponse().getStatusCode(), + "statusCode must not be null"); throw new CircuitBreakerStatusCodeException(status); } }), t -> { @@ -145,9 +147,11 @@ public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { @Override public String toString() { + String name = config.getName(); + URI fallbackUri = config.getFallbackUri(); return filterToStringCreator(SpringCloudCircuitBreakerFilterFactory.this) - .append("name", config.getName()) - .append("fallback", config.fallbackUri) + .append("name", name != null ? name : "") + .append("fallback", fallbackUri != null ? fallbackUri : "") .toString(); } }; @@ -168,11 +172,11 @@ public String name() { public static class Config implements HasRouteId { - private String name; + private @Nullable String name; - private URI fallbackUri; + private @Nullable URI fallbackUri; - private String routeId; + private @Nullable String routeId; private Set statusCodes = new HashSet<>(); @@ -183,11 +187,11 @@ public void setRouteId(String routeId) { this.routeId = routeId; } - public String getRouteId() { + public @Nullable String getRouteId() { return routeId; } - public URI getFallbackUri() { + public @Nullable URI getFallbackUri() { return fallbackUri; } @@ -200,7 +204,7 @@ public Config setFallbackUri(String fallbackUri) { return setFallbackUri(URI.create(fallbackUri)); } - public String getName() { + public @Nullable String getName() { return name; } @@ -209,7 +213,7 @@ public Config setName(String name) { return this; } - public String getId() { + public @Nullable String getId() { if (!StringUtils.hasText(name) && StringUtils.hasText(routeId)) { return routeId; } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/TokenRelayGatewayFilterFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/TokenRelayGatewayFilterFactory.java index 68a2523d9a..18f6012afd 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/TokenRelayGatewayFilterFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/TokenRelayGatewayFilterFactory.java @@ -19,6 +19,7 @@ import java.util.Collections; import java.util.List; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Mono; import org.springframework.beans.factory.ObjectProvider; @@ -55,7 +56,7 @@ public GatewayFilter apply() { } @Override - public GatewayFilter apply(NameConfig config) { + public GatewayFilter apply(@Nullable NameConfig config) { String defaultClientRegistrationId = (config == null) ? null : config.getName(); return (exchange, chain) -> exchange.getPrincipal() // .log("token-relay-filter") @@ -70,7 +71,7 @@ public GatewayFilter apply(NameConfig config) { .flatMap(chain::filter); } - private Mono authorizationRequest(String defaultClientRegistrationId, + private Mono authorizationRequest(@Nullable String defaultClientRegistrationId, Authentication principal) { String clientRegistrationId = defaultClientRegistrationId; if (clientRegistrationId == null && principal instanceof OAuth2AuthenticationToken) { diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/cache/CachedResponse.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/cache/CachedResponse.java index fecc169a0d..e6573eb0c4 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/cache/CachedResponse.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/cache/CachedResponse.java @@ -34,6 +34,8 @@ import java.util.List; import java.util.zip.GZIPInputStream; +import org.jspecify.annotations.Nullable; + import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatusCode; import org.springframework.util.FileCopyUtils; @@ -120,7 +122,7 @@ public static class Builder { private final List body = new ArrayList<>(); - private Instant timestamp; + private @Nullable Instant timestamp; public Builder(HttpStatusCode statusCode) { this.statusCode = statusCode; diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/cache/LocalResponseCacheGatewayFilterFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/cache/LocalResponseCacheGatewayFilterFactory.java index 7f73a35bb3..95fa4e8d7e 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/cache/LocalResponseCacheGatewayFilterFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/cache/LocalResponseCacheGatewayFilterFactory.java @@ -18,8 +18,10 @@ import java.time.Duration; import java.util.List; +import java.util.Objects; import com.github.benmanes.caffeine.cache.Caffeine; +import org.jspecify.annotations.Nullable; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.cache.Cache; @@ -86,6 +88,7 @@ public GatewayFilter apply(RouteCacheConfiguration config) { String cacheName = config.getRouteId() + "-cache"; caffeineCacheManager.registerCustomCache(cacheName, caffeine.build()); Cache routeCache = caffeineCacheManager.getCache(cacheName); + Objects.requireNonNull(routeCache, "Cache " + cacheName + " not found"); return new ResponseCacheGatewayFilter( cacheManagerFactory.create(routeCache, cacheProperties.getTimeToLive(), requestOptions)); @@ -109,26 +112,26 @@ public List shortcutFieldOrder() { @Validated public static class RouteCacheConfiguration implements HasRouteId { - private DataSize size; + private @Nullable DataSize size; - private Duration timeToLive; + private @Nullable Duration timeToLive; - private String routeId; + private @Nullable String routeId; - public DataSize getSize() { + public @Nullable DataSize getSize() { return size; } - public RouteCacheConfiguration setSize(DataSize size) { + public RouteCacheConfiguration setSize(@Nullable DataSize size) { this.size = size; return this; } - public Duration getTimeToLive() { + public @Nullable Duration getTimeToLive() { return timeToLive; } - public RouteCacheConfiguration setTimeToLive(Duration timeToLive) { + public RouteCacheConfiguration setTimeToLive(@Nullable Duration timeToLive) { this.timeToLive = timeToLive; return this; } @@ -139,7 +142,7 @@ public void setRouteId(String routeId) { } @Override - public String getRouteId() { + public @Nullable String getRouteId() { return this.routeId; } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/cache/LocalResponseCacheProperties.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/cache/LocalResponseCacheProperties.java index c3bbd2a6fe..2dd13d2cdf 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/cache/LocalResponseCacheProperties.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/cache/LocalResponseCacheProperties.java @@ -20,6 +20,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.util.unit.DataSize; @@ -36,13 +37,13 @@ public class LocalResponseCacheProperties { private static final Duration DEFAULT_CACHE_TTL_MINUTES = Duration.ofMinutes(5); - private DataSize size; + private @Nullable DataSize size; - private Duration timeToLive; + private @Nullable Duration timeToLive; private RequestOptions request = new RequestOptions(); - public DataSize getSize() { + public @Nullable DataSize getSize() { return size; } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/cache/ResponseCacheManager.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/cache/ResponseCacheManager.java index 655a9d7485..c82b758f11 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/cache/ResponseCacheManager.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/cache/ResponseCacheManager.java @@ -22,10 +22,12 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Objects; import java.util.Optional; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -102,6 +104,7 @@ public Flux processFromUpstream(String metadataKey, ServerWebExchang final ServerHttpResponse response = exchange.getResponse(); final CachedResponseMetadata metadata = new CachedResponseMetadata(response.getHeaders().getVary()); final String key = resolveKey(exchange, metadata.varyOnHeaders()); + Objects.requireNonNull(response.getStatusCode(), "Response status code must not be null"); CachedResponse.Builder cachedResponseBuilder = CachedResponse.create(response.getStatusCode()) .headers(response.getHeaders()); CachedResponse toProcess = cachedResponseBuilder.build(); @@ -152,7 +155,7 @@ Mono processFromCache(ServerWebExchange exchange, String metadataKey, Cach .writeWith(Flux.fromIterable(cachedResponse.body()).map(data -> response.bufferFactory().wrap(data))); } - private CachedResponseMetadata retrieveMetadata(String metadataKey) { + private @Nullable CachedResponseMetadata retrieveMetadata(String metadataKey) { CachedResponseMetadata metadata; try { metadata = cache.get(metadataKey, CachedResponseMetadata.class); diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/rewrite/CachedBodyOutputMessage.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/rewrite/CachedBodyOutputMessage.java index b3e9730d4f..bc16a7a82e 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/rewrite/CachedBodyOutputMessage.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/rewrite/CachedBodyOutputMessage.java @@ -18,6 +18,7 @@ import java.util.function.Supplier; +import org.jspecify.annotations.Nullable; import org.reactivestreams.Publisher; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -40,7 +41,7 @@ public class CachedBodyOutputMessage implements ReactiveHttpOutputMessage { private boolean cached = false; - private Flux body = null; + private @Nullable Flux body = null; public CachedBodyOutputMessage(ServerWebExchange exchange, HttpHeaders httpHeaders) { this.bufferFactory = exchange.getResponse().bufferFactory(); diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/rewrite/ModifyRequestBodyGatewayFilterFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/rewrite/ModifyRequestBodyGatewayFilterFactory.java index 71d93d9b02..5ce82af8b9 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/rewrite/ModifyRequestBodyGatewayFilterFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/rewrite/ModifyRequestBodyGatewayFilterFactory.java @@ -17,8 +17,10 @@ package org.springframework.cloud.gateway.filter.factory.rewrite; import java.util.List; +import java.util.Objects; import java.util.function.Function; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -65,15 +67,20 @@ public GatewayFilter apply(Config config) { return new GatewayFilter() { @Override public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { - ParameterizedTypeReference inClass = config.getInClass(); + ParameterizedTypeReference inClass = Objects.requireNonNull(config.getInClass(), + "inClass must not be null"); + RewriteFunction rewriteFunction = Objects.requireNonNull(config.getRewriteFunction(), + "rewriteFunction must not be null"); + ParameterizedTypeReference outClass = Objects.requireNonNull(config.getOutClass(), + "outClass must not be null"); ServerRequest serverRequest = ServerRequest.create(exchange, messageReaders); // TODO: flux or mono Mono modifiedBody = serverRequest.bodyToMono(inClass) - .flatMap(originalBody -> config.getRewriteFunction().apply(exchange, originalBody)) - .switchIfEmpty(Mono.defer(() -> (Mono) config.getRewriteFunction().apply(exchange, null))); + .flatMap(originalBody -> rewriteFunction.apply(exchange, originalBody)) + .switchIfEmpty(Mono.defer(() -> (Mono) rewriteFunction.apply(exchange, null))); - BodyInserter bodyInserter = BodyInserters.fromPublisher(modifiedBody, config.getOutClass()); + BodyInserter bodyInserter = BodyInserters.fromPublisher(modifiedBody, outClass); HttpHeaders headers = new HttpHeaders(); headers.putAll(exchange.getRequest().getHeaders()); @@ -144,15 +151,15 @@ public Flux getBody() { public static class Config { - private ParameterizedTypeReference inClass; + private @Nullable ParameterizedTypeReference inClass; - private ParameterizedTypeReference outClass; + private @Nullable ParameterizedTypeReference outClass; - private String contentType; + private @Nullable String contentType; - private RewriteFunction rewriteFunction; + private @Nullable RewriteFunction rewriteFunction; - public ParameterizedTypeReference getInClass() { + public @Nullable ParameterizedTypeReference getInClass() { return inClass; } @@ -165,7 +172,7 @@ public Config setInClass(ParameterizedTypeReference inTypeReference) { return this; } - public ParameterizedTypeReference getOutClass() { + public @Nullable ParameterizedTypeReference getOutClass() { return outClass; } @@ -178,7 +185,7 @@ public Config setOutClass(ParameterizedTypeReference outClass) { return this; } - public RewriteFunction getRewriteFunction() { + public @Nullable RewriteFunction getRewriteFunction() { return rewriteFunction; } @@ -203,11 +210,11 @@ public Config setRewriteFunction(ParameterizedTypeReference inClass, return this; } - public String getContentType() { + public @Nullable String getContentType() { return contentType; } - public Config setContentType(String contentType) { + public Config setContentType(@Nullable String contentType) { this.contentType = contentType; return this; } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/rewrite/ModifyResponseBodyGatewayFilterFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/rewrite/ModifyResponseBodyGatewayFilterFactory.java index 13367d6256..8d2cfaf87a 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/rewrite/ModifyResponseBodyGatewayFilterFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/rewrite/ModifyResponseBodyGatewayFilterFactory.java @@ -18,9 +18,11 @@ import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; +import org.jspecify.annotations.Nullable; import org.reactivestreams.Publisher; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -81,19 +83,19 @@ public GatewayFilter apply(Config config) { public static class Config { - private Class inClass; + private @Nullable Class inClass; - private Class outClass; + private @Nullable Class outClass; - private Map inHints; + private @Nullable Map inHints; - private Map outHints; + private @Nullable Map outHints; - private String newContentType; + private @Nullable String newContentType; - private RewriteFunction rewriteFunction; + private @Nullable RewriteFunction rewriteFunction; - public Class getInClass() { + public @Nullable Class getInClass() { return inClass; } @@ -102,7 +104,7 @@ public Config setInClass(Class inClass) { return this; } - public Class getOutClass() { + public @Nullable Class getOutClass() { return outClass; } @@ -111,7 +113,7 @@ public Config setOutClass(Class outClass) { return this; } - public Map getInHints() { + public @Nullable Map getInHints() { return inHints; } @@ -120,7 +122,7 @@ public Config setInHints(Map inHints) { return this; } - public Map getOutHints() { + public @Nullable Map getOutHints() { return outHints; } @@ -129,16 +131,16 @@ public Config setOutHints(Map outHints) { return this; } - public String getNewContentType() { + public @Nullable String getNewContentType() { return newContentType; } - public Config setNewContentType(String newContentType) { + public Config setNewContentType(@Nullable String newContentType) { this.newContentType = newContentType; return this; } - public RewriteFunction getRewriteFunction() { + public @Nullable RewriteFunction getRewriteFunction() { return rewriteFunction; } @@ -161,7 +163,7 @@ public class ModifyResponseGatewayFilter implements GatewayFilter, Ordered { private final Config config; - private GatewayFilterFactory gatewayFilterFactory; + private @Nullable GatewayFilterFactory gatewayFilterFactory; public ModifyResponseGatewayFilter(Config config) { this.config = config; @@ -208,8 +210,10 @@ public ModifiedServerHttpResponse(ServerWebExchange exchange, Config config) { @Override public Mono writeWith(Publisher body) { - Class inClass = config.getInClass(); - Class outClass = config.getOutClass(); + Class inClass = Objects.requireNonNull(config.getInClass(), "inClass must not be null"); + Class outClass = Objects.requireNonNull(config.getOutClass(), "outClass must not be null"); + RewriteFunction rewriteFunction = Objects.requireNonNull(config.getRewriteFunction(), + "rewriteFunction must not be null"); String originalResponseContentType = exchange.getAttribute(ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR); HttpHeaders httpHeaders = new HttpHeaders(); @@ -223,8 +227,8 @@ public Mono writeWith(Publisher body) { // TODO: flux or mono Mono modifiedBody = extractBody(exchange, clientResponse, inClass) - .flatMap(originalBody -> config.getRewriteFunction().apply(exchange, originalBody)) - .switchIfEmpty(Mono.defer(() -> (Mono) config.getRewriteFunction().apply(exchange, null))); + .flatMap(originalBody -> rewriteFunction.apply(exchange, originalBody)) + .switchIfEmpty(Mono.defer(() -> (Mono) rewriteFunction.apply(exchange, null))); BodyInserter bodyInserter = BodyInserters.fromPublisher(modifiedBody, outClass); CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage(exchange, @@ -253,7 +257,9 @@ public Mono writeAndFlushWith(Publisher body, HttpHeaders httpHeaders) { ClientResponse.Builder builder; - builder = ClientResponse.create(exchange.getResponse().getStatusCode(), messageReaders); + builder = ClientResponse.create( + Objects.requireNonNull(exchange.getResponse().getStatusCode(), "Status code must not be null"), + messageReaders); return builder.headers(headers -> headers.putAll(httpHeaders)).body(Flux.from(body)).build(); } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/headers/ForwardedHeadersFilter.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/headers/ForwardedHeadersFilter.java index b43a53814b..6fe61f7998 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/headers/ForwardedHeadersFilter.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/headers/ForwardedHeadersFilter.java @@ -28,6 +28,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.springframework.cloud.gateway.config.GatewayProperties; import org.springframework.core.Ordered; @@ -48,7 +49,7 @@ public class ForwardedHeadersFilter implements HttpHeadersFilter, Ordered { private static final Log log = LogFactory.getLog(ForwardedHeadersFilter.class); - private Integer serverPort; + private @Nullable Integer serverPort; private final Log logger = LogFactory.getLog(getClass()); @@ -82,14 +83,16 @@ static List parse(List values) { String[] forwardedValues = StringUtils.tokenizeToStringArray(value, ","); for (String forwardedValue : forwardedValues) { Forwarded forwarded = parse(forwardedValue); - forwardeds.add(forwarded); + if (forwarded != null) { + forwardeds.add(forwarded); + } } } return forwardeds; } /* for testing */ - static Forwarded parse(String value) { + static @Nullable Forwarded parse(String value) { String[] pairs = StringUtils.tokenizeToStringArray(value, ";"); LinkedCaseInsensitiveMap result = splitIntoCaseInsensitiveMap(pairs); @@ -102,7 +105,7 @@ static Forwarded parse(String value) { return forwarded; } - /* for testing */ static LinkedCaseInsensitiveMap splitIntoCaseInsensitiveMap(String[] pairs) { + /* for testing */ static @Nullable LinkedCaseInsensitiveMap splitIntoCaseInsensitiveMap(String[] pairs) { if (ObjectUtils.isEmpty(pairs)) { return null; } @@ -152,11 +155,16 @@ public HttpHeaders filter(HttpHeaders input, ServerWebExchange exchange) { } } - List forwardeds = parse(original.get(FORWARDED_HEADER)); + List forwardedHeaders = original.get(FORWARDED_HEADER); + if (forwardedHeaders == null) { + forwardedHeaders = List.of(); + } + List forwardeds = parse(forwardedHeaders); for (Forwarded f : forwardeds) { // only add if "for" value matches trustedProxies - if (trustedProxies.isTrusted(f.get("for"))) { + String forValue = f.get("for"); + if (forValue != null && trustedProxies.isTrusted(forValue)) { updated.add(FORWARDED_HEADER, f.toHeaderValue()); } } @@ -164,7 +172,10 @@ public HttpHeaders filter(HttpHeaders input, ServerWebExchange exchange) { // TODO: add new forwarded URI uri = request.getURI(); String host = original.getFirst(HttpHeaders.HOST); - Forwarded forwarded = new Forwarded().put("host", host).put("proto", uri.getScheme()); + Forwarded forwarded = new Forwarded().put("proto", uri.getScheme()); + if (host != null) { + forwarded.put("host", host); + } InetSocketAddress remoteAddress = request.getRemoteAddress(); // TODO: only add if "remoteAddress" value matches trustedProxies @@ -251,7 +262,7 @@ private String quoteIfNeeded(String s) { return s; } - public String get(String key) { + public @Nullable String get(String key) { return this.values.get(key); } @@ -267,7 +278,7 @@ public String toString() { public String toHeaderValue() { StringBuilder builder = new StringBuilder(); for (Map.Entry entry : this.values.entrySet()) { - if (builder.length() > 0) { + if (!builder.isEmpty()) { builder.append(SEMICOLON); } builder.append(entry.getKey()).append(EQUALS).append(entry.getValue()); diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/headers/GRPCRequestHeadersFilter.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/headers/GRPCRequestHeadersFilter.java index 4f1bf1289d..31eb57c418 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/headers/GRPCRequestHeadersFilter.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/headers/GRPCRequestHeadersFilter.java @@ -19,6 +19,8 @@ import java.util.List; import java.util.Map; +import org.jspecify.annotations.Nullable; + import org.springframework.core.Ordered; import org.springframework.http.HttpHeaders; import org.springframework.util.StringUtils; @@ -44,7 +46,7 @@ public HttpHeaders filter(HttpHeaders headers, ServerWebExchange exchange) { return updated; } - private boolean isGRPC(String contentTypeValue) { + private boolean isGRPC(@Nullable String contentTypeValue) { return StringUtils.startsWithIgnoreCase(contentTypeValue, "application/grpc"); } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/headers/GRPCResponseHeadersFilter.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/headers/GRPCResponseHeadersFilter.java index 3652b2eef7..b3a3ffa385 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/headers/GRPCResponseHeadersFilter.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/headers/GRPCResponseHeadersFilter.java @@ -16,6 +16,7 @@ package org.springframework.cloud.gateway.filter.headers; +import org.jspecify.annotations.Nullable; import reactor.netty.http.server.HttpServerResponse; import org.springframework.core.Ordered; @@ -63,7 +64,7 @@ private boolean isGRPC(ServerWebExchange exchange) { return StringUtils.startsWithIgnoreCase(contentTypeValue, "application/grpc"); } - private String getGrpcStatus(HttpHeaders headers) { + private @Nullable String getGrpcStatus(HttpHeaders headers) { final String grpcStatusValue = headers.getFirst(GRPC_STATUS_HEADER); return StringUtils.hasText(grpcStatusValue) ? grpcStatusValue : null; } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/headers/HttpHeadersFilter.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/headers/HttpHeadersFilter.java index d41764c6b3..a26c00d95e 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/headers/HttpHeadersFilter.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/headers/HttpHeadersFilter.java @@ -18,17 +18,19 @@ import java.util.List; +import org.jspecify.annotations.Nullable; + import org.springframework.http.HttpHeaders; import org.springframework.web.server.ServerWebExchange; public interface HttpHeadersFilter { - static HttpHeaders filterRequest(List filters, ServerWebExchange exchange) { + static HttpHeaders filterRequest(@Nullable List filters, ServerWebExchange exchange) { HttpHeaders headers = exchange.getRequest().getHeaders(); return filter(filters, headers, exchange, Type.REQUEST); } - static HttpHeaders filter(List filters, HttpHeaders input, ServerWebExchange exchange, + static HttpHeaders filter(@Nullable List filters, HttpHeaders input, ServerWebExchange exchange, Type type) { if (filters != null) { HttpHeaders filtered = input; diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/headers/XForwardedHeadersFilter.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/headers/XForwardedHeadersFilter.java index 1eabe9824e..584cb6b1ca 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/headers/XForwardedHeadersFilter.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/headers/XForwardedHeadersFilter.java @@ -24,6 +24,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.cloud.gateway.config.GatewayProperties; @@ -319,14 +320,16 @@ private void write(HttpHeaders headers, String name, String value, boolean appen write(headers, name, value, append, s -> true); } - private void write(HttpHeaders headers, String name, String value, boolean append, Predicate shouldWrite) { + private void write(HttpHeaders headers, String name, @Nullable String value, boolean append, + Predicate shouldWrite) { if (append) { if (value != null) { headers.add(name, value); } // these headers should be treated as a single comma separated header - if (headers.containsHeader(name)) { - List values = headers.get(name).stream().filter(shouldWrite).toList(); + List headerValues = headers.get(name); + if (headerValues != null) { + List values = headerValues.stream().filter(shouldWrite).toList(); String delimitedValue = StringUtils.collectionToCommaDelimitedString(values); headers.set(name, delimitedValue); } @@ -354,11 +357,12 @@ private String toHostHeader(ServerHttpRequest request) { } private String stripTrailingSlash(URI uri) { - if (uri.getPath().endsWith("/")) { - return uri.getPath().substring(0, uri.getPath().length() - 1); + String path = uri.getPath(); + if (path != null && path.endsWith("/")) { + return path.substring(0, path.length() - 1); } else { - return uri.getPath(); + return path; } } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/headers/observation/DefaultGatewayObservationConvention.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/headers/observation/DefaultGatewayObservationConvention.java index 9686d9ffe3..54b27e424a 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/headers/observation/DefaultGatewayObservationConvention.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/headers/observation/DefaultGatewayObservationConvention.java @@ -17,8 +17,7 @@ package org.springframework.cloud.gateway.filter.headers.observation; import io.micrometer.common.KeyValues; -import io.micrometer.common.lang.NonNull; -import io.micrometer.common.lang.Nullable; +import org.jspecify.annotations.Nullable; import org.springframework.cloud.gateway.route.Route; import org.springframework.cloud.gateway.support.ServerWebExchangeUtils; @@ -50,10 +49,12 @@ public KeyValues getLowCardinalityKeyValues(GatewayContext context) { return keyValues; } Route route = context.getServerWebExchange().getAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR); - keyValues = keyValues - .and(ROUTE_URI.withValue(route.getUri().toString()), - METHOD.withValue(context.getRequest().getMethod().name())) - .and(ROUTE_ID.withValue(route.getId())); + if (route != null) { + keyValues = keyValues + .and(ROUTE_URI.withValue(route.getUri().toString()), + METHOD.withValue(context.getRequest().getMethod().name())) + .and(ROUTE_ID.withValue(route.getId())); + } ServerHttpResponse response = context.getResponse(); if (response != null && response.getStatusCode() != null) { keyValues = keyValues.and(STATUS.withValue(String.valueOf(response.getStatusCode().value()))); @@ -70,14 +71,12 @@ public KeyValues getHighCardinalityKeyValues(GatewayContext context) { } @Override - @NonNull public String getName() { return "http.client.requests"; } - @Nullable @Override - public String getContextualName(GatewayContext context) { + public @Nullable String getContextualName(GatewayContext context) { if (context.getRequest() == null) { return null; } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/headers/observation/ObservedRequestHttpHeadersFilter.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/headers/observation/ObservedRequestHttpHeadersFilter.java index bdebc71c8c..001867cf33 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/headers/observation/ObservedRequestHttpHeadersFilter.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/headers/observation/ObservedRequestHttpHeadersFilter.java @@ -90,6 +90,7 @@ public HttpHeaders filter(HttpHeaders input, ServerWebExchange exchange) { * @param exchange server web exchange * @return parent observation or {@code null} when there is none */ + @Nullable private Observation getParentObservation(ServerWebExchange exchange) { ContextView contextView = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_REACTOR_CONTEXT_ATTR); if (contextView == null) { diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/ratelimit/AbstractRateLimiter.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/ratelimit/AbstractRateLimiter.java index 95e1dab09f..e24fa7b651 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/ratelimit/AbstractRateLimiter.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/ratelimit/AbstractRateLimiter.java @@ -18,6 +18,8 @@ import java.util.Map; +import org.jspecify.annotations.Nullable; + import org.springframework.cloud.gateway.event.FilterArgsEvent; import org.springframework.cloud.gateway.support.AbstractStatefulConfigurable; import org.springframework.cloud.gateway.support.ConfigurationService; @@ -29,10 +31,10 @@ public abstract class AbstractRateLimiter extends AbstractStatefulConfigurabl private String configurationPropertyName; - private ConfigurationService configurationService; + private @Nullable ConfigurationService configurationService; protected AbstractRateLimiter(Class configClass, String configurationPropertyName, - ConfigurationService configurationService) { + @Nullable ConfigurationService configurationService) { super(configClass); this.configurationPropertyName = configurationPropertyName; this.configurationService = configurationService; diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/ratelimit/Bucket4jRateLimiter.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/ratelimit/Bucket4jRateLimiter.java index 268817d2c2..a43d2f276f 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/ratelimit/Bucket4jRateLimiter.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/ratelimit/Bucket4jRateLimiter.java @@ -33,6 +33,7 @@ import io.github.bucket4j.distributed.proxy.AsyncProxyManager; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Mono; import org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator; @@ -130,20 +131,20 @@ public static class Config { Function configurationBuilder = DEFAULT_CONFIGURATION_BUILDER; - Supplier> configurationSupplier; + protected @Nullable Supplier> configurationSupplier; String headerName = DEFAULT_HEADER_NAME; - Duration refillPeriod; + protected @Nullable Duration refillPeriod; RefillStyle refillStyle = RefillStyle.GREEDY; - Long refillTokens; + protected @Nullable Long refillTokens; long requestedTokens = 1; // for RefillStyle.INTERVALLY_ALIGNED - Instant timeOfFirstRefill; + protected @Nullable Instant timeOfFirstRefill; public long getCapacity() { return capacity; @@ -185,7 +186,7 @@ public Config setHeaderName(String headerName) { return this; } - public Duration getRefillPeriod() { + public @Nullable Duration getRefillPeriod() { return refillPeriod; } @@ -203,7 +204,7 @@ public Config setRefillStyle(RefillStyle refillStyle) { return this; } - public Long getRefillTokens() { + public @Nullable Long getRefillTokens() { return refillTokens; } @@ -221,7 +222,7 @@ public Config setRequestedTokens(long requestedTokens) { return this; } - public Instant getTimeOfFirstRefill() { + public @Nullable Instant getTimeOfFirstRefill() { return timeOfFirstRefill; } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/ratelimit/RedisRateLimiter.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/ratelimit/RedisRateLimiter.java index 52d57363c1..9720ca0a61 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/ratelimit/RedisRateLimiter.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/ratelimit/RedisRateLimiter.java @@ -21,11 +21,13 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.concurrent.atomic.AtomicBoolean; import jakarta.validation.constraints.Min; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -93,13 +95,13 @@ public class RedisRateLimiter extends AbstractRateLimiter> script; + private @Nullable RedisScript> script; private AtomicBoolean initialized = new AtomicBoolean(false); - private Config defaultConfig; + private @Nullable Config defaultConfig; // configuration properties /** @@ -151,6 +153,7 @@ public RedisRateLimiter(int defaultReplenishRate, long defaultBurstCapacity) { */ public RedisRateLimiter(int defaultReplenishRate, long defaultBurstCapacity, int defaultRequestedTokens) { this(defaultReplenishRate, defaultBurstCapacity); + Objects.requireNonNull(this.defaultConfig, "defaultConfig may not be null"); this.defaultConfig.setRequestedTokens(defaultRequestedTokens); } @@ -226,7 +229,9 @@ public void setApplicationContext(ApplicationContext context) throws BeansExcept } } - /* for testing */ Config getDefaultConfig() { + @SuppressWarnings("NullAway") + /* for testing */ + Config getDefaultConfig() { return defaultConfig; } @@ -259,6 +264,8 @@ public Mono isAllowed(String routeId, String id) { // The arguments to the LUA script. time() returns unixtime in seconds. List scriptArgs = Arrays.asList(replenishRate + "", burstCapacity + "", "", requestedTokens + ""); // allowed, tokens_left = redis.eval(SCRIPT, keys, args) + Objects.requireNonNull(this.redisTemplate, "redisTemplate may not be null"); + Objects.requireNonNull(this.script, "script may not be null"); Flux> flux = this.redisTemplate.execute(this.script, keys, scriptArgs); // .log("redisratelimiter", Level.FINER); return flux.onErrorResume(throwable -> { @@ -290,6 +297,7 @@ public Mono isAllowed(String routeId, String id) { return Mono.just(new Response(true, getHeaders(routeConfig, -1L))); } + @SuppressWarnings("NullAway") /* for testing */ Config loadConfiguration(String routeId) { Config routeConfig = getConfig().getOrDefault(routeId, defaultConfig); diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/RoutePredicateHandlerMapping.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/RoutePredicateHandlerMapping.java index c80e707098..d12290b8bf 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/RoutePredicateHandlerMapping.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/RoutePredicateHandlerMapping.java @@ -18,6 +18,7 @@ import java.util.function.Function; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Mono; import org.springframework.cloud.gateway.config.GatewayProperties; @@ -47,7 +48,7 @@ public class RoutePredicateHandlerMapping extends AbstractHandlerMapping { private final RouteLocator routeLocator; - private final Integer managementPort; + private final @Nullable Integer managementPort; private final ManagementPortType managementPortType; @@ -71,7 +72,7 @@ private ManagementPortType getManagementPortType(Environment environment) { || (this.managementPort != 0 && this.managementPort.equals(serverPort))) ? SAME : DIFFERENT); } - private static Integer getPortProperty(Environment environment, String prefix) { + private static @Nullable Integer getPortProperty(Environment environment, String prefix) { return environment.getProperty(prefix + "port", Integer.class); } @@ -109,7 +110,7 @@ protected Mono getHandlerInternal(ServerWebExchange exchange) { } @Override - protected CorsConfiguration getCorsConfiguration(Object handler, ServerWebExchange exchange) { + protected @Nullable CorsConfiguration getCorsConfiguration(Object handler, ServerWebExchange exchange) { // TODO: support cors configuration via properties on a route see gh-229 // see RequestMappingHandlerMapping.initCorsConfiguration() // also see diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/AfterRoutePredicateFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/AfterRoutePredicateFactory.java index a45de2222d..17615f47df 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/AfterRoutePredicateFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/AfterRoutePredicateFactory.java @@ -22,6 +22,7 @@ import java.util.function.Predicate; import jakarta.validation.constraints.NotNull; +import org.jspecify.annotations.Nullable; import org.springframework.web.server.ServerWebExchange; @@ -68,9 +69,9 @@ public String toString() { public static class Config { @NotNull - private ZonedDateTime datetime; + private @Nullable ZonedDateTime datetime; - public ZonedDateTime getDatetime() { + public @Nullable ZonedDateTime getDatetime() { return datetime; } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/BeforeRoutePredicateFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/BeforeRoutePredicateFactory.java index d2919851c5..b6af3251f1 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/BeforeRoutePredicateFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/BeforeRoutePredicateFactory.java @@ -22,6 +22,7 @@ import java.util.function.Predicate; import jakarta.validation.constraints.NotNull; +import org.jspecify.annotations.Nullable; import org.springframework.web.server.ServerWebExchange; @@ -68,9 +69,9 @@ public String toString() { public static class Config { @NotNull - private ZonedDateTime datetime; + private @Nullable ZonedDateTime datetime; - public ZonedDateTime getDatetime() { + public @Nullable ZonedDateTime getDatetime() { return datetime; } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/BetweenRoutePredicateFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/BetweenRoutePredicateFactory.java index 177b61cd53..660e734561 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/BetweenRoutePredicateFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/BetweenRoutePredicateFactory.java @@ -22,6 +22,7 @@ import java.util.function.Predicate; import jakarta.validation.constraints.NotNull; +import org.jspecify.annotations.Nullable; import org.springframework.util.Assert; import org.springframework.web.server.ServerWebExchange; @@ -52,6 +53,7 @@ public List shortcutFieldOrder() { @Override public Predicate apply(Config config) { + Assert.notNull(config.getDatetime1(), DATETIME1_KEY + " must not be null"); Assert.isTrue(config.getDatetime1().isBefore(config.getDatetime2()), config.getDatetime1() + " must be before " + config.getDatetime2()); @@ -77,12 +79,12 @@ public String toString() { public static class Config { @NotNull - private ZonedDateTime datetime1; + private @Nullable ZonedDateTime datetime1; @NotNull - private ZonedDateTime datetime2; + private @Nullable ZonedDateTime datetime2; - public ZonedDateTime getDatetime1() { + public @Nullable ZonedDateTime getDatetime1() { return datetime1; } @@ -91,7 +93,7 @@ public Config setDatetime1(ZonedDateTime datetime1) { return this; } - public ZonedDateTime getDatetime2() { + public @Nullable ZonedDateTime getDatetime2() { return datetime2; } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/CookieRoutePredicateFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/CookieRoutePredicateFactory.java index ce59799845..d26d5972c5 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/CookieRoutePredicateFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/CookieRoutePredicateFactory.java @@ -21,6 +21,7 @@ import java.util.function.Predicate; import jakarta.validation.constraints.NotEmpty; +import org.jspecify.annotations.Nullable; import org.springframework.http.HttpCookie; import org.springframework.web.server.ServerWebExchange; @@ -55,7 +56,7 @@ public Predicate apply(Config config) { @Override public boolean test(ServerWebExchange exchange) { List cookies = exchange.getRequest().getCookies().get(config.name); - if (cookies == null) { + if (cookies == null || config.regexp == null) { return false; } return cookies.stream().anyMatch(cookie -> cookie.getValue().matches(config.regexp)); @@ -76,12 +77,12 @@ public String toString() { public static class Config { @NotEmpty - private String name; + private @Nullable String name; @NotEmpty - private String regexp; + private @Nullable String regexp; - public String getName() { + public @Nullable String getName() { return name; } @@ -90,7 +91,7 @@ public Config setName(String name) { return this; } - public String getRegexp() { + public @Nullable String getRegexp() { return regexp; } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/HeaderRoutePredicateFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/HeaderRoutePredicateFactory.java index da86f06ad9..276934cf98 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/HeaderRoutePredicateFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/HeaderRoutePredicateFactory.java @@ -22,6 +22,7 @@ import java.util.regex.Pattern; import jakarta.validation.constraints.NotEmpty; +import org.jspecify.annotations.Nullable; import org.springframework.util.StringUtils; import org.springframework.web.server.ServerWebExchange; @@ -57,6 +58,9 @@ public Predicate apply(Config config) { return new GatewayPredicate() { @Override public boolean test(ServerWebExchange exchange) { + if (!StringUtils.hasText(config.header)) { + return false; + } List values = exchange.getRequest().getHeaders().getValuesAsList(config.header); if (values.isEmpty()) { return false; @@ -92,11 +96,11 @@ public String toString() { public static class Config { @NotEmpty - private String header; + private @Nullable String header; - private String regexp; + private @Nullable String regexp; - public String getHeader() { + public @Nullable String getHeader() { return header; } @@ -105,11 +109,11 @@ public Config setHeader(String header) { return this; } - public String getRegexp() { + public @Nullable String getRegexp() { return regexp; } - public Config setRegexp(String regexp) { + public Config setRegexp(@Nullable String regexp) { this.regexp = regexp; return this; } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/HostRoutePredicateFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/HostRoutePredicateFactory.java index b605aa3696..f71cbe16cd 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/HostRoutePredicateFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/HostRoutePredicateFactory.java @@ -84,6 +84,10 @@ public boolean test(ServerWebExchange exchange) { } } + if (host == null) { + return false; + } + String match = null; for (int i = 0; i < config.getPatterns().size(); i++) { String pattern = config.getPatterns().get(i); diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/MethodRoutePredicateFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/MethodRoutePredicateFactory.java index 38d096e710..18a7abf02d 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/MethodRoutePredicateFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/MethodRoutePredicateFactory.java @@ -42,7 +42,7 @@ public MethodRoutePredicateFactory() { @Override public List shortcutFieldOrder() { - return Arrays.asList(METHODS_KEY); + return List.of(METHODS_KEY); } @Override @@ -68,7 +68,7 @@ public String toString() { public static class Config { - private HttpMethod[] methods; + private HttpMethod[] methods = new HttpMethod[0]; public HttpMethod[] getMethods() { return methods; diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/PathRoutePredicateFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/PathRoutePredicateFactory.java index 77982ca269..1b67b65d9d 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/PathRoutePredicateFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/PathRoutePredicateFactory.java @@ -121,7 +121,9 @@ public boolean test(ServerWebExchange exchange) { if (match != null) { traceMatch("Pattern", match.getPatternString(), path, true); PathMatchInfo pathMatchInfo = match.matchAndExtract(path); - putUriTemplateVariables(exchange, pathMatchInfo.getUriVariables()); + if (pathMatchInfo != null) { + putUriTemplateVariables(exchange, pathMatchInfo.getUriVariables()); + } exchange.getAttributes().put(GATEWAY_PREDICATE_MATCHED_PATH_ATTR, match.getPatternString()); String routeId = (String) exchange.getAttributes().get(GATEWAY_PREDICATE_ROUTE_ATTR); if (routeId != null) { diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/PredicateDefinition.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/PredicateDefinition.java index 2d7749897f..368a465843 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/PredicateDefinition.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/PredicateDefinition.java @@ -21,7 +21,7 @@ import java.util.Objects; import jakarta.validation.ValidationException; -import jakarta.validation.constraints.NotNull; +import org.jspecify.annotations.Nullable; import org.springframework.cloud.gateway.support.NameUtils; import org.springframework.validation.annotation.Validated; @@ -34,8 +34,7 @@ @Validated public class PredicateDefinition { - @NotNull - private String name; + private @Nullable String name; private Map args = new LinkedHashMap<>(); @@ -57,7 +56,7 @@ public PredicateDefinition(String text) { } } - public String getName() { + public @Nullable String getName() { return name; } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/QueryRoutePredicateFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/QueryRoutePredicateFactory.java index 48efcc3cb5..ace25f9706 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/QueryRoutePredicateFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/QueryRoutePredicateFactory.java @@ -22,6 +22,7 @@ import jakarta.validation.constraints.AssertTrue; import jakarta.validation.constraints.NotEmpty; +import org.jspecify.annotations.Nullable; import org.springframework.util.StringUtils; import org.springframework.web.server.ServerWebExchange; @@ -75,7 +76,7 @@ public boolean test(ServerWebExchange exchange) { predicate = value -> value.matches(config.regexp); } for (String value : values) { - if (value != null && predicate.test(value)) { + if (value != null && predicate != null && predicate.test(value)) { return true; } } @@ -97,13 +98,13 @@ public String toString() { public static class Config { @NotEmpty - private String param; + private @Nullable String param; - private String regexp; + private @Nullable String regexp; - private Predicate predicate; + private @Nullable Predicate predicate; - public String getParam() { + public @Nullable String getParam() { return this.param; } @@ -112,16 +113,16 @@ public Config setParam(String param) { return this; } - public String getRegexp() { + public @Nullable String getRegexp() { return this.regexp; } - public Config setRegexp(String regexp) { + public Config setRegexp(@Nullable String regexp) { this.regexp = regexp; return this; } - public Predicate getPredicate() { + public @Nullable Predicate getPredicate() { return this.predicate; } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/ReadBodyRoutePredicateFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/ReadBodyRoutePredicateFactory.java index cc583ff9a2..7e0dcecc15 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/ReadBodyRoutePredicateFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/ReadBodyRoutePredicateFactory.java @@ -22,12 +22,14 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.reactivestreams.Publisher; import reactor.core.publisher.Mono; import org.springframework.cloud.gateway.handler.AsyncPredicate; import org.springframework.cloud.gateway.support.ServerWebExchangeUtils; import org.springframework.http.codec.HttpMessageReader; +import org.springframework.util.Assert; import org.springframework.web.reactive.function.server.HandlerStrategies; import org.springframework.web.reactive.function.server.ServerRequest; import org.springframework.web.server.ServerWebExchange; @@ -75,7 +77,7 @@ public Publisher apply(ServerWebExchange exchange) { // multiple times if (cachedBody != null) { try { - boolean test = config.predicate.test(cachedBody); + boolean test = config.predicate != null && config.predicate.test(cachedBody); exchange.getAttributes().put(TEST_ATTRIBUTE, test); return Mono.just(test); } @@ -88,13 +90,15 @@ public Publisher apply(ServerWebExchange exchange) { return Mono.just(false); } else { + Assert.notNull(inClass, "inClass must not be null"); return ServerWebExchangeUtils.cacheRequestBodyAndRequest(exchange, (serverHttpRequest) -> ServerRequest .create(exchange.mutate().request(serverHttpRequest).build(), messageReaders) .bodyToMono(inClass) .doOnNext(objectValue -> exchange.getAttributes() .put(CACHE_REQUEST_BODY_OBJECT_KEY, objectValue)) - .map(objectValue -> config.getPredicate().test(objectValue))); + .map(objectValue -> config.getPredicate() != null + && config.getPredicate().test(objectValue))); } } @@ -118,13 +122,13 @@ public Predicate apply(Config config) { public static class Config { - private Class inClass; + private @Nullable Class inClass; - private Predicate predicate; + private @Nullable Predicate predicate; - private Map hints; + private @Nullable Map hints; - public Class getInClass() { + public @Nullable Class getInClass() { return inClass; } @@ -133,7 +137,7 @@ public Config setInClass(Class inClass) { return this; } - public Predicate getPredicate() { + public @Nullable Predicate getPredicate() { return predicate; } @@ -148,7 +152,7 @@ public Config setPredicate(Class inClass, Predicate predicate) { return this; } - public Map getHints() { + public @Nullable Map getHints() { return hints; } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/VersionRoutePredicateFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/VersionRoutePredicateFactory.java index e564202e5f..ac1e7f833c 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/VersionRoutePredicateFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/VersionRoutePredicateFactory.java @@ -39,14 +39,14 @@ public class VersionRoutePredicateFactory extends AbstractRoutePredicateFactory< private static final Log log = LogFactory.getLog(VersionRoutePredicateFactory.class); - private final ApiVersionStrategy apiVersionStrategy; + private final @Nullable ApiVersionStrategy apiVersionStrategy; public VersionRoutePredicateFactory(@Nullable ApiVersionStrategy apiVersionStrategy) { super(Config.class); this.apiVersionStrategy = apiVersionStrategy; } - private static void traceMatch(String prefix, Object desired, Object actual, boolean match) { + private static void traceMatch(String prefix, @Nullable Object desired, @Nullable Object actual, boolean match) { if (log.isTraceEnabled()) { log.trace(String.format("%s \"%s\" %s against value \"%s\"", prefix, desired, match ? "matches" : "does not match", actual)); @@ -62,8 +62,11 @@ public List shortcutFieldOrder() { public Predicate apply(Config config) { if (apiVersionStrategy instanceof DefaultApiVersionStrategy strategy) { - strategy.addMappedVersion((config.version.endsWith("+") - ? config.version.substring(0, config.version.length() - 1) : config.version)); + String version = config.version; + if (version != null) { + strategy + .addMappedVersion((version.endsWith("+") ? version.substring(0, version.length() - 1) : version)); + } } return new GatewayPredicate() { @@ -72,7 +75,9 @@ public boolean test(ServerWebExchange exchange) { ServerHttpRequest request = exchange.getRequest(); if (config.parsedVersion == null) { Assert.state(apiVersionStrategy != null, "No ApiVersionStrategy to parse version with"); - config.parsedVersion = apiVersionStrategy.parseVersion(config.version); + String version = config.version; + Assert.notNull(version, "version must not be null"); + config.parsedVersion = apiVersionStrategy.parseVersion(version); } Comparable requestVersion = (Comparable) request.getAttributes() @@ -110,9 +115,9 @@ public static class Config { private boolean baselineVersion; @NotBlank - private String version; + private @Nullable String version; - private String originalVersion; + private @Nullable String originalVersion; private @Nullable Comparable parsedVersion; @@ -120,7 +125,7 @@ public boolean isBaselineVersion() { return baselineVersion; } - public String getOriginalVersion() { + public @Nullable String getOriginalVersion() { return originalVersion; } @@ -128,7 +133,7 @@ public String getOriginalVersion() { return parsedVersion; } - public String getVersion() { + public @Nullable String getVersion() { return version; } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/WeightRoutePredicateFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/WeightRoutePredicateFactory.java index f0b34b3f73..422c03ffd5 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/WeightRoutePredicateFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/WeightRoutePredicateFactory.java @@ -24,6 +24,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.springframework.cloud.gateway.event.WeightDefinedEvent; import org.springframework.cloud.gateway.support.WeightConfig; @@ -53,7 +54,7 @@ public class WeightRoutePredicateFactory extends AbstractRoutePredicateFactory apply(Config config) { if (log.isDebugEnabled()) { ServerHttpRequest request = exchange.getRequest(); - log.debug("Request for \"" + request.getURI() + "\" from client \"" - + request.getRemoteAddress().getAddress().getHostAddress() + "\" with \"" + String clientAddress = request.getRemoteAddress() != null + ? request.getRemoteAddress().getAddress().getHostAddress() : "unknown"; + log.debug("Request for \"" + request.getURI() + "\" from client \"" + clientAddress + "\" with \"" + XForwardedRemoteAddressResolver.X_FORWARDED_FOR + "\" header value of \"" + request.getHeaders().get(XForwardedRemoteAddressResolver.X_FORWARDED_FOR) + "\" is " + (isAllowed ? "ALLOWED" : "NOT ALLOWED")); diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/route/CachingRouteLocator.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/route/CachingRouteLocator.java index b36b1a10fd..e499f6d5ed 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/route/CachingRouteLocator.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/route/CachingRouteLocator.java @@ -18,11 +18,13 @@ import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import reactor.cache.CacheFlux; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -52,7 +54,7 @@ public class CachingRouteLocator private final Map cache = new ConcurrentHashMap<>(); - private ApplicationEventPublisher applicationEventPublisher; + private @Nullable ApplicationEventPublisher applicationEventPublisher; public CachingRouteLocator(RouteLocator delegate) { this.delegate = delegate; @@ -111,6 +113,7 @@ private synchronized void updateCache(Flux routes) { private void publishRefreshEvent(List> signals) { cache.put(CACHE_KEY, signals); + Objects.requireNonNull(applicationEventPublisher, "ApplicationEventPublisher is required"); applicationEventPublisher.publishEvent(new RefreshRoutesResultEvent(this)); } @@ -123,6 +126,7 @@ private void handleRefreshError(Throwable throwable) { if (log.isErrorEnabled()) { log.error("Refresh routes error !!!", throwable); } + Objects.requireNonNull(applicationEventPublisher, "ApplicationEventPublisher is required"); applicationEventPublisher.publishEvent(new RefreshRoutesResultEvent(this, throwable)); } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/route/RedisRouteDefinitionRepository.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/route/RedisRouteDefinitionRepository.java index a80f3faad0..d4f7f03314 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/route/RedisRouteDefinitionRepository.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/route/RedisRouteDefinitionRepository.java @@ -16,6 +16,8 @@ package org.springframework.cloud.gateway.route; +import java.util.Objects; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import reactor.core.publisher.Flux; @@ -63,15 +65,19 @@ public Flux getRouteDefinitions() { @Override public Mono save(Mono route) { - return route.flatMap(routeDefinition -> routeDefinitionReactiveValueOperations - .set(createKey(routeDefinition.getId()), routeDefinition) - .flatMap(success -> { - if (success) { - return Mono.empty(); - } - return Mono.defer(() -> Mono.error(new RuntimeException( - String.format("Could not add route to redis repository: %s", routeDefinition)))); - })); + return route.flatMap(routeDefinition -> { + Objects.requireNonNull(routeDefinition.getId(), "id may not be null"); + return routeDefinitionReactiveValueOperations.set(createKey(routeDefinition.getId()), routeDefinition) + .flatMap(success -> { + if (success) { + return Mono.empty(); + } + return Mono.defer(() -> Mono.error(new RuntimeException( + String.format("Could not add route to redis repository: %s", routeDefinition)))); + + }); + }); + } @Override diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/route/Route.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/route/Route.java index 0da1e22ae3..baf598af2e 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/route/Route.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/route/Route.java @@ -27,6 +27,8 @@ import java.util.Objects; import java.util.function.Predicate; +import org.jspecify.annotations.Nullable; + import org.springframework.cloud.gateway.filter.GatewayFilter; import org.springframework.cloud.gateway.handler.AsyncPredicate; import org.springframework.cloud.gateway.route.builder.Buildable; @@ -71,10 +73,15 @@ public static Builder builder() { public static Builder builder(RouteDefinition routeDefinition) { // @formatter:off - return new Builder().id(routeDefinition.getId()) - .uri(routeDefinition.getUri()) - .order(routeDefinition.getOrder()) + Builder builder = new Builder().order(routeDefinition.getOrder()) .metadata(routeDefinition.getMetadata()); + if (routeDefinition.getUri() != null) { + builder.uri(routeDefinition.getUri()); + } + if (routeDefinition.getId() != null) { + builder.id(routeDefinition.getId()); + } + return builder; // @formatter:on } @@ -84,10 +91,16 @@ public static AsyncBuilder async() { public static AsyncBuilder async(RouteDefinition routeDefinition) { // @formatter:off - return new AsyncBuilder().id(routeDefinition.getId()) - .uri(routeDefinition.getUri()) + AsyncBuilder asyncBuilder = new AsyncBuilder() .order(routeDefinition.getOrder()) .metadata(routeDefinition.getMetadata()); + if (routeDefinition.getUri() != null) { + asyncBuilder.uri(routeDefinition.getUri()); + } + if (routeDefinition.getId() != null) { + asyncBuilder.id(routeDefinition.getId()); + } + return asyncBuilder; // @formatter:on } @@ -150,9 +163,9 @@ public String toString() { public abstract static class AbstractBuilder> implements Buildable { - protected String id; + protected @Nullable String id; - protected URI uri; + protected @Nullable URI uri; protected int order = 0; @@ -170,7 +183,7 @@ public B id(String id) { return getThis(); } - public String getId() { + public @Nullable String getId() { return id; } @@ -211,7 +224,7 @@ public B metadata(Map metadata) { return getThis(); } - public B metadata(String key, Object value) { + public B metadata(@Nullable String key, @Nullable Object value) { this.metadata.put(key, value); return getThis(); } @@ -250,7 +263,7 @@ public Route build() { public static class AsyncBuilder extends AbstractBuilder { - protected AsyncPredicate predicate; + protected @Nullable AsyncPredicate predicate; @Override protected AsyncBuilder getThis() { @@ -259,6 +272,7 @@ protected AsyncBuilder getThis() { @Override public AsyncPredicate getPredicate() { + Assert.notNull(this.predicate, "predicate can not be null"); return this.predicate; } @@ -293,7 +307,7 @@ public AsyncBuilder negate() { public static class Builder extends AbstractBuilder { - protected Predicate predicate; + protected @Nullable Predicate predicate; @Override protected Builder getThis() { diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/route/RouteDefinition.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/route/RouteDefinition.java index 56eff40124..58a6c04011 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/route/RouteDefinition.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/route/RouteDefinition.java @@ -26,7 +26,7 @@ import jakarta.validation.Valid; import jakarta.validation.ValidationException; import jakarta.validation.constraints.NotEmpty; -import jakarta.validation.constraints.NotNull; +import org.jspecify.annotations.Nullable; import org.springframework.cloud.gateway.filter.FilterDefinition; import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition; @@ -40,7 +40,7 @@ @Validated public class RouteDefinition { - private String id; + private @Nullable String id; @NotEmpty @Valid @@ -49,8 +49,7 @@ public class RouteDefinition { @Valid private List filters = new ArrayList<>(); - @NotNull - private URI uri; + private @Nullable URI uri; private Map metadata = new HashMap<>(); @@ -79,7 +78,7 @@ public RouteDefinition(String text) { } } - public String getId() { + public @Nullable String getId() { return id; } @@ -103,7 +102,7 @@ public void setFilters(List filters) { this.filters = filters; } - public URI getUri() { + public @Nullable URI getUri() { return uri; } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/route/RouteDefinitionRouteLocator.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/route/RouteDefinitionRouteLocator.java index 89798f3e7e..e70f46a2b6 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/route/RouteDefinitionRouteLocator.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/route/RouteDefinitionRouteLocator.java @@ -21,6 +21,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -179,7 +180,7 @@ List loadGatewayFilters(String id, List filterD private List getFilters(RouteDefinition routeDefinition) { List filters = new ArrayList<>(); - + Objects.requireNonNull(routeDefinition.getId(), "Route id must be set"); // TODO: support option to apply defaults after route specific filters? if (!this.gatewayProperties.getDefaultFilters().isEmpty()) { filters.addAll(loadGatewayFilters(routeDefinition.getId(), @@ -222,8 +223,11 @@ private AsyncPredicate lookup(RouteDefinition route, Predicat Object config = this.configurationService.with(factory) .name(predicate.getName()) .properties(predicate.getArgs()) - .eventFunction((bound, properties) -> new PredicateArgsEvent( - RouteDefinitionRouteLocator.this, route.getId(), properties)) + .eventFunction((bound, properties) -> { + Objects.requireNonNull(route.getId(), "Route id must be set"); + return new PredicateArgsEvent(RouteDefinitionRouteLocator.this, route.getId(), properties); + } + ) .bind(); // @formatter:on diff --git a/spring-cloud-gateway-server-webflux/src/test/java/org/springframework/cloud/gateway/filter/ratelimit/RedisRateLimiterUnitTests.java b/spring-cloud-gateway-server-webflux/src/test/java/org/springframework/cloud/gateway/filter/ratelimit/RedisRateLimiterUnitTests.java index fa40b42be6..33389e7e58 100644 --- a/spring-cloud-gateway-server-webflux/src/test/java/org/springframework/cloud/gateway/filter/ratelimit/RedisRateLimiterUnitTests.java +++ b/spring-cloud-gateway-server-webflux/src/test/java/org/springframework/cloud/gateway/filter/ratelimit/RedisRateLimiterUnitTests.java @@ -33,8 +33,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.assertj.core.data.MapEntry.entry; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.Mockito.when; /** @@ -84,7 +82,6 @@ public void shouldThrowWhenNotInitialized() { @Test public void shouldAllowRequestWhenRedisIssueOccurs() { - when(redisTemplate.execute(any(), anyList(), anyList())).thenThrow(REDIS_EXCEPTION); redisRateLimiter.setApplicationContext(applicationContext); Mono response = redisRateLimiter.isAllowed(ROUTE_ID, REQUEST_ID); assertThat(response.block()).extracting(RateLimiter.Response::isAllowed).isEqualTo(true); @@ -92,7 +89,6 @@ public void shouldAllowRequestWhenRedisIssueOccurs() { @Test public void shouldReturnHeadersWhenRedisIssueOccurs() { - when(redisTemplate.execute(any(), anyList(), anyList())).thenThrow(REDIS_EXCEPTION); redisRateLimiter.setApplicationContext(applicationContext); Mono response = redisRateLimiter.isAllowed(ROUTE_ID, REQUEST_ID); assertThat(response.block().getHeaders()).containsOnly(entry(redisRateLimiter.getRemainingHeader(), "-1"), diff --git a/spring-cloud-gateway-server-webflux/src/test/resources/application-disable-components.yml b/spring-cloud-gateway-server-webflux/src/test/resources/application-disable-components.yml index ade6bdf3fc..123951977d 100644 --- a/spring-cloud-gateway-server-webflux/src/test/resources/application-disable-components.yml +++ b/spring-cloud-gateway-server-webflux/src/test/resources/application-disable-components.yml @@ -1,8 +1,8 @@ -server: - error: - include-message: always spring: + web: + error: + include-message: always config: import: classpath:application-logging.yml diff --git a/spring-cloud-gateway-server-webflux/src/test/resources/application-netty-routing-filter.yml b/spring-cloud-gateway-server-webflux/src/test/resources/application-netty-routing-filter.yml index 9356078b4d..42c921bf00 100644 --- a/spring-cloud-gateway-server-webflux/src/test/resources/application-netty-routing-filter.yml +++ b/spring-cloud-gateway-server-webflux/src/test/resources/application-netty-routing-filter.yml @@ -4,11 +4,10 @@ test: my.timeout: 3000 -server: - error: - include-message: always - spring: + web: + error: + include-message: always profiles: group: - logging diff --git a/spring-cloud-gateway-server-webflux/src/test/resources/application.yml b/spring-cloud-gateway-server-webflux/src/test/resources/application.yml index 4e1a44aa1a..7c0f597538 100644 --- a/spring-cloud-gateway-server-webflux/src/test/resources/application.yml +++ b/spring-cloud-gateway-server-webflux/src/test/resources/application.yml @@ -4,11 +4,10 @@ test: # uri: http://${test.hostport} uri: lb://testservice -server: - error: - include-message: always - spring: + web: + error: + include-message: always profiles: group: - logging From 4d76aa92d8217be2ae464d0db4b9204434ddff04 Mon Sep 17 00:00:00 2001 From: Ryan Baxter Date: Fri, 21 Nov 2025 11:45:03 -0500 Subject: [PATCH 2/3] NullAway changes for server-webmvc --- .../ReactiveLoadBalancerClientFilter.java | 3 +- .../GatewayServerMvcAutoConfiguration.java | 3 + .../gateway/server/mvc/common/MvcUtils.java | 31 ++++++-- .../server/mvc/common/WeightConfig.java | 4 +- .../server/mvc/config/FilterProperties.java | 5 +- .../mvc/config/GatewayMvcProperties.java | 5 +- .../GatewayMvcRuntimeHintsProcessor.java | 3 +- .../mvc/config/PredicateProperties.java | 5 +- .../server/mvc/config/RouteProperties.java | 9 +-- .../config/RouterFunctionHolderFactory.java | 26 +++++-- .../mvc/filter/BodyFilterFunctions.java | 2 +- .../mvc/filter/Bucket4jFilterFunctions.java | 12 ++-- .../filter/CircuitBreakerFilterFunctions.java | 11 +-- .../mvc/filter/FilterAutoConfiguration.java | 9 ++- .../filter/ForwardedRequestHeadersFilter.java | 72 ++++++++++--------- ...LocationResponseHeaderFilterFunctions.java | 6 +- .../mvc/filter/TokenRelayFilterFunctions.java | 12 ++-- .../mvc/filter/WeightCalculatorFilter.java | 10 ++- .../XForwardedRequestHeadersFilter.java | 9 ++- ...ClientHttpRequestFactoryProxyExchange.java | 3 + .../handler/FunctionHandlerHeaderUtils.java | 12 ++-- .../handler/GatewayEntityResponseBuilder.java | 8 +-- .../HandlerFunctionAutoConfiguration.java | 32 ++++++--- .../server/mvc/handler/HandlerFunctions.java | 8 ++- .../server/mvc/handler/ProxyExchange.java | 8 ++- .../mvc/handler/RestClientProxyExchange.java | 3 + .../server/mvc/invoke/InvocationContext.java | 4 +- .../mvc/invoke/OperationArgumentResolver.java | 4 +- ...ConversionServiceParameterValueMapper.java | 6 +- .../convert/IsoOffsetDateTimeConverter.java | 4 +- .../reflect/OperationMethodParameters.java | 14 ++-- .../reflect/ReflectiveOperationInvoker.java | 12 +++- 32 files changed, 236 insertions(+), 119 deletions(-) diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/ReactiveLoadBalancerClientFilter.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/ReactiveLoadBalancerClientFilter.java index 902e09773f..a17bea2c3d 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/ReactiveLoadBalancerClientFilter.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/ReactiveLoadBalancerClientFilter.java @@ -85,7 +85,8 @@ public int getOrder() { } @Override - // TODO remove this suppress warnings once the commons changes are merged in for CompletionContext + // TODO remove this suppress warnings once the commons changes are merged in for + // CompletionContext @SuppressWarnings("NullAway") public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { URI url = exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR); diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfiguration.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfiguration.java index 09743e2fe1..8f36aff0bb 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfiguration.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfiguration.java @@ -17,6 +17,7 @@ package org.springframework.cloud.gateway.server.mvc; import java.util.Map; +import java.util.Objects; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.ObjectProvider; @@ -130,6 +131,7 @@ public FormFilter formFilter() { @ConditionalOnMissingBean @Conditional(TrustedProxies.ForwardedTrustedProxiesCondition.class) public ForwardedRequestHeadersFilter forwardedRequestHeadersFilter(GatewayMvcProperties properties) { + Objects.requireNonNull(properties.getTrustedProxies(), "trustedProxies must not be null"); return new ForwardedRequestHeadersFilter(properties.getTrustedProxies()); } @@ -207,6 +209,7 @@ public WeightCalculatorFilter weightCalculatorFilter() { @Conditional(TrustedProxies.XForwardedTrustedProxiesCondition.class) public XForwardedRequestHeadersFilter xForwardedRequestHeadersFilter(XForwardedRequestHeadersFilterProperties props, GatewayMvcProperties gatewayMvcProperties) { + Objects.requireNonNull(gatewayMvcProperties.getTrustedProxies(), "trustedProxies must not be null"); return new XForwardedRequestHeadersFilter(props, gatewayMvcProperties.getTrustedProxies()); } diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/MvcUtils.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/MvcUtils.java index 1ebd49e0e8..f852d27988 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/MvcUtils.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/MvcUtils.java @@ -152,7 +152,11 @@ public static String expand(ServerRequest request, String template) { } Map variables = getUriTemplateVariables(request); try { - return UriComponentsBuilder.fromPath(template).build().expand(variables).getPath(); + String path = UriComponentsBuilder.fromPath(template).build().expand(variables).getPath(); + if (path == null) { + return template; + } + return path; } catch (IllegalArgumentException e) { log.trace(LogMessage.format("unable to find substitution for %s", template), e); @@ -207,8 +211,15 @@ public static Map getUriTemplateVariables(ServerRequest request) } public static void putAttribute(ServerRequest request, String key, @Nullable Object value) { - request.attributes().put(key, value); - getGatewayAttributes(request).put(key, value); + if (value == null) { + request.attributes().remove(key); + getGatewayAttributes(request).remove(key); + } + else { + request.attributes().put(key, value); + getGatewayAttributes(request).put(key, value); + } + } @SuppressWarnings("unchecked") @@ -219,7 +230,7 @@ public static void putUriTemplateVariables(ServerRequest request, Map Map mergeMaps(Map left, Map right) { + public static Map mergeMaps(@Nullable Map left, @Nullable Map right) { if (CollectionUtils.isEmpty(left)) { if (CollectionUtils.isEmpty(right)) { return Collections.emptyMap(); @@ -259,9 +270,15 @@ public static Optional readBody(ServerRequest request, ByteArrayInputStre return Optional.empty(); } - public static void setRouteId(ServerRequest request, String routeId) { - request.attributes().put(GATEWAY_ROUTE_ID_ATTR, routeId); - request.servletRequest().setAttribute(GATEWAY_ROUTE_ID_ATTR, routeId); + public static void setRouteId(ServerRequest request, @Nullable String routeId) { + if (routeId == null) { + request.attributes().remove(GATEWAY_ROUTE_ID_ATTR); + request.servletRequest().removeAttribute(GATEWAY_ROUTE_ID_ATTR); + } + else { + request.attributes().put(GATEWAY_ROUTE_ID_ATTR, routeId); + request.servletRequest().setAttribute(GATEWAY_ROUTE_ID_ATTR, routeId); + } } public static void setRequestUrl(ServerRequest request, URI url) { diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/WeightConfig.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/WeightConfig.java index 5cd2055000..59a49130d0 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/WeightConfig.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/WeightConfig.java @@ -32,7 +32,7 @@ public class WeightConfig { public static final String CONFIG_PREFIX = "weight"; @NotEmpty - private String group; + private @Nullable String group; private @Nullable String routeId; @@ -52,7 +52,7 @@ public WeightConfig(String routeId) { this.routeId = routeId; } - public String getGroup() { + public @Nullable String getGroup() { return group; } diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/FilterProperties.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/FilterProperties.java index 410536d04b..aed0c8b1e1 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/FilterProperties.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/FilterProperties.java @@ -21,6 +21,7 @@ import java.util.Objects; import jakarta.validation.constraints.NotNull; +import org.jspecify.annotations.Nullable; import org.springframework.cloud.gateway.server.mvc.common.NameUtils; import org.springframework.validation.annotation.Validated; @@ -34,7 +35,7 @@ public class FilterProperties { @NotNull - private String name; + private @Nullable String name; private Map args = new LinkedHashMap<>(); @@ -56,7 +57,7 @@ public FilterProperties(String text) { } } - public String getName() { + public @Nullable String getName() { return name; } diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/GatewayMvcProperties.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/GatewayMvcProperties.java index dc9f8da09b..ed75754cb7 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/GatewayMvcProperties.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/GatewayMvcProperties.java @@ -23,6 +23,7 @@ import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; +import org.jspecify.annotations.Nullable; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.core.style.ToStringCreator; @@ -66,7 +67,7 @@ public class GatewayMvcProperties { * Regular expression defining proxies that are trusted when they appear in a * Forwarded of X-Forwarded header. */ - private String trustedProxies; + private @Nullable String trustedProxies; /** * 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) { this.streamingBufferSize = streamingBufferSize; } - public String getTrustedProxies() { + public @Nullable String getTrustedProxies() { return trustedProxies; } diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/GatewayMvcRuntimeHintsProcessor.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/GatewayMvcRuntimeHintsProcessor.java index 359e6896b9..927bcfc508 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/GatewayMvcRuntimeHintsProcessor.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/GatewayMvcRuntimeHintsProcessor.java @@ -27,6 +27,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.springframework.aot.hint.MemberCategory; import org.springframework.aot.hint.ReflectionHints; @@ -106,7 +107,7 @@ private static Set> getTypesToRegister(String packageName) { return classesToAdd.stream().filter(Objects::nonNull).collect(Collectors.toSet()); } - private static void addEnclosingClassesForClass(Set> enclosingClasses, Class clazz) { + private static void addEnclosingClassesForClass(Set> enclosingClasses, @Nullable Class clazz) { if (clazz == null) { return; } diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/PredicateProperties.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/PredicateProperties.java index 405b4e5867..709bb453d9 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/PredicateProperties.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/PredicateProperties.java @@ -22,6 +22,7 @@ import jakarta.validation.ValidationException; import jakarta.validation.constraints.NotNull; +import org.jspecify.annotations.Nullable; import org.springframework.cloud.gateway.server.mvc.common.NameUtils; import org.springframework.validation.annotation.Validated; @@ -35,7 +36,7 @@ public class PredicateProperties { @NotNull - private String name; + private @Nullable String name; private Map args = new LinkedHashMap<>(); @@ -57,7 +58,7 @@ public PredicateProperties(String text) { } } - public String getName() { + public @Nullable String getName() { return name; } diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/RouteProperties.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/RouteProperties.java index cb419fc7dd..a2157cf54c 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/RouteProperties.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/RouteProperties.java @@ -27,6 +27,7 @@ import jakarta.validation.ValidationException; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; +import org.jspecify.annotations.Nullable; import org.springframework.validation.annotation.Validated; @@ -41,7 +42,7 @@ public class RouteProperties { /** * The Route ID. */ - private String id; + private @Nullable String id; /** * List of predicates for matching the Route. @@ -60,7 +61,7 @@ public class RouteProperties { * The destination URI. */ @NotNull - private URI uri; + private @Nullable URI uri; /** * Metadata associated with the Route. @@ -93,7 +94,7 @@ public RouteProperties(String text) { } } - public String getId() { + public @Nullable String getId() { return id; } @@ -117,7 +118,7 @@ public void setFilters(List filters) { this.filters = filters; } - public URI getUri() { + public @Nullable URI getUri() { return uri; } diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/RouterFunctionHolderFactory.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/RouterFunctionHolderFactory.java index 14c66a900f..e788f363bc 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/RouterFunctionHolderFactory.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/RouterFunctionHolderFactory.java @@ -25,6 +25,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; @@ -32,6 +33,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanNotOfRequiredTypeException; @@ -153,6 +155,7 @@ private GatewayMvcPropertiesBeanDefinitionRegistrar.RouterFunctionHolder routerF Map routerFunctions = new LinkedHashMap<>(); properties.getRoutes().forEach(routeProperties -> { + Objects.requireNonNull(routeProperties.getId(), "Route id is required"); routerFunctions.put(routeProperties.getId(), getRouterFunction(routeProperties, routeProperties.getId())); }); properties.getRoutesMap().forEach((routeId, routeProperties) -> { @@ -171,6 +174,7 @@ private GatewayMvcPropertiesBeanDefinitionRegistrar.RouterFunctionHolder routerF routerFunction = routerFunctions.values().stream().reduce(RouterFunction::andOther).orElse(null); // puts the map of configured RouterFunctions in an attribute. Makes testing // easy. + Objects.requireNonNull(routerFunction, "Unable to create RouterFunction"); routerFunction = routerFunction.withAttribute("gatewayRouterFunctions", routerFunctions); } log.trace(LogMessage.format("RouterFunctionHolder initialized %s", routerFunction.toString())); @@ -186,7 +190,11 @@ private RouterFunction getRouterFunction(RouteProperties routeProperties, String MultiValueMap handlerOperations = handlerDiscoverer.getOperations(); // TODO: cache? // translate handlerFunction - String scheme = routeProperties.getUri().getScheme(); + + String scheme = "http"; + if (routeProperties.getUri() != null && routeProperties.getUri().getScheme() != null) { + scheme = routeProperties.getUri().getScheme(); + } // filters added by HandlerDiscoverer need to go last, so save them HandlerFunction handlerFunction = null; @@ -246,7 +254,7 @@ else if (response instanceof HandlerDiscoverer.Result result) { predicateOperations.addAll(predicateBeanFactoryDiscoverer.getOperations()); } predicateOperations.addAll(predicateDiscoverer.getOperations()); - final AtomicReference predicate = new AtomicReference<>(); + final AtomicReference<@Nullable RequestPredicate> predicate = new AtomicReference<>(); routeProperties.getPredicates().forEach(predicateProperties -> { Map args = new LinkedHashMap<>(predicateProperties.getArgs()); @@ -265,7 +273,8 @@ else if (response instanceof HandlerDiscoverer.Result result) { }); // combine predicate and handlerFunction - builder.route(predicate.get(), handlerFunction); + RequestPredicate check = Objects.requireNonNull(predicate.get(), "Unable to create RequestPredicate"); + builder.route(check, handlerFunction); predicate.set(null); // HandlerDiscoverer filters needing lower priority, so put them first @@ -290,9 +299,12 @@ else if (response instanceof HandlerDiscoverer.Result result) { return builder.build(); } - private void translate(MultiValueMap operations, String operationName, + private void translate(MultiValueMap operations, @Nullable String operationName, Map operationArgs, Class returnType, Consumer operationHandler) { - String normalizedName = StringUtils.uncapitalize(operationName); + String normalizedName = operationName; + if (operationName != null) { + normalizedName = StringUtils.uncapitalize(operationName); + } Optional operationMethod = findOperation(operations, normalizedName, operationArgs); if (operationMethod.isPresent()) { NormalizedOperationMethod opMethod = operationMethod.get(); @@ -313,7 +325,7 @@ private void translate(MultiValueMap operations, St } private Optional findOperation(MultiValueMap operations, - String operationName, Map operationArgs) { + @Nullable String operationName, Map operationArgs) { return operations.getOrDefault(operationName, Collections.emptyList()) .stream() .sorted(Comparator.comparing(OperationMethod::isConfigurable)) @@ -381,7 +393,7 @@ public boolean canResolve(Class type) { } @Override - public T resolve(Class type) { + public @Nullable T resolve(Class type) { return null; } diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/BodyFilterFunctions.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/BodyFilterFunctions.java index b2567206ca..ec3c0f9891 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/BodyFilterFunctions.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/BodyFilterFunctions.java @@ -421,7 +421,7 @@ public Optional checkNotModified(Instant lastModified, String et } @Override - public ApiVersionStrategy apiVersionStrategy() { + public @Nullable ApiVersionStrategy apiVersionStrategy() { return delegate.apiVersionStrategy(); } diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/Bucket4jFilterFunctions.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/Bucket4jFilterFunctions.java index eb709343f0..12910b1177 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/Bucket4jFilterFunctions.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/Bucket4jFilterFunctions.java @@ -28,6 +28,7 @@ import io.github.bucket4j.ConsumptionProbe; import io.github.bucket4j.distributed.AsyncBucketProxy; import io.github.bucket4j.distributed.proxy.AsyncProxyManager; +import org.jspecify.annotations.Nullable; import org.springframework.cloud.gateway.server.mvc.common.MvcUtils; import org.springframework.core.task.TaskExecutor; @@ -73,7 +74,7 @@ public static HandlerFilterFunction rateLimit( return (request, next) -> { AsyncProxyManager proxyManager = MvcUtils.getApplicationContext(request).getBean(AsyncProxyManager.class); - String key = config.getKeyResolver().apply(request); + String key = config.getKeyResolver() != null ? config.getKeyResolver().apply(request) : ""; if (!StringUtils.hasText(key)) { // TODO: configurable empty key status code return ServerResponse.status(HttpStatus.FORBIDDEN).build(); @@ -110,12 +111,15 @@ public static class RateLimitConfig { long capacity; + @org.jspecify.annotations.Nullable Duration period; + @org.jspecify.annotations.Nullable Function keyResolver; HttpStatusCode statusCode = HttpStatus.TOO_MANY_REQUESTS; + @org.jspecify.annotations.Nullable Duration timeout; int tokens = 1; @@ -140,7 +144,7 @@ public RateLimitConfig setCapacity(long capacity) { return this; } - public Duration getPeriod() { + public @Nullable Duration getPeriod() { return period; } @@ -149,7 +153,7 @@ public RateLimitConfig setPeriod(Duration period) { return this; } - public Function getKeyResolver() { + public @Nullable Function getKeyResolver() { return keyResolver; } @@ -168,7 +172,7 @@ public RateLimitConfig setStatusCode(HttpStatusCode statusCode) { return this; } - public Duration getTimeout() { + public @Nullable Duration getTimeout() { return timeout; } diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/CircuitBreakerFilterFunctions.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/CircuitBreakerFilterFunctions.java index 2f5593a226..85b8d39afb 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/CircuitBreakerFilterFunctions.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/CircuitBreakerFilterFunctions.java @@ -106,8 +106,8 @@ public static HandlerFilterFunction circuitBreak } // TODO: if not permitted (like circuit open), SERVICE_UNAVAILABLE // TODO: if resume without error, return ok response? - throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, throwable.getMessage(), - throwable); + throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, + throwable != null ? throwable.getMessage() : null, throwable); } // add the throwable as an attribute. That way, if the fallback is a @@ -119,7 +119,8 @@ public static HandlerFilterFunction circuitBreak // ok() is wrong, but will be overwritten by the forwarded request return GatewayServerResponse.ok().build((httpServletRequest, httpServletResponse) -> { try { - String expandedFallback = MvcUtils.expand(request, config.getFallbackPath()); + String expandedFallback = MvcUtils.expand(request, + config.getFallbackPath() != null ? config.getFallbackPath() : ""); request.servletRequest() .getServletContext() .getRequestDispatcher(expandedFallback) @@ -136,13 +137,13 @@ public static HandlerFilterFunction circuitBreak public static class CircuitBreakerConfig { - private String id; + private @Nullable String id; private @Nullable String fallbackPath; private Set statusCodes = new HashSet<>(); - public String getId() { + public @Nullable String getId() { return id; } diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/FilterAutoConfiguration.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/FilterAutoConfiguration.java index f4ad1b3709..4a58098740 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/FilterAutoConfiguration.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/FilterAutoConfiguration.java @@ -17,6 +17,7 @@ package org.springframework.cloud.gateway.server.mvc.filter; import java.util.Collections; +import java.util.Objects; import java.util.function.Function; import io.github.bucket4j.BucketConfiguration; @@ -75,9 +76,11 @@ public static class LoadBalancerHandlerConfiguration { @Bean public Function lbHandlerFunctionDefinition() { - return routeProperties -> new HandlerFunctionDefinition.Default("lb", HandlerFunctions.http(), - Collections.emptyList(), - Collections.singletonList(LoadBalancerFilterFunctions.lb(routeProperties.getUri().getHost()))); + return routeProperties -> { + Objects.requireNonNull(routeProperties.getUri(), "routeProperties.uri must not be null"); + return new HandlerFunctionDefinition.Default("lb", HandlerFunctions.http(), Collections.emptyList(), + Collections.singletonList(LoadBalancerFilterFunctions.lb(routeProperties.getUri().getHost()))); + }; } } diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/ForwardedRequestHeadersFilter.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/ForwardedRequestHeadersFilter.java index 87640014ab..be08ec4e06 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/ForwardedRequestHeadersFilter.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/ForwardedRequestHeadersFilter.java @@ -130,51 +130,57 @@ public HttpHeaders apply(HttpHeaders input, ServerRequest request) { } } - List forwardeds = parse(original.get(FORWARDED_HEADER)); - - for (Forwarded f : forwardeds) { - // only add if "for" value matches trustedProxies - if (trustedProxies.isTrusted(f.get("for"))) { - updated.add(FORWARDED_HEADER, f.toHeaderValue()); + List forwardedHeader = original.get(FORWARDED_HEADER); + if (forwardedHeader != null) { + List forwardeds = parse(forwardedHeader); + + for (Forwarded f : forwardeds) { + // only add if "for" value matches trustedProxies + if (trustedProxies.isTrusted(f.get("for"))) { + updated.add(FORWARDED_HEADER, f.toHeaderValue()); + } } } // TODO: add new forwarded URI uri = request.uri(); String host = original.getFirst(HttpHeaders.HOST); - Forwarded forwarded = new Forwarded().put("host", host).put("proto", uri.getScheme()); - - request.remoteAddress().ifPresent(remoteAddress -> { - // If remoteAddress is unresolved, calling getHostAddress() would cause a - // NullPointerException. - String forValue; - if (remoteAddress.isUnresolved()) { - forValue = remoteAddress.getHostName(); - } - else { - InetAddress address = remoteAddress.getAddress(); - forValue = remoteAddress.getAddress().getHostAddress(); - if (address instanceof Inet6Address) { - forValue = "[" + forValue + "]"; + if (host != null) { + Forwarded forwarded = new Forwarded().put("host", host).put("proto", uri.getScheme()); + + request.remoteAddress().ifPresent(remoteAddress -> { + // If remoteAddress is unresolved, calling getHostAddress() would cause a + // NullPointerException. + String forValue; + if (remoteAddress.isUnresolved()) { + forValue = remoteAddress.getHostName(); } - } - if (!trustedProxies.isTrusted(forValue)) { - // don't add for value - return; - } - int port = remoteAddress.getPort(); - if (port >= 0 && !forValue.endsWith(":" + port)) { - forValue = forValue + ":" + port; - } - forwarded.put("for", forValue); - }); - // TODO: support by? + else { + InetAddress address = remoteAddress.getAddress(); + forValue = remoteAddress.getAddress().getHostAddress(); + if (address instanceof Inet6Address) { + forValue = "[" + forValue + "]"; + } + } + if (!trustedProxies.isTrusted(forValue)) { + // don't add for value + return; + } + int port = remoteAddress.getPort(); + if (port >= 0 && !forValue.endsWith(":" + port)) { + forValue = forValue + ":" + port; + } + forwarded.put("for", forValue); + }); + // TODO: support by? - updated.add(FORWARDED_HEADER, forwarded.toHeaderValue()); + updated.add(FORWARDED_HEADER, forwarded.toHeaderValue()); + } return updated; } + @SuppressWarnings("NullAway") /* for testing */ static class Forwarded { private static final char EQUALS = '='; diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/RewriteLocationResponseHeaderFilterFunctions.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/RewriteLocationResponseHeaderFilterFunctions.java index 9d898622c9..867f995e0c 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/RewriteLocationResponseHeaderFilterFunctions.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/RewriteLocationResponseHeaderFilterFunctions.java @@ -20,6 +20,8 @@ import java.util.function.Consumer; import java.util.regex.Pattern; +import org.jspecify.annotations.Nullable; + import org.springframework.http.HttpHeaders; import org.springframework.web.servlet.function.ServerRequest; import org.springframework.web.servlet.function.ServerResponse; @@ -162,7 +164,7 @@ public static class RewriteLocationResponseHeaderConfig { private String locationHeaderName = HttpHeaders.LOCATION; - private String hostValue; + private @Nullable String hostValue; private String protocolsRegex = DEFAULT_PROTOCOLS; @@ -193,7 +195,7 @@ public RewriteLocationResponseHeaderConfig setLocationHeaderName(String location return this; } - public String getHostValue() { + public @Nullable String getHostValue() { return hostValue; } diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/TokenRelayFilterFunctions.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/TokenRelayFilterFunctions.java index 65a59db061..34f8aa0958 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/TokenRelayFilterFunctions.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/TokenRelayFilterFunctions.java @@ -59,11 +59,13 @@ public static HandlerFilterFunction tokenRelay( OAuth2AuthorizedClientManager clientManager = getApplicationContext(request) .getBean(OAuth2AuthorizedClientManager.class); OAuth2AuthorizedClient authorizedClient = clientManager.authorize(authorizeRequest); - OAuth2AccessToken accessToken = authorizedClient.getAccessToken(); - ServerRequest modified = ServerRequest.from(request) - .headers(httpHeaders -> httpHeaders.setBearerAuth(accessToken.getTokenValue())) - .build(); - return next.handle(modified); + if (authorizedClient != null) { + OAuth2AccessToken accessToken = authorizedClient.getAccessToken(); + ServerRequest modified = ServerRequest.from(request) + .headers(httpHeaders -> httpHeaders.setBearerAuth(accessToken.getTokenValue())) + .build(); + return next.handle(modified); + } } return next.handle(request); }; diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/WeightCalculatorFilter.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/WeightCalculatorFilter.java index 092dd82a5d..8185de24fd 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/WeightCalculatorFilter.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/WeightCalculatorFilter.java @@ -21,6 +21,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.atomic.AtomicInteger; @@ -33,6 +34,7 @@ import jakarta.servlet.ServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.springframework.cloud.gateway.server.mvc.common.ArgumentSupplier.ArgumentSuppliedEvent; import org.springframework.cloud.gateway.server.mvc.common.AttributedArugmentSuppliedEvent; @@ -59,7 +61,7 @@ public class WeightCalculatorFilter implements Filter, Ordered, SmartApplication private static final Log log = LogFactory.getLog(WeightCalculatorFilter.class); - private Supplier randomSupplier = null; + private @Nullable Supplier randomSupplier = null; private int order = WEIGHT_CALC_FILTER_ORDER; @@ -99,7 +101,7 @@ public boolean supportsEventType(Class eventType) { } @Override - public boolean supportsSourceType(Class sourceType) { + public boolean supportsSourceType(@Nullable Class sourceType) { return true; } @@ -111,6 +113,7 @@ public void onApplicationEvent(ApplicationEvent event) { if (weightConfig.getRouteId() == null && argumentSuppliedEvent instanceof AttributedArugmentSuppliedEvent attributed) { String routeId = (String) attributed.getAttributes().get(MvcUtils.GATEWAY_ROUTE_ID_ATTR); + Objects.requireNonNull(routeId, "routeId is required for WeightConfig"); weightConfig.setRouteId(routeId); } @@ -119,7 +122,8 @@ public void onApplicationEvent(ApplicationEvent event) { } } - /* for testing */ void addWeightConfig(WeightConfig weightConfig) { + @SuppressWarnings("NullAway") + /* for testing */ void addWeightConfig(@Nullable WeightConfig weightConfig) { // Assert.hasText(weightConfig.getRouteId(), "routeId is required"); String group = weightConfig.getGroup(); diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/XForwardedRequestHeadersFilter.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/XForwardedRequestHeadersFilter.java index c865123d0d..069dccbbb8 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/XForwardedRequestHeadersFilter.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/XForwardedRequestHeadersFilter.java @@ -203,9 +203,12 @@ private void write(HttpHeaders headers, String name, @Nullable String value, boo } // these headers should be treated as a single comma separated header if (headers.containsHeader(name)) { - List values = headers.get(name).stream().filter(shouldWrite).toList(); - String delimitedValue = StringUtils.collectionToCommaDelimitedString(values); - headers.set(name, delimitedValue); + List values = headers.get(name); + if (values != null) { + List filteredValues = values.stream().filter(shouldWrite).toList(); + String delimitedValue = StringUtils.collectionToCommaDelimitedString(filteredValues); + headers.set(name, delimitedValue); + } } } else if (value != null && shouldWrite.test(value)) { diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/ClientHttpRequestFactoryProxyExchange.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/ClientHttpRequestFactoryProxyExchange.java index 61e836759a..9a8f3e4d05 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/ClientHttpRequestFactoryProxyExchange.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/ClientHttpRequestFactoryProxyExchange.java @@ -19,6 +19,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.UncheckedIOException; +import java.util.Objects; import org.springframework.cloud.gateway.server.mvc.common.AbstractProxyExchange; import org.springframework.cloud.gateway.server.mvc.common.MvcUtils; @@ -42,6 +43,7 @@ public ClientHttpRequestFactoryProxyExchange(ClientHttpRequestFactory requestFac @Override public ServerResponse exchange(Request request) { try { + Objects.requireNonNull(request.getUri(), "uri is required"); ClientHttpRequest clientHttpRequest = requestFactory.createRequest(request.getUri(), request.getMethod()); clientHttpRequest.getHeaders().putAll(request.getHeaders()); // copy body from request to clientHttpRequest @@ -58,6 +60,7 @@ public ServerResponse exchange(Request request) { // modified. InputStream inputStream = MvcUtils.getAttribute(request.getServerRequest(), MvcUtils.CLIENT_RESPONSE_INPUT_STREAM_ATTR); + Objects.requireNonNull(inputStream, "input stream cannot be null"); // copy body from request to clientHttpRequest ClientHttpRequestFactoryProxyExchange.this.copyResponseBody(clientHttpResponse, inputStream, httpServletResponse.getOutputStream()); diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/FunctionHandlerHeaderUtils.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/FunctionHandlerHeaderUtils.java index 32cfceea55..303aa3b77b 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/FunctionHandlerHeaderUtils.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/FunctionHandlerHeaderUtils.java @@ -16,7 +16,6 @@ package org.springframework.cloud.gateway.server.mvc.handler; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.LinkedHashMap; @@ -24,6 +23,8 @@ import java.util.Locale; import java.util.Map; +import org.jspecify.annotations.Nullable; + import org.springframework.http.HttpHeaders; import org.springframework.messaging.MessageHeaders; @@ -83,7 +84,7 @@ public static HttpHeaders sanitize(HttpHeaders request, List ignoredHede List value = request.get(name); name = name.toLowerCase(Locale.ROOT); if (!IGNORED.containsHeader(name) && !REQUEST_ONLY.containsHeader(name) && !ignoredHeders.contains(name) - && !requestOnlyHeaders.contains(name)) { + && !requestOnlyHeaders.contains(name) && value != null) { result.put(name, value); } } @@ -109,8 +110,11 @@ public static MessageHeaders fromHttp(HttpHeaders headers) { return new MessageHeaders(map); } - private static Collection multi(Object value) { - return value instanceof Collection ? (Collection) value : Arrays.asList(value); + private static Collection multi(@Nullable Object value) { + if (value == null) { + return Collections.emptyList(); + } + return value instanceof Collection ? (Collection) value : List.of(value); } } diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/GatewayEntityResponseBuilder.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/GatewayEntityResponseBuilder.java index 06f18280d4..6e0b21f383 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/GatewayEntityResponseBuilder.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/GatewayEntityResponseBuilder.java @@ -239,8 +239,8 @@ public T entity() { } @Override - protected ModelAndView writeToInternal(HttpServletRequest servletRequest, HttpServletResponse servletResponse, - Context context) throws ServletException, IOException { + protected @Nullable ModelAndView writeToInternal(HttpServletRequest servletRequest, + HttpServletResponse servletResponse, Context context) throws ServletException, IOException { writeEntityWithMessageConverters(this.entity, servletRequest, servletResponse, context); return null; @@ -336,8 +336,8 @@ private static class CompletionStageEntityResponse extends GatewayEntityRespo } @Override - protected ModelAndView writeToInternal(HttpServletRequest servletRequest, HttpServletResponse servletResponse, - Context context) throws ServletException, IOException { + protected @Nullable ModelAndView writeToInternal(HttpServletRequest servletRequest, + HttpServletResponse servletResponse, Context context) throws ServletException, IOException { DeferredResult deferredResult = createDeferredResult(servletRequest, servletResponse, context); diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/HandlerFunctionAutoConfiguration.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/HandlerFunctionAutoConfiguration.java index 573d09a4d3..dd07d4d61f 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/HandlerFunctionAutoConfiguration.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/HandlerFunctionAutoConfiguration.java @@ -19,8 +19,11 @@ import java.net.URI; import java.util.Arrays; import java.util.Collections; +import java.util.Objects; import java.util.function.Function; +import org.jspecify.annotations.Nullable; + import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.cloud.gateway.server.mvc.common.MvcUtils; import org.springframework.cloud.gateway.server.mvc.config.RouteProperties; @@ -34,14 +37,21 @@ public class HandlerFunctionAutoConfiguration { @Bean public Function fnHandlerFunctionDefinition() { - return routeProperties -> new HandlerFunctionDefinition.Default("fn", - HandlerFunctions.fn(routeProperties.getUri().getSchemeSpecificPart())); + return routeProperties -> { + Objects.requireNonNull(routeProperties.getUri(), "routeProperties.uri must not be null"); + return new HandlerFunctionDefinition.Default("fn", + HandlerFunctions.fn(routeProperties.getUri().getSchemeSpecificPart())); + }; } @Bean public Function forwardHandlerFunctionDefinition() { - return routeProperties -> new HandlerFunctionDefinition.Default("forward", - HandlerFunctions.forward(routeProperties.getUri().getPath())); + return routeProperties -> { + Objects.requireNonNull(routeProperties.getUri(), "routeProperties.uri must not be null"); + Objects.requireNonNull(routeProperties.getUri().getPath(), "routeProperties.uri.path must not be null"); + return new HandlerFunctionDefinition.Default("forward", + HandlerFunctions.forward(routeProperties.getUri().getPath())); + }; } @Bean @@ -64,11 +74,14 @@ public Function noHandlerFunctionDef @Bean public Function streamHandlerFunctionDefinition() { - return routeProperties -> new HandlerFunctionDefinition.Default("stream", - HandlerFunctions.stream(routeProperties.getUri().getSchemeSpecificPart())); + return routeProperties -> { + Objects.requireNonNull(routeProperties.getUri(), "routeProperties.uri must not be null"); + return new HandlerFunctionDefinition.Default("stream", + HandlerFunctions.stream(routeProperties.getUri().getSchemeSpecificPart())); + }; } - private static HandlerFunctionDefinition getResult(String scheme, String id, URI uri, + private static HandlerFunctionDefinition getResult(String scheme, @Nullable String id, @Nullable URI uri, HandlerFunction handlerFunction) { HandlerFilterFunction setId = setIdFilter(id); HandlerFilterFunction setRequest = setRequestUrlFilter(uri); @@ -76,15 +89,16 @@ private static HandlerFunctionDefinition getResult(String scheme, String id, URI Collections.emptyList()); } - private static HandlerFilterFunction setIdFilter(String id) { + private static HandlerFilterFunction setIdFilter(@Nullable String id) { return (request, next) -> { MvcUtils.setRouteId(request, id); return next.handle(request); }; } - private static HandlerFilterFunction setRequestUrlFilter(URI uri) { + private static HandlerFilterFunction setRequestUrlFilter(@Nullable URI uri) { return (request, next) -> { + Objects.requireNonNull(uri, "uri must not be null"); MvcUtils.setRequestUrl(request, uri); return next.handle(request); }; diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/HandlerFunctions.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/HandlerFunctions.java index 401dab64c9..db4949410b 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/HandlerFunctions.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/HandlerFunctions.java @@ -20,6 +20,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.Objects; import java.util.concurrent.atomic.AtomicReference; import jakarta.servlet.ServletException; @@ -118,6 +119,7 @@ public static HandlerFunction stream(String bindingName) { // for properties public static HandlerFunction forward(RouteProperties routeProperties) { + Objects.requireNonNull(routeProperties.getUri(), "routeProperties uri must not be null"); return forward(routeProperties.getUri().getPath()); } @@ -156,12 +158,14 @@ static class LookupProxyExchangeHandlerFunction implements HandlerFunction { + ProxyExchangeHandlerFunction proxyFunction = proxyExchangeHandlerFunction.updateAndGet(function -> { if (function == null) { return lookup(serverRequest); } return function; - }).handle(serverRequest); + }); + Objects.requireNonNull(proxyFunction, "No ProxyExchangeHandlerFunction found"); + return proxyFunction.handle(serverRequest); } private static ProxyExchangeHandlerFunction lookup(ServerRequest request) { diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/ProxyExchange.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/ProxyExchange.java index 79b7c09220..49ede28077 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/ProxyExchange.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/ProxyExchange.java @@ -21,6 +21,8 @@ import java.util.Collection; import java.util.function.BiConsumer; +import org.jspecify.annotations.Nullable; + import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMessage; import org.springframework.http.HttpMethod; @@ -40,6 +42,7 @@ interface Request extends HttpMessage { HttpMethod getMethod(); + @org.jspecify.annotations.Nullable URI getUri(); ServerRequest getServerRequest(); @@ -80,13 +83,14 @@ class DefaultRequestBuilder implements RequestBuilder, Request { private HttpMethod method; - private URI uri; + private @Nullable URI uri; private ArrayList responseConsumers = new ArrayList<>(); DefaultRequestBuilder(ServerRequest serverRequest) { this.serverRequest = serverRequest; this.method = serverRequest.method(); + this.httpHeaders = serverRequest.headers().asHttpHeaders(); } @Override @@ -130,7 +134,7 @@ public HttpMethod getMethod() { } @Override - public URI getUri() { + public @Nullable URI getUri() { return uri; } diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/RestClientProxyExchange.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/RestClientProxyExchange.java index da2b3760c3..0e7e5e8fda 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/RestClientProxyExchange.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/RestClientProxyExchange.java @@ -20,6 +20,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.io.UncheckedIOException; +import java.util.Objects; import org.springframework.cloud.gateway.server.mvc.common.AbstractProxyExchange; import org.springframework.cloud.gateway.server.mvc.common.MvcUtils; @@ -40,6 +41,7 @@ public RestClientProxyExchange(RestClient restClient, GatewayMvcProperties prope @Override public ServerResponse exchange(Request request) { + Objects.requireNonNull(request.getUri(), "uri cannot be null"); RestClient.RequestBodySpec requestSpec = restClient.method(request.getMethod()) .uri(request.getUri()) .headers(httpHeaders -> httpHeaders.putAll(request.getHeaders())); @@ -74,6 +76,7 @@ private ServerResponse doExchange(Request request, ClientHttpResponse clientResp // modified. InputStream inputStream = MvcUtils.getAttribute(request.getServerRequest(), MvcUtils.CLIENT_RESPONSE_INPUT_STREAM_ATTR); + Objects.requireNonNull(inputStream, "input stream cannot be null"); // copy body from request to clientHttpRequest RestClientProxyExchange.this.copyResponseBody(clientResponse, inputStream, httpServletResponse.getOutputStream()); diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/invoke/InvocationContext.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/invoke/InvocationContext.java index 5f442f5f3f..03c8c506e5 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/invoke/InvocationContext.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/invoke/InvocationContext.java @@ -21,6 +21,8 @@ import java.util.List; import java.util.Map; +import org.jspecify.annotations.Nullable; + import org.springframework.util.Assert; /** @@ -68,7 +70,7 @@ public Map getArguments() { * @since 2.5.0 * @see #canResolve(Class) */ - public T resolveArgument(Class argumentType) { + public @Nullable T resolveArgument(Class argumentType) { for (OperationArgumentResolver argumentResolver : this.argumentResolvers) { if (argumentResolver.canResolve(argumentType)) { T result = argumentResolver.resolve(argumentType); diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/invoke/OperationArgumentResolver.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/invoke/OperationArgumentResolver.java index 6c6a006c56..649646ad92 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/invoke/OperationArgumentResolver.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/invoke/OperationArgumentResolver.java @@ -18,6 +18,8 @@ import java.util.function.Supplier; +import org.jspecify.annotations.Nullable; + import org.springframework.util.Assert; /** @@ -42,7 +44,7 @@ public interface OperationArgumentResolver { * @param type argument type * @return an argument of the required type, or {@code null} */ - T resolve(Class type); + @Nullable T resolve(Class type); /** * Factory method that creates an {@link OperationArgumentResolver} for a specific diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/invoke/convert/ConversionServiceParameterValueMapper.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/invoke/convert/ConversionServiceParameterValueMapper.java index be47daee69..c0f6e164f8 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/invoke/convert/ConversionServiceParameterValueMapper.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/invoke/convert/ConversionServiceParameterValueMapper.java @@ -16,6 +16,8 @@ package org.springframework.cloud.gateway.server.mvc.invoke.convert; +import java.util.Objects; + import org.springframework.boot.convert.ApplicationConversionService; import org.springframework.cloud.gateway.server.mvc.invoke.OperationParameter; import org.springframework.cloud.gateway.server.mvc.invoke.ParameterMappingException; @@ -54,7 +56,9 @@ public ConversionServiceParameterValueMapper(ConversionService conversionService @Override public Object mapParameterValue(OperationParameter parameter, Object value) throws ParameterMappingException { try { - return this.conversionService.convert(value, parameter.getType()); + Object toReturn = this.conversionService.convert(value, parameter.getType()); + Objects.requireNonNull(toReturn, "ConversionService returned null"); + return toReturn; } catch (Exception ex) { throw new ParameterMappingException(parameter, value, ex); diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/invoke/convert/IsoOffsetDateTimeConverter.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/invoke/convert/IsoOffsetDateTimeConverter.java index 2f3dafbaa2..c4e4a843ab 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/invoke/convert/IsoOffsetDateTimeConverter.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/invoke/convert/IsoOffsetDateTimeConverter.java @@ -19,6 +19,8 @@ import java.time.OffsetDateTime; import java.time.format.DateTimeFormatter; +import org.jspecify.annotations.Nullable; + import org.springframework.core.convert.converter.Converter; import org.springframework.core.convert.converter.ConverterRegistry; import org.springframework.util.StringUtils; @@ -34,7 +36,7 @@ public class IsoOffsetDateTimeConverter implements Converter { @Override - public OffsetDateTime convert(String source) { + public @Nullable OffsetDateTime convert(String source) { if (StringUtils.hasLength(source)) { return OffsetDateTime.parse(source, DateTimeFormatter.ISO_OFFSET_DATE_TIME); } diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/invoke/reflect/OperationMethodParameters.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/invoke/reflect/OperationMethodParameters.java index 125e58582a..3b87e25662 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/invoke/reflect/OperationMethodParameters.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/invoke/reflect/OperationMethodParameters.java @@ -22,8 +22,11 @@ import java.util.Collections; import java.util.Iterator; import java.util.List; +import java.util.Objects; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; + import org.springframework.cloud.gateway.server.mvc.invoke.OperationParameter; import org.springframework.cloud.gateway.server.mvc.invoke.OperationParameters; import org.springframework.core.ParameterNameDiscoverer; @@ -46,16 +49,19 @@ class OperationMethodParameters implements OperationParameters { OperationMethodParameters(Method method, ParameterNameDiscoverer parameterNameDiscoverer) { Assert.notNull(method, "Method must not be null"); Assert.notNull(parameterNameDiscoverer, "ParameterNameDiscoverer must not be null"); - String[] parameterNames = parameterNameDiscoverer.getParameterNames(method); + @Nullable String @Nullable [] parameterNames = parameterNameDiscoverer.getParameterNames(method); Parameter[] parameters = method.getParameters(); - Assert.state(parameterNames != null, () -> "Failed to extract parameter names for " + method); this.operationParameters = getOperationParameters(parameters, parameterNames); } - private List getOperationParameters(Parameter[] parameters, String[] names) { + private List getOperationParameters(Parameter[] parameters, + @Nullable String @Nullable [] names) { List operationParameters = new ArrayList<>(parameters.length); + Objects.requireNonNull(names, "Parameter names must not be null"); for (int i = 0; i < names.length; i++) { - operationParameters.add(new OperationMethodParameter(names[i], parameters[i])); + String name = names[i]; + Objects.requireNonNull(name, "Parameter name must not be null"); + operationParameters.add(new OperationMethodParameter(name, parameters[i])); } return Collections.unmodifiableList(operationParameters); } diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/invoke/reflect/ReflectiveOperationInvoker.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/invoke/reflect/ReflectiveOperationInvoker.java index c6d55a7e87..6e74a931db 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/invoke/reflect/ReflectiveOperationInvoker.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/invoke/reflect/ReflectiveOperationInvoker.java @@ -17,9 +17,12 @@ package org.springframework.cloud.gateway.server.mvc.invoke.reflect; import java.lang.reflect.Method; +import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; +import org.jspecify.annotations.Nullable; + import org.springframework.cloud.gateway.server.mvc.invoke.InvocationContext; import org.springframework.cloud.gateway.server.mvc.invoke.MissingParametersException; import org.springframework.cloud.gateway.server.mvc.invoke.OperationInvoker; @@ -39,7 +42,7 @@ */ public class ReflectiveOperationInvoker implements OperationInvoker { - private final Object target; + private final @Nullable Object target; private final OperationMethod operationMethod; @@ -66,7 +69,7 @@ public ReflectiveOperationInvoker(OperationMethod operationMethod, ParameterValu * @param operationMethod the method info * @param parameterValueMapper the parameter mapper */ - public ReflectiveOperationInvoker(Object target, OperationMethod operationMethod, + public ReflectiveOperationInvoker(@Nullable Object target, OperationMethod operationMethod, ParameterValueMapper parameterValueMapper) { // Assert.notNull(target, "Target must not be null"); Assert.notNull(operationMethod, "OperationMethod must not be null"); @@ -84,7 +87,9 @@ public T invoke(InvocationContext context) { Method method = this.operationMethod.getMethod(); Object[] resolvedArguments = resolveArguments(context); ReflectionUtils.makeAccessible(method); - return (T) ReflectionUtils.invokeMethod(method, this.target, resolvedArguments); + T result = (T) ReflectionUtils.invokeMethod(method, this.target, resolvedArguments); + Objects.requireNonNull(result, "Operation method returned null"); + return result; } private void validateRequiredParameters(InvocationContext context) { @@ -120,6 +125,7 @@ private Object resolveArgument(OperationParameter parameter, InvocationContext c return resolvedByType; } Object value = context.getArguments().get(parameter.getName()); + Objects.requireNonNull(value, "Missing value for parameter " + parameter.getName()); return this.parameterValueMapper.mapParameterValue(parameter, value); } From b814cc259bc3973aed27ee7be2e01b00a58f204f Mon Sep 17 00:00:00 2001 From: Ryan Baxter Date: Fri, 21 Nov 2025 13:36:53 -0500 Subject: [PATCH 3/3] User Objects.requireNonNull --- .../cloud/gateway/webflux/ProxyExchange.java | 12 +++++----- .../cloud/gateway/mvc/ProxyExchange.java | 22 +++++++++---------- .../config/ProxyExchangeArgumentResolver.java | 8 +++---- .../ProxyResponseAutoConfiguration.java | 2 +- .../gateway/mvc/GetWithBodyRequestTests.java | 2 +- .../gateway/filter/ForwardRoutingFilter.java | 4 ++-- .../filter/WeightCalculatorWebFilter.java | 6 ++--- .../CacheRequestBodyGatewayFilterFactory.java | 3 +-- .../JsonToGrpcGatewayFilterFactory.java | 3 +-- .../RequestSizeGatewayFilterFactory.java | 4 +++- .../factory/RetryGatewayFilterFactory.java | 3 ++- .../RewritePathGatewayFilterFactory.java | 2 +- .../headers/RemoveHopByHopHeadersFilter.java | 4 ++-- .../filter/ratelimit/Bucket4jRateLimiter.java | 8 +++---- .../gateway/filter/ratelimit/RateLimiter.java | 4 ++-- .../cloud/gateway/handler/AsyncPredicate.java | 12 +++++----- .../BetweenRoutePredicateFactory.java | 3 ++- .../handler/predicate/GatewayPredicate.java | 14 ++++++------ .../ReadBodyRoutePredicateFactory.java | 4 ++-- .../VersionRoutePredicateFactory.java | 3 ++- .../cloud/gateway/route/Route.java | 20 ++++++++--------- .../gateway/route/RouteRefreshListener.java | 5 +++-- .../gateway/route/builder/BooleanSpec.java | 4 ++-- .../route/builder/GatewayFilterSpec.java | 2 +- .../gateway/support/ConfigurationService.java | 5 +++-- .../support/ServerWebExchangeUtils.java | 8 +++---- .../tagsprovider/GatewayTagsProvider.java | 4 ++-- .../GatewayControllerEndpointTests.java | 2 +- ...outeDefinitionLocatorIntegrationTests.java | 2 +- .../SpringCloudCircuitBreakerTestConfig.java | 2 +- .../test/support/AbstractHttpServer.java | 3 ++- .../websocket/WebSocketIntegrationTests.java | 12 +++++----- .../mvc/common/AbstractProxyExchange.java | 8 +++---- .../gateway/server/mvc/common/MvcUtils.java | 6 ++--- .../mvc/filter/AfterFilterFunctions.java | 3 ++- .../mvc/filter/BeforeFilterFunctions.java | 5 +++-- .../mvc/filter/Bucket4jFilterFunctions.java | 7 +++--- .../filter/CircuitBreakerFilterFunctions.java | 3 ++- .../XForwardedRequestHeadersFilter.java | 6 ++--- .../handler/GatewayAsyncServerResponse.java | 4 ++-- .../handler/GatewayEntityResponseBuilder.java | 6 ++--- .../GatewayErrorHandlingServerResponse.java | 10 ++++----- .../GatewayRenderingResponseBuilder.java | 14 ++++++------ .../handler/GatewayServerResponseBuilder.java | 10 ++++----- .../GatewayStreamingServerResponse.java | 12 +++++----- .../server/mvc/invoke/InvocationContext.java | 5 ++--- .../mvc/invoke/OperationArgumentResolver.java | 7 +++--- ...ConversionServiceParameterValueMapper.java | 3 +-- .../reflect/DefaultOperationMethod.java | 4 ++-- .../reflect/OperationMethodParameter.java | 2 +- .../reflect/OperationMethodParameters.java | 5 ++--- .../reflect/ReflectiveOperationInvoker.java | 7 +++--- .../predicate/GatewayRequestPredicates.java | 9 ++++---- .../server/mvc/ServerMvcIntegrationTests.java | 2 +- .../server/mvc/test/HttpbinUriResolver.java | 3 ++- .../mvc/test/LocalHostUriBuilderFactory.java | 6 ++--- 56 files changed, 173 insertions(+), 166 deletions(-) diff --git a/spring-cloud-gateway-proxyexchange-webflux/src/main/java/org/springframework/cloud/gateway/webflux/ProxyExchange.java b/spring-cloud-gateway-proxyexchange-webflux/src/main/java/org/springframework/cloud/gateway/webflux/ProxyExchange.java index 820011b25a..da21176ec4 100644 --- a/spring-cloud-gateway-proxyexchange-webflux/src/main/java/org/springframework/cloud/gateway/webflux/ProxyExchange.java +++ b/spring-cloud-gateway-proxyexchange-webflux/src/main/java/org/springframework/cloud/gateway/webflux/ProxyExchange.java @@ -23,6 +23,7 @@ import java.util.Collections; import java.util.HashSet; import java.util.Locale; +import java.util.Objects; import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; @@ -41,7 +42,6 @@ import org.springframework.http.RequestEntity.BodyBuilder; import org.springframework.http.ResponseEntity; import org.springframework.http.converter.HttpMessageConverter; -import org.springframework.util.Assert; import org.springframework.util.StringUtils; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.RequestBody; @@ -246,7 +246,7 @@ public String path(String prefix) { } public Mono> get() { - Assert.notNull(uri, "URI must not be null"); + Objects.requireNonNull(uri, "URI must not be null"); RequestEntity requestEntity = headers((BodyBuilder) RequestEntity.get(uri)).build(); return exchange(requestEntity); } @@ -256,7 +256,7 @@ public Mono> get(Function, ResponseEntit } public Mono> head() { - Assert.notNull(uri, "URI must not be null"); + Objects.requireNonNull(uri, "URI must not be null"); RequestEntity requestEntity = headers((BodyBuilder) RequestEntity.head(uri)).build(); return exchange(requestEntity); } @@ -266,7 +266,7 @@ public Mono> head(Function, ResponseEnti } public Mono> options() { - Assert.notNull(uri, "URI must not be null"); + Objects.requireNonNull(uri, "URI must not be null"); RequestEntity requestEntity = headers((BodyBuilder) RequestEntity.options(uri)).build(); return exchange(requestEntity); } @@ -296,7 +296,7 @@ public Mono> put() { } private Mono> doExchange(Function getBodyBuilder) { - Assert.notNull(uri, "URI must not be null"); + Objects.requireNonNull(uri, "URI must not be null"); BodyBuilder bodyBuilder = headers(getBodyBuilder.apply(uri)); Publisher body = body(); RequestEntity requestEntity = body != null ? bodyBuilder.body(body) : bodyBuilder.build(); @@ -369,7 +369,7 @@ else if (httpMethod.equals(HttpMethod.PATCH)) { private Mono> exchange(RequestEntity requestEntity) { Type type = this.responseType; - Assert.notNull(requestEntity.getMethod(), "Method must not be null"); + Objects.requireNonNull(requestEntity.getMethod(), "Method must not be null"); RequestBodySpec builder = rest.method(requestEntity.getMethod()) .uri(requestEntity.getUrl()) .headers(headers -> addHeaders(headers, requestEntity.getHeaders())); diff --git a/spring-cloud-gateway-proxyexchange-webmvc/src/main/java/org/springframework/cloud/gateway/mvc/ProxyExchange.java b/spring-cloud-gateway-proxyexchange-webmvc/src/main/java/org/springframework/cloud/gateway/mvc/ProxyExchange.java index df2400f497..8b190500d7 100644 --- a/spring-cloud-gateway-proxyexchange-webmvc/src/main/java/org/springframework/cloud/gateway/mvc/ProxyExchange.java +++ b/spring-cloud-gateway-proxyexchange-webmvc/src/main/java/org/springframework/cloud/gateway/mvc/ProxyExchange.java @@ -32,6 +32,7 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Locale; +import java.util.Objects; import java.util.Set; import java.util.Vector; import java.util.function.Function; @@ -56,7 +57,6 @@ import org.springframework.http.ResponseEntity; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.HttpMessageNotWritableException; -import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; import org.springframework.validation.BindingResult; @@ -268,8 +268,8 @@ public void forward(String path) { HttpServletRequest request = this.webRequest.getNativeRequest(HttpServletRequest.class); HttpServletResponse response = this.webRequest.getNativeResponse(HttpServletResponse.class); try { - Assert.notNull(request, "HttpServletRequest is required"); - Assert.notNull(response, "HttpServletResponse is required"); + Objects.requireNonNull(request, "HttpServletRequest is required"); + Objects.requireNonNull(response, "HttpServletResponse is required"); request.getRequestDispatcher(path) .forward(new BodyForwardingHttpServletRequest(request, response), response); } @@ -279,7 +279,7 @@ public void forward(String path) { } public ResponseEntity get() { - Assert.notNull(this.uri, "URI is required"); + Objects.requireNonNull(this.uri, "URI is required"); Object body = body(); BodyBuilder builder = headers((BodyBuilder) RequestEntity.get(uri)); if (body != null) { @@ -295,7 +295,7 @@ public ResponseEntity get(Function, ResponseEntity> } public ResponseEntity head() { - Assert.notNull(this.uri, "URI is required"); + Objects.requireNonNull(this.uri, "URI is required"); RequestEntity requestEntity = headers((BodyBuilder) RequestEntity.head(uri)).build(); return exchange(requestEntity); } @@ -305,7 +305,7 @@ public ResponseEntity head(Function, ResponseEntity> } public ResponseEntity options() { - Assert.notNull(this.uri, "URI is required"); + Objects.requireNonNull(this.uri, "URI is required"); RequestEntity requestEntity = headers((BodyBuilder) RequestEntity.options(uri)).build(); return exchange(requestEntity); } @@ -315,7 +315,7 @@ public ResponseEntity options(Function, ResponseEntity< } public ResponseEntity post() { - Assert.notNull(this.uri, "URI is required"); + Objects.requireNonNull(this.uri, "URI is required"); Object body = body(); BodyBuilder builder = headers(RequestEntity.post(uri)); if (body != null) { @@ -331,7 +331,7 @@ public ResponseEntity post(Function, ResponseEntity> } public ResponseEntity delete() { - Assert.notNull(this.uri, "URI is required"); + Objects.requireNonNull(this.uri, "URI is required"); Object body = body(); BodyBuilder builder = headers((BodyBuilder) RequestEntity.delete(uri)); if (body != null) { @@ -347,7 +347,7 @@ public ResponseEntity delete(Function, ResponseEntity put() { - Assert.notNull(this.uri, "URI is required"); + Objects.requireNonNull(this.uri, "URI is required"); Object body = body(); BodyBuilder builder = headers(RequestEntity.put(uri)); if (body != null) { @@ -363,7 +363,7 @@ public ResponseEntity put(Function, ResponseEntity> } public ResponseEntity patch() { - Assert.notNull(this.uri, "URI is required"); + Objects.requireNonNull(this.uri, "URI is required"); Object body = body(); BodyBuilder builder = headers(RequestEntity.patch(uri)); if (body != null) { @@ -420,7 +420,7 @@ private Set filterHeaderKeys(Collection headerNames) { private void proxy() { HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); - Assert.notNull(request, "Request is required"); + Objects.requireNonNull(request, "Request is required"); try { URI uri = new URI(request.getRequestURL().toString()); appendForwarded(uri); diff --git a/spring-cloud-gateway-proxyexchange-webmvc/src/main/java/org/springframework/cloud/gateway/mvc/config/ProxyExchangeArgumentResolver.java b/spring-cloud-gateway-proxyexchange-webmvc/src/main/java/org/springframework/cloud/gateway/mvc/config/ProxyExchangeArgumentResolver.java index 646e5d1bf5..21d68aba73 100644 --- a/spring-cloud-gateway-proxyexchange-webmvc/src/main/java/org/springframework/cloud/gateway/mvc/config/ProxyExchangeArgumentResolver.java +++ b/spring-cloud-gateway-proxyexchange-webmvc/src/main/java/org/springframework/cloud/gateway/mvc/config/ProxyExchangeArgumentResolver.java @@ -21,6 +21,7 @@ import java.util.Collections; import java.util.Enumeration; import java.util.Locale; +import java.util.Objects; import java.util.Set; import jakarta.servlet.http.HttpServletRequest; @@ -29,7 +30,6 @@ import org.springframework.cloud.gateway.mvc.ProxyExchange; import org.springframework.core.MethodParameter; import org.springframework.http.HttpHeaders; -import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.client.RestTemplate; @@ -78,8 +78,8 @@ public boolean supportsParameter(MethodParameter parameter) { @Override public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception { - Assert.notNull(binderFactory, "WebDataBinderFactory is required"); - Assert.notNull(mavContainer, "ModelAndViewContainer is required"); + Objects.requireNonNull(binderFactory, "WebDataBinderFactory is required"); + Objects.requireNonNull(mavContainer, "ModelAndViewContainer is required"); ProxyExchange proxy = new ProxyExchange<>(rest, webRequest, mavContainer, binderFactory, type(parameter)); configureHeaders(proxy); configureAutoForwardedHeaders(proxy, webRequest); @@ -97,7 +97,7 @@ private Type type(MethodParameter parameter) { private HttpHeaders extractAutoForwardedHeaders(NativeWebRequest webRequest) { HttpServletRequest nativeRequest = webRequest.getNativeRequest(HttpServletRequest.class); - Assert.notNull(nativeRequest, "HttpServletRequest is required"); + Objects.requireNonNull(nativeRequest, "HttpServletRequest is required"); Enumeration headerNames = nativeRequest.getHeaderNames(); HttpHeaders headers = new HttpHeaders(); if (headerNames != null && autoForwardedHeaders != null) { diff --git a/spring-cloud-gateway-proxyexchange-webmvc/src/main/java/org/springframework/cloud/gateway/mvc/config/ProxyResponseAutoConfiguration.java b/spring-cloud-gateway-proxyexchange-webmvc/src/main/java/org/springframework/cloud/gateway/mvc/config/ProxyResponseAutoConfiguration.java index f1b404bd50..eebd8a985c 100644 --- a/spring-cloud-gateway-proxyexchange-webmvc/src/main/java/org/springframework/cloud/gateway/mvc/config/ProxyResponseAutoConfiguration.java +++ b/spring-cloud-gateway-proxyexchange-webmvc/src/main/java/org/springframework/cloud/gateway/mvc/config/ProxyResponseAutoConfiguration.java @@ -94,7 +94,7 @@ public void addArgumentResolvers(List argumentRes argumentResolvers.add(context.getBean(ProxyExchangeArgumentResolver.class)); } - private static class NoOpResponseErrorHandler extends DefaultResponseErrorHandler { + private static final class NoOpResponseErrorHandler extends DefaultResponseErrorHandler { @Override public void handleError(URI url, HttpMethod method, ClientHttpResponse response) throws IOException { diff --git a/spring-cloud-gateway-proxyexchange-webmvc/src/test/java/org/springframework/cloud/gateway/mvc/GetWithBodyRequestTests.java b/spring-cloud-gateway-proxyexchange-webmvc/src/test/java/org/springframework/cloud/gateway/mvc/GetWithBodyRequestTests.java index 8e740d245e..1f1e393ff5 100644 --- a/spring-cloud-gateway-proxyexchange-webmvc/src/test/java/org/springframework/cloud/gateway/mvc/GetWithBodyRequestTests.java +++ b/spring-cloud-gateway-proxyexchange-webmvc/src/test/java/org/springframework/cloud/gateway/mvc/GetWithBodyRequestTests.java @@ -194,7 +194,7 @@ public void setName(final String name) { } - private static class NoOpResponseErrorHandler extends DefaultResponseErrorHandler { + private static final class NoOpResponseErrorHandler extends DefaultResponseErrorHandler { @Override public void handleError(URI url, HttpMethod method, ClientHttpResponse response) throws IOException { diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/ForwardRoutingFilter.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/ForwardRoutingFilter.java index 18c37fb155..5f9ca039b6 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/ForwardRoutingFilter.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/ForwardRoutingFilter.java @@ -17,6 +17,7 @@ package org.springframework.cloud.gateway.filter; import java.net.URI; +import java.util.Objects; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -25,7 +26,6 @@ import org.springframework.beans.factory.ObjectProvider; import org.springframework.core.Ordered; -import org.springframework.util.Assert; import org.springframework.web.reactive.DispatcherHandler; import org.springframework.web.server.ServerWebExchange; @@ -73,7 +73,7 @@ public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { log.trace("Forwarding to URI: " + requestUrl); } DispatcherHandler handler = getDispatcherHandler(); - Assert.notNull(handler, "DispatcherHandler must not be null"); + Objects.requireNonNull(handler, "DispatcherHandler must not be null"); return handle(handler, exchange); } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/WeightCalculatorWebFilter.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/WeightCalculatorWebFilter.java index fd6feff88f..3c7ccab27e 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/WeightCalculatorWebFilter.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/WeightCalculatorWebFilter.java @@ -20,6 +20,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.atomic.AtomicBoolean; @@ -45,7 +46,6 @@ import org.springframework.core.Ordered; import org.springframework.core.log.LogMessage; import org.springframework.core.style.ToStringCreator; -import org.springframework.util.Assert; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebFilter; import org.springframework.web.server.WebFilterChain; @@ -104,12 +104,12 @@ public void setOrder(int order) { } public void setRandomSupplier(Supplier randomSupplier) { - Assert.notNull(randomSupplier, "randomSupplier may not be null"); + Objects.requireNonNull(randomSupplier, "randomSupplier may not be null"); this.randomFunction = exchange -> randomSupplier.get(); } public void setRandomFunction(Function randomFunction) { - Assert.notNull(randomFunction, "randomFunction may not be null"); + Objects.requireNonNull(randomFunction, "randomFunction may not be null"); this.randomFunction = randomFunction; } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/CacheRequestBodyGatewayFilterFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/CacheRequestBodyGatewayFilterFactory.java index 01c923dacb..4bd47a97cb 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/CacheRequestBodyGatewayFilterFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/CacheRequestBodyGatewayFilterFactory.java @@ -30,7 +30,6 @@ import org.springframework.core.io.buffer.DataBufferUtils; import org.springframework.http.codec.HttpMessageReader; import org.springframework.http.server.reactive.ServerHttpRequest; -import org.springframework.util.Assert; import org.springframework.web.reactive.function.server.HandlerStrategies; import org.springframework.web.reactive.function.server.ServerRequest; import org.springframework.web.server.ServerWebExchange; @@ -91,7 +90,7 @@ public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { }).then(Mono.defer(() -> { ServerHttpRequest cachedRequest = exchange .getAttribute(CACHED_SERVER_HTTP_REQUEST_DECORATOR_ATTR); - Assert.notNull(cachedRequest, "cache request shouldn't be null"); + Objects.requireNonNull(cachedRequest, "cache request shouldn't be null"); exchange.getAttributes().remove(CACHED_SERVER_HTTP_REQUEST_DECORATOR_ATTR); return chain.filter(exchange.mutate().request(cachedRequest).build()).doFinally(s -> { // diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/JsonToGrpcGatewayFilterFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/JsonToGrpcGatewayFilterFactory.java index 55d6689f1e..5cb5059c08 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/JsonToGrpcGatewayFilterFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/JsonToGrpcGatewayFilterFactory.java @@ -69,7 +69,6 @@ import org.springframework.core.io.buffer.NettyDataBufferFactory; import org.springframework.http.codec.json.JacksonJsonDecoder; import org.springframework.http.server.reactive.ServerHttpResponseDecorator; -import org.springframework.util.Assert; import org.springframework.web.server.ServerWebExchange; import static org.springframework.cloud.gateway.support.GatewayToStringStyler.filterToStringCreator; @@ -224,7 +223,7 @@ private ClientCall createClientCallForType(Confi private Descriptors.MethodDescriptor getMethodDescriptor(Config config) throws IOException, Descriptors.DescriptorValidationException { - Assert.notNull(config.getProtoDescriptor(), "Proto Descriptor must not be null"); + Objects.requireNonNull(config.getProtoDescriptor(), "Proto Descriptor must not be null"); Resource descriptorFile = resourceLoader.getResource(config.getProtoDescriptor()); DescriptorProtos.FileDescriptorSet fileDescriptorSet = DescriptorProtos.FileDescriptorSet .parseFrom(descriptorFile.getInputStream()); diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RequestSizeGatewayFilterFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RequestSizeGatewayFilterFactory.java index 660bc5b0be..1decffd93b 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RequestSizeGatewayFilterFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RequestSizeGatewayFilterFactory.java @@ -16,6 +16,8 @@ package org.springframework.cloud.gateway.filter.factory; +import java.util.Objects; + import reactor.core.publisher.Mono; import org.springframework.cloud.gateway.filter.GatewayFilter; @@ -111,7 +113,7 @@ public RequestSizeGatewayFilterFactory.RequestSizeConfig setMaxSize(DataSize max // TODO: use validator annotation public void validate() { - Assert.notNull(this.maxSize, "maxSize may not be null"); + Objects.requireNonNull(this.maxSize, "maxSize may not be null"); Assert.isTrue(this.maxSize.toBytes() > 0, "maxSize must be greater than 0"); } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RetryGatewayFilterFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RetryGatewayFilterFactory.java index 12b02712a1..28a4ee25dd 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RetryGatewayFilterFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RetryGatewayFilterFactory.java @@ -21,6 +21,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Objects; import java.util.function.Predicate; import java.util.function.Supplier; @@ -456,7 +457,7 @@ public BackoffConfig(Duration firstBackoff, Duration maxBackoff, int factor, boo } public void validate() { - Assert.notNull(this.firstBackoff, "firstBackoff must be present"); + Objects.requireNonNull(this.firstBackoff, "firstBackoff must be present"); } public Duration getFirstBackoff() { diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RewritePathGatewayFilterFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RewritePathGatewayFilterFactory.java index 2907340bbb..33c75b32d8 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RewritePathGatewayFilterFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/factory/RewritePathGatewayFilterFactory.java @@ -111,7 +111,7 @@ public Config setRegexp(String regexp) { } public Config setReplacement(String replacement) { - Assert.notNull(replacement, "replacement must not be null"); + Objects.requireNonNull(replacement, "replacement must not be null"); this.replacement = replacement; return this; } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/headers/RemoveHopByHopHeadersFilter.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/headers/RemoveHopByHopHeadersFilter.java index b6c5401861..789e6d16bf 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/headers/RemoveHopByHopHeadersFilter.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/headers/RemoveHopByHopHeadersFilter.java @@ -21,13 +21,13 @@ import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.core.Ordered; import org.springframework.http.HttpHeaders; -import org.springframework.util.Assert; import org.springframework.web.server.ServerWebExchange; @ConfigurationProperties("spring.cloud.gateway.server.webflux.filter.remove-hop-by-hop") @@ -54,7 +54,7 @@ public Set getHeaders() { } public void setHeaders(Set headers) { - Assert.notNull(headers, "headers may not be null"); + Objects.requireNonNull(headers, "headers may not be null"); this.headers = headers.stream().map(String::toLowerCase).collect(Collectors.toSet()); } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/ratelimit/Bucket4jRateLimiter.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/ratelimit/Bucket4jRateLimiter.java index a43d2f276f..218655fbe8 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/ratelimit/Bucket4jRateLimiter.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/ratelimit/Bucket4jRateLimiter.java @@ -20,6 +20,7 @@ import java.time.Instant; import java.util.HashMap; import java.util.Map; +import java.util.Objects; import java.util.concurrent.CompletableFuture; import java.util.function.Function; import java.util.function.Supplier; @@ -39,7 +40,6 @@ import org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator; import org.springframework.cloud.gateway.support.ConfigurationService; import org.springframework.core.style.ToStringCreator; -import org.springframework.util.Assert; public class Bucket4jRateLimiter extends AbstractRateLimiter { @@ -160,7 +160,7 @@ public Function getConfigurationBuilder() { } public void setConfigurationBuilder(Function configurationBuilder) { - Assert.notNull(configurationBuilder, "configurationBuilder may not be null"); + Objects.requireNonNull(configurationBuilder, "configurationBuilder may not be null"); this.configurationBuilder = configurationBuilder; } @@ -172,7 +172,7 @@ public Supplier> getConfigurationSupplier } public void setConfigurationSupplier(Function configurationBuilder) { - Assert.notNull(configurationBuilder, "configurationBuilder may not be null"); + Objects.requireNonNull(configurationBuilder, "configurationBuilder may not be null"); this.configurationBuilder = configurationBuilder; } @@ -181,7 +181,7 @@ public String getHeaderName() { } public Config setHeaderName(String headerName) { - Assert.notNull(headerName, "headerName may not be null"); + Objects.requireNonNull(headerName, "headerName may not be null"); this.headerName = headerName; return this; } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/ratelimit/RateLimiter.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/ratelimit/RateLimiter.java index 2775234a75..474ab8eb97 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/ratelimit/RateLimiter.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/filter/ratelimit/RateLimiter.java @@ -18,11 +18,11 @@ import java.util.Collections; import java.util.Map; +import java.util.Objects; import reactor.core.publisher.Mono; import org.springframework.cloud.gateway.support.StatefulConfigurable; -import org.springframework.util.Assert; /** * @author Spencer Gibb @@ -42,7 +42,7 @@ class Response { public Response(boolean allowed, Map headers) { this.allowed = allowed; this.tokensRemaining = -1; - Assert.notNull(headers, "headers may not be null"); + Objects.requireNonNull(headers, "headers may not be null"); this.headers = headers; } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/AsyncPredicate.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/AsyncPredicate.java index 57e29e8bee..a8c7b8f325 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/AsyncPredicate.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/AsyncPredicate.java @@ -16,6 +16,7 @@ package org.springframework.cloud.gateway.handler; +import java.util.Objects; import java.util.function.Function; import java.util.function.Predicate; @@ -25,7 +26,6 @@ import org.springframework.cloud.gateway.handler.predicate.GatewayPredicate; import org.springframework.cloud.gateway.support.HasConfig; import org.springframework.cloud.gateway.support.Visitor; -import org.springframework.util.Assert; import org.springframework.web.server.ServerWebExchange; /** @@ -89,7 +89,7 @@ class NegateAsyncPredicate implements AsyncPredicate { private final AsyncPredicate predicate; public NegateAsyncPredicate(AsyncPredicate predicate) { - Assert.notNull(predicate, "predicate AsyncPredicate must not be null"); + Objects.requireNonNull(predicate, "predicate AsyncPredicate must not be null"); this.predicate = predicate; } @@ -112,8 +112,8 @@ class AndAsyncPredicate implements AsyncPredicate { private final AsyncPredicate right; public AndAsyncPredicate(AsyncPredicate left, AsyncPredicate right) { - Assert.notNull(left, "Left AsyncPredicate must not be null"); - Assert.notNull(right, "Right AsyncPredicate must not be null"); + Objects.requireNonNull(left, "Left AsyncPredicate must not be null"); + Objects.requireNonNull(right, "Right AsyncPredicate must not be null"); this.left = left; this.right = right; } @@ -143,8 +143,8 @@ class OrAsyncPredicate implements AsyncPredicate { private final AsyncPredicate right; public OrAsyncPredicate(AsyncPredicate left, AsyncPredicate right) { - Assert.notNull(left, "Left AsyncPredicate must not be null"); - Assert.notNull(right, "Right AsyncPredicate must not be null"); + Objects.requireNonNull(left, "Left AsyncPredicate must not be null"); + Objects.requireNonNull(right, "Right AsyncPredicate must not be null"); this.left = left; this.right = right; } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/BetweenRoutePredicateFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/BetweenRoutePredicateFactory.java index 660e734561..5bcfa2e6d6 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/BetweenRoutePredicateFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/BetweenRoutePredicateFactory.java @@ -19,6 +19,7 @@ import java.time.ZonedDateTime; import java.util.Arrays; import java.util.List; +import java.util.Objects; import java.util.function.Predicate; import jakarta.validation.constraints.NotNull; @@ -53,7 +54,7 @@ public List shortcutFieldOrder() { @Override public Predicate apply(Config config) { - Assert.notNull(config.getDatetime1(), DATETIME1_KEY + " must not be null"); + Objects.requireNonNull(config.getDatetime1(), DATETIME1_KEY + " must not be null"); Assert.isTrue(config.getDatetime1().isBefore(config.getDatetime2()), config.getDatetime1() + " must be before " + config.getDatetime2()); diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/GatewayPredicate.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/GatewayPredicate.java index 050b6d9c4e..84121a1909 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/GatewayPredicate.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/GatewayPredicate.java @@ -16,11 +16,11 @@ package org.springframework.cloud.gateway.handler.predicate; +import java.util.Objects; import java.util.function.Predicate; import org.springframework.cloud.gateway.support.HasConfig; import org.springframework.cloud.gateway.support.Visitor; -import org.springframework.util.Assert; import org.springframework.web.server.ServerWebExchange; public interface GatewayPredicate extends Predicate, HasConfig { @@ -61,7 +61,7 @@ class GatewayPredicateWrapper implements GatewayPredicate { private final Predicate delegate; public GatewayPredicateWrapper(Predicate delegate) { - Assert.notNull(delegate, "delegate GatewayPredicate must not be null"); + Objects.requireNonNull(delegate, "delegate GatewayPredicate must not be null"); this.delegate = delegate; } @@ -89,7 +89,7 @@ class NegateGatewayPredicate implements GatewayPredicate { private final GatewayPredicate predicate; public NegateGatewayPredicate(GatewayPredicate predicate) { - Assert.notNull(predicate, "predicate GatewayPredicate must not be null"); + Objects.requireNonNull(predicate, "predicate GatewayPredicate must not be null"); this.predicate = predicate; } @@ -117,8 +117,8 @@ class AndGatewayPredicate implements GatewayPredicate { private final GatewayPredicate right; public AndGatewayPredicate(GatewayPredicate left, GatewayPredicate right) { - Assert.notNull(left, "Left GatewayPredicate must not be null"); - Assert.notNull(right, "Right GatewayPredicate must not be null"); + Objects.requireNonNull(left, "Left GatewayPredicate must not be null"); + Objects.requireNonNull(right, "Right GatewayPredicate must not be null"); this.left = left; this.right = right; } @@ -148,8 +148,8 @@ class OrGatewayPredicate implements GatewayPredicate { private final GatewayPredicate right; public OrGatewayPredicate(GatewayPredicate left, GatewayPredicate right) { - Assert.notNull(left, "Left GatewayPredicate must not be null"); - Assert.notNull(right, "Right GatewayPredicate must not be null"); + Objects.requireNonNull(left, "Left GatewayPredicate must not be null"); + Objects.requireNonNull(right, "Right GatewayPredicate must not be null"); this.left = left; this.right = right; } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/ReadBodyRoutePredicateFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/ReadBodyRoutePredicateFactory.java index 7e0dcecc15..d138b48ce0 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/ReadBodyRoutePredicateFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/ReadBodyRoutePredicateFactory.java @@ -18,6 +18,7 @@ import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.function.Predicate; import org.apache.commons.logging.Log; @@ -29,7 +30,6 @@ import org.springframework.cloud.gateway.handler.AsyncPredicate; import org.springframework.cloud.gateway.support.ServerWebExchangeUtils; import org.springframework.http.codec.HttpMessageReader; -import org.springframework.util.Assert; import org.springframework.web.reactive.function.server.HandlerStrategies; import org.springframework.web.reactive.function.server.ServerRequest; import org.springframework.web.server.ServerWebExchange; @@ -90,7 +90,7 @@ public Publisher apply(ServerWebExchange exchange) { return Mono.just(false); } else { - Assert.notNull(inClass, "inClass must not be null"); + Objects.requireNonNull(inClass, "inClass must not be null"); return ServerWebExchangeUtils.cacheRequestBodyAndRequest(exchange, (serverHttpRequest) -> ServerRequest .create(exchange.mutate().request(serverHttpRequest).build(), messageReaders) diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/VersionRoutePredicateFactory.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/VersionRoutePredicateFactory.java index ac1e7f833c..e9e3c869e2 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/VersionRoutePredicateFactory.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/handler/predicate/VersionRoutePredicateFactory.java @@ -17,6 +17,7 @@ package org.springframework.cloud.gateway.handler.predicate; import java.util.List; +import java.util.Objects; import java.util.function.Predicate; import jakarta.validation.constraints.NotBlank; @@ -76,7 +77,7 @@ public boolean test(ServerWebExchange exchange) { if (config.parsedVersion == null) { Assert.state(apiVersionStrategy != null, "No ApiVersionStrategy to parse version with"); String version = config.version; - Assert.notNull(version, "version must not be null"); + Objects.requireNonNull(version, "version must not be null"); config.parsedVersion = apiVersionStrategy.parseVersion(version); } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/route/Route.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/route/Route.java index baf598af2e..3fb29c0188 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/route/Route.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/route/Route.java @@ -251,10 +251,10 @@ public B filters(GatewayFilter... gatewayFilters) { } public Route build() { - Assert.notNull(this.id, "id can not be null"); - Assert.notNull(this.uri, "uri can not be null"); + Objects.requireNonNull(this.id, "id can not be null"); + Objects.requireNonNull(this.uri, "uri can not be null"); AsyncPredicate predicate = getPredicate(); - Assert.notNull(predicate, "predicate can not be null"); + Objects.requireNonNull(predicate, "predicate can not be null"); return new Route(this.id, this.uri, this.order, predicate, this.gatewayFilters, this.metadata); } @@ -272,7 +272,7 @@ protected AsyncBuilder getThis() { @Override public AsyncPredicate getPredicate() { - Assert.notNull(this.predicate, "predicate can not be null"); + Objects.requireNonNull(this.predicate, "predicate can not be null"); return this.predicate; } @@ -286,19 +286,19 @@ public AsyncBuilder asyncPredicate(AsyncPredicate predicate) } public AsyncBuilder and(AsyncPredicate predicate) { - Assert.notNull(this.predicate, "can not call and() on null predicate"); + Objects.requireNonNull(this.predicate, "can not call and() on null predicate"); this.predicate = this.predicate.and(predicate); return this; } public AsyncBuilder or(AsyncPredicate predicate) { - Assert.notNull(this.predicate, "can not call or() on null predicate"); + Objects.requireNonNull(this.predicate, "can not call or() on null predicate"); this.predicate = this.predicate.or(predicate); return this; } public AsyncBuilder negate() { - Assert.notNull(this.predicate, "can not call negate() on null predicate"); + Objects.requireNonNull(this.predicate, "can not call negate() on null predicate"); this.predicate = this.predicate.negate(); return this; } @@ -320,19 +320,19 @@ public AsyncPredicate getPredicate() { } public Builder and(Predicate predicate) { - Assert.notNull(this.predicate, "can not call and() on null predicate"); + Objects.requireNonNull(this.predicate, "can not call and() on null predicate"); this.predicate = this.predicate.and(predicate); return this; } public Builder or(Predicate predicate) { - Assert.notNull(this.predicate, "can not call or() on null predicate"); + Objects.requireNonNull(this.predicate, "can not call or() on null predicate"); this.predicate = this.predicate.or(predicate); return this; } public Builder negate() { - Assert.notNull(this.predicate, "can not call negate() on null predicate"); + Objects.requireNonNull(this.predicate, "can not call negate() on null predicate"); this.predicate = this.predicate.negate(); return this; } diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/route/RouteRefreshListener.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/route/RouteRefreshListener.java index ff9090c5e0..623e52a560 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/route/RouteRefreshListener.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/route/RouteRefreshListener.java @@ -16,6 +16,8 @@ package org.springframework.cloud.gateway.route; +import java.util.Objects; + import org.springframework.boot.web.server.context.WebServerApplicationContext; import org.springframework.cloud.client.discovery.event.HeartbeatEvent; import org.springframework.cloud.client.discovery.event.HeartbeatMonitor; @@ -27,7 +29,6 @@ import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationListener; import org.springframework.context.event.ContextRefreshedEvent; -import org.springframework.util.Assert; // see ZuulDiscoveryRefreshListener // TODO: make abstract class in commons? @@ -38,7 +39,7 @@ public class RouteRefreshListener implements ApplicationListener getThis() { @Override protected void validate() { - Assert.notNull(this.configurable, "configurable may not be null"); + Objects.requireNonNull(this.configurable, "configurable may not be null"); } @Override @@ -170,7 +171,7 @@ protected InstanceBuilder getThis() { @Override protected void validate() { - Assert.notNull(this.instance, "instance may not be null"); + Objects.requireNonNull(this.instance, "instance may not be null"); } @Override diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/support/ServerWebExchangeUtils.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/support/ServerWebExchangeUtils.java index d48e2caa87..d2c2ad4cc6 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/support/ServerWebExchangeUtils.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/support/ServerWebExchangeUtils.java @@ -24,6 +24,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.function.Function; import java.util.function.Predicate; @@ -49,7 +50,6 @@ import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpRequestDecorator; import org.springframework.http.server.reactive.ServerHttpResponse; -import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; @@ -298,13 +298,13 @@ public static void addOriginalRequestUrl(ServerWebExchange exchange, URI url) { } public static AsyncPredicate toAsyncPredicate(Predicate predicate) { - Assert.notNull(predicate, "predicate must not be null"); + Objects.requireNonNull(predicate, "predicate must not be null"); return AsyncPredicate.from(predicate); } public static String expand(ServerWebExchange exchange, String template) { - Assert.notNull(exchange, "exchange may not be null"); - Assert.notNull(template, "template may not be null"); + Objects.requireNonNull(exchange, "exchange may not be null"); + Objects.requireNonNull(template, "template may not be null"); if (template.indexOf('{') == -1) { // short circuit return template; diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/support/tagsprovider/GatewayTagsProvider.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/support/tagsprovider/GatewayTagsProvider.java index 432061fd15..c8544585f6 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/support/tagsprovider/GatewayTagsProvider.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/support/tagsprovider/GatewayTagsProvider.java @@ -16,11 +16,11 @@ package org.springframework.cloud.gateway.support.tagsprovider; +import java.util.Objects; import java.util.function.Function; import io.micrometer.core.instrument.Tags; -import org.springframework.util.Assert; import org.springframework.web.server.ServerWebExchange; /** @@ -29,7 +29,7 @@ public interface GatewayTagsProvider extends Function { default GatewayTagsProvider and(GatewayTagsProvider other) { - Assert.notNull(other, "other must not be null"); + Objects.requireNonNull(other, "other must not be null"); return exchange -> other.apply(exchange).and(apply(exchange)); } diff --git a/spring-cloud-gateway-server-webflux/src/test/java/org/springframework/cloud/gateway/actuate/GatewayControllerEndpointTests.java b/spring-cloud-gateway-server-webflux/src/test/java/org/springframework/cloud/gateway/actuate/GatewayControllerEndpointTests.java index b4392b6ebe..4f84c3a520 100644 --- a/spring-cloud-gateway-server-webflux/src/test/java/org/springframework/cloud/gateway/actuate/GatewayControllerEndpointTests.java +++ b/spring-cloud-gateway-server-webflux/src/test/java/org/springframework/cloud/gateway/actuate/GatewayControllerEndpointTests.java @@ -834,7 +834,7 @@ public TestRoutePredicateFactory customGatewayPredicateFactory() { } - private static class TestFilterGatewayFilterFactory extends AbstractGatewayFilterFactory { + private static final class TestFilterGatewayFilterFactory extends AbstractGatewayFilterFactory { @Override public GatewayFilter apply(Object config) { diff --git a/spring-cloud-gateway-server-webflux/src/test/java/org/springframework/cloud/gateway/discovery/DiscoveryClientRouteDefinitionLocatorIntegrationTests.java b/spring-cloud-gateway-server-webflux/src/test/java/org/springframework/cloud/gateway/discovery/DiscoveryClientRouteDefinitionLocatorIntegrationTests.java index 40b424525b..964edbe920 100644 --- a/spring-cloud-gateway-server-webflux/src/test/java/org/springframework/cloud/gateway/discovery/DiscoveryClientRouteDefinitionLocatorIntegrationTests.java +++ b/spring-cloud-gateway-server-webflux/src/test/java/org/springframework/cloud/gateway/discovery/DiscoveryClientRouteDefinitionLocatorIntegrationTests.java @@ -80,7 +80,7 @@ TestDiscoveryClient discoveryClient() { } - private static class TestDiscoveryClient implements ReactiveDiscoveryClient { + private static final class TestDiscoveryClient implements ReactiveDiscoveryClient { AtomicBoolean single = new AtomicBoolean(true); diff --git a/spring-cloud-gateway-server-webflux/src/test/java/org/springframework/cloud/gateway/filter/factory/SpringCloudCircuitBreakerTestConfig.java b/spring-cloud-gateway-server-webflux/src/test/java/org/springframework/cloud/gateway/filter/factory/SpringCloudCircuitBreakerTestConfig.java index 18d8edf147..c050305423 100644 --- a/spring-cloud-gateway-server-webflux/src/test/java/org/springframework/cloud/gateway/filter/factory/SpringCloudCircuitBreakerTestConfig.java +++ b/spring-cloud-gateway-server-webflux/src/test/java/org/springframework/cloud/gateway/filter/factory/SpringCloudCircuitBreakerTestConfig.java @@ -158,7 +158,7 @@ RouterFunction routerFunction(CircuitBreakerExceptionFallbackHan return route(GET("/circuitbreakerExceptionFallback"), exceptionFallbackHandler::retrieveExceptionInfo); } - private static class CircuitBreakerExceptionFallbackHandler { + private static final class CircuitBreakerExceptionFallbackHandler { static final String RETRIEVED_EXCEPTION = "Retrieved-Exception"; diff --git a/spring-cloud-gateway-server-webflux/src/test/java/org/springframework/cloud/gateway/test/support/AbstractHttpServer.java b/spring-cloud-gateway-server-webflux/src/test/java/org/springframework/cloud/gateway/test/support/AbstractHttpServer.java index b3e1b24d56..0036667aef 100644 --- a/spring-cloud-gateway-server-webflux/src/test/java/org/springframework/cloud/gateway/test/support/AbstractHttpServer.java +++ b/spring-cloud-gateway-server-webflux/src/test/java/org/springframework/cloud/gateway/test/support/AbstractHttpServer.java @@ -18,6 +18,7 @@ import java.util.LinkedHashMap; import java.util.Map; +import java.util.Objects; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -93,7 +94,7 @@ protected HttpHandler resolveHttpHandler() { @Override public final void afterPropertiesSet() throws Exception { - Assert.notNull(this.host, "Host must not be null"); + Objects.requireNonNull(this.host, "Host must not be null"); Assert.isTrue(this.port >= 0, "Port must not be a negative number"); Assert.isTrue(this.httpHandler != null || this.handlerMap != null, "No HttpHandler configured"); Assert.state(!this.running, "Cannot reconfigure while running"); diff --git a/spring-cloud-gateway-server-webflux/src/test/java/org/springframework/cloud/gateway/test/websocket/WebSocketIntegrationTests.java b/spring-cloud-gateway-server-webflux/src/test/java/org/springframework/cloud/gateway/test/websocket/WebSocketIntegrationTests.java index 596a5942b2..deeba620f0 100644 --- a/spring-cloud-gateway-server-webflux/src/test/java/org/springframework/cloud/gateway/test/websocket/WebSocketIntegrationTests.java +++ b/spring-cloud-gateway-server-webflux/src/test/java/org/springframework/cloud/gateway/test/websocket/WebSocketIntegrationTests.java @@ -330,7 +330,7 @@ public WebFilter cookieWebFilter() { } - private static class EchoWebSocketHandler implements WebSocketHandler { + private static final class EchoWebSocketHandler implements WebSocketHandler { @Override public Mono handle(WebSocketSession session) { @@ -340,7 +340,7 @@ public Mono handle(WebSocketSession session) { } - private static class SubProtocolWebSocketHandler implements WebSocketHandler { + private static final class SubProtocolWebSocketHandler implements WebSocketHandler { @Override public List getSubProtocols() { @@ -361,7 +361,7 @@ public Mono handle(WebSocketSession session) { } - private static class CustomHeaderHandler implements WebSocketHandler { + private static final class CustomHeaderHandler implements WebSocketHandler { @Override public Mono handle(WebSocketSession session) { @@ -376,7 +376,7 @@ public Mono handle(WebSocketSession session) { } - private static class ServerClosingHandler implements WebSocketHandler { + private static final class ServerClosingHandler implements WebSocketHandler { @Override public Mono handle(WebSocketSession session) { @@ -385,7 +385,7 @@ public Mono handle(WebSocketSession session) { } - private static class ClientClosingHandler implements WebSocketHandler { + private static final class ClientClosingHandler implements WebSocketHandler { @Override public Mono handle(WebSocketSession session) { @@ -394,7 +394,7 @@ public Mono handle(WebSocketSession session) { } - private static class CookieHandler implements WebSocketHandler { + private static final class CookieHandler implements WebSocketHandler { @Override public Mono handle(WebSocketSession session) { diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/AbstractProxyExchange.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/AbstractProxyExchange.java index b5171634e2..46dd589a5f 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/AbstractProxyExchange.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/AbstractProxyExchange.java @@ -19,11 +19,11 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.Objects; import org.springframework.cloud.gateway.server.mvc.config.GatewayMvcProperties; import org.springframework.cloud.gateway.server.mvc.handler.ProxyExchange; import org.springframework.http.client.ClientHttpResponse; -import org.springframework.util.Assert; import org.springframework.util.StreamUtils; public abstract class AbstractProxyExchange implements ProxyExchange { @@ -36,9 +36,9 @@ protected AbstractProxyExchange(GatewayMvcProperties properties) { protected int copyResponseBody(ClientHttpResponse clientResponse, InputStream inputStream, OutputStream outputStream) throws IOException { - Assert.notNull(clientResponse, "No ClientResponse specified"); - Assert.notNull(inputStream, "No InputStream specified"); - Assert.notNull(outputStream, "No OutputStream specified"); + Objects.requireNonNull(clientResponse, "No ClientResponse specified"); + Objects.requireNonNull(inputStream, "No InputStream specified"); + Objects.requireNonNull(outputStream, "No OutputStream specified"); int transferredBytes; diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/MvcUtils.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/MvcUtils.java index f852d27988..3139b1cf68 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/MvcUtils.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/common/MvcUtils.java @@ -31,6 +31,7 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import org.apache.commons.logging.Log; @@ -42,7 +43,6 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.HttpInputMessage; import org.springframework.http.converter.HttpMessageConverter; -import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; @@ -144,8 +144,8 @@ public static ByteArrayInputStream getOrCacheBody(ServerRequest request) { } public static String expand(ServerRequest request, String template) { - Assert.notNull(request, "request may not be null"); - Assert.notNull(template, "template may not be null"); + Objects.requireNonNull(request, "request may not be null"); + Objects.requireNonNull(template, "template may not be null"); if (template.indexOf('{') == -1) { // short circuit return template; diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/AfterFilterFunctions.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/AfterFilterFunctions.java index a0fd429f73..057ec1c791 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/AfterFilterFunctions.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/AfterFilterFunctions.java @@ -20,6 +20,7 @@ import java.util.Arrays; import java.util.LinkedHashSet; import java.util.List; +import java.util.Objects; import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.regex.Pattern; @@ -69,7 +70,7 @@ public static BiFunction dedupeRe public static BiFunction dedupeResponseHeader(String name, DedupeStrategy strategy) { Assert.hasText(name, "name must not be null or empty"); - Assert.notNull(strategy, "strategy must not be null"); + Objects.requireNonNull(strategy, "strategy must not be null"); return (request, response) -> { dedupeHeaders(response.headers(), name, strategy); return response; diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctions.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctions.java index 67f06293b2..f9d20962b4 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctions.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/BeforeFilterFunctions.java @@ -23,6 +23,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.function.Consumer; import java.util.function.Function; import java.util.regex.Pattern; @@ -242,7 +243,7 @@ public static Function requestHeaderSize(DataSize } public static Function requestHeaderSize(DataSize maxSize, String errorHeaderName) { - Assert.notNull(maxSize, "maxSize may not be null"); + Objects.requireNonNull(maxSize, "maxSize may not be null"); Assert.isTrue(maxSize.toBytes() > 0, "maxSize must be greater than 0"); Assert.hasText(errorHeaderName, "errorHeaderName may not be empty"); return request -> { @@ -300,7 +301,7 @@ public static Function requestSize(String maxSize) } public static Function requestSize(DataSize maxSize) { - Assert.notNull(maxSize, "maxSize may not be null"); + Objects.requireNonNull(maxSize, "maxSize may not be null"); Assert.isTrue(maxSize.toBytes() > 0, "maxSize must be greater than 0"); return request -> { if (request.headers().asHttpHeaders().containsHeader(HttpHeaders.CONTENT_LENGTH)) { diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/Bucket4jFilterFunctions.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/Bucket4jFilterFunctions.java index 12910b1177..8df51990ed 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/Bucket4jFilterFunctions.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/Bucket4jFilterFunctions.java @@ -17,6 +17,7 @@ package org.springframework.cloud.gateway.server.mvc.filter; import java.time.Duration; +import java.util.Objects; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; @@ -131,7 +132,7 @@ public Function getConfigurationBuilder() } public void setConfigurationBuilder(Function configurationBuilder) { - Assert.notNull(configurationBuilder, "configurationBuilder may not be null"); + Objects.requireNonNull(configurationBuilder, "configurationBuilder may not be null"); this.configurationBuilder = configurationBuilder; } @@ -158,7 +159,7 @@ public RateLimitConfig setPeriod(Duration period) { } public RateLimitConfig setKeyResolver(Function keyResolver) { - Assert.notNull(keyResolver, "keyResolver may not be null"); + Objects.requireNonNull(keyResolver, "keyResolver may not be null"); this.keyResolver = keyResolver; return this; } @@ -196,7 +197,7 @@ public String getHeaderName() { } public RateLimitConfig setHeaderName(String headerName) { - Assert.notNull(headerName, "headerName may not be null"); + Objects.requireNonNull(headerName, "headerName may not be null"); this.headerName = headerName; return this; } diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/CircuitBreakerFilterFunctions.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/CircuitBreakerFilterFunctions.java index 85b8d39afb..61f81d867c 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/CircuitBreakerFilterFunctions.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/CircuitBreakerFilterFunctions.java @@ -21,6 +21,7 @@ import java.util.Arrays; import java.util.HashSet; import java.util.LinkedHashSet; +import java.util.Objects; import java.util.Set; import java.util.concurrent.TimeoutException; import java.util.function.Consumer; @@ -157,7 +158,7 @@ public CircuitBreakerConfig setId(String id) { } public CircuitBreakerConfig setFallbackUri(String fallbackUri) { - Assert.notNull(fallbackUri, "fallbackUri String may not be null"); + Objects.requireNonNull(fallbackUri, "fallbackUri String may not be null"); setFallbackUri(URI.create(fallbackUri)); return this; } diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/XForwardedRequestHeadersFilter.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/XForwardedRequestHeadersFilter.java index 069dccbbb8..23d79c5523 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/XForwardedRequestHeadersFilter.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/XForwardedRequestHeadersFilter.java @@ -20,6 +20,7 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.function.Predicate; import org.apache.commons.logging.Log; @@ -31,7 +32,6 @@ import org.springframework.core.Ordered; import org.springframework.core.log.LogMessage; import org.springframework.http.HttpHeaders; -import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; import org.springframework.web.servlet.function.ServerRequest; @@ -84,8 +84,8 @@ public XForwardedRequestHeadersFilter(XForwardedRequestHeadersFilterProperties p private XForwardedRequestHeadersFilter(XForwardedRequestHeadersFilterProperties props, TrustedProxies trustedProxies) { - Assert.notNull(props, "XForwardedRequestHeadersFilterProperties must not be null"); - Assert.notNull(trustedProxies, "trustedProxies must not be null"); + Objects.requireNonNull(props, "XForwardedRequestHeadersFilterProperties must not be null"); + Objects.requireNonNull(trustedProxies, "trustedProxies must not be null"); this.properties = props; this.trustedProxies = trustedProxies; } diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/GatewayAsyncServerResponse.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/GatewayAsyncServerResponse.java index caa7ca38c6..8f277b4aff 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/GatewayAsyncServerResponse.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/GatewayAsyncServerResponse.java @@ -18,6 +18,7 @@ import java.io.IOException; import java.time.Duration; +import java.util.Objects; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; import java.util.concurrent.ExecutionException; @@ -33,7 +34,6 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatusCode; -import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.MultiValueMap; import org.springframework.web.context.request.async.AsyncWebRequest; @@ -161,7 +161,7 @@ private DeferredResult createDeferredResult(HttpServletRequest r @SuppressWarnings({ "unchecked", "rawtypes" }) public static AsyncServerResponse create(Object obj, @Nullable Duration timeout) { - Assert.notNull(obj, "Argument to async must not be null"); + Objects.requireNonNull(obj, "Argument to async must not be null"); if (obj instanceof CompletableFuture futureResponse) { return new GatewayAsyncServerResponse(futureResponse, timeout); diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/GatewayEntityResponseBuilder.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/GatewayEntityResponseBuilder.java index 6e0b21f383..9a8866bc8f 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/GatewayEntityResponseBuilder.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/GatewayEntityResponseBuilder.java @@ -24,6 +24,7 @@ import java.util.Arrays; import java.util.LinkedHashSet; import java.util.List; +import java.util.Objects; import java.util.Set; import java.util.concurrent.CompletionException; import java.util.concurrent.CompletionStage; @@ -50,7 +51,6 @@ import org.springframework.http.converter.GenericHttpMessageConverter; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.server.ServletServerHttpResponse; -import org.springframework.util.Assert; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.web.HttpMediaTypeNotAcceptableException; @@ -88,7 +88,7 @@ private GatewayEntityResponseBuilder(T entity, @Nullable Type entityType) { @Override public EntityResponse.Builder status(HttpStatusCode status) { - Assert.notNull(status, "HttpStatusCode must not be null"); + Objects.requireNonNull(status, "HttpStatusCode must not be null"); this.status = status; return this; } @@ -100,7 +100,7 @@ public EntityResponse.Builder status(int status) { @Override public EntityResponse.Builder cookie(Cookie cookie) { - Assert.notNull(cookie, "Cookie must not be null"); + Objects.requireNonNull(cookie, "Cookie must not be null"); this.cookies.add(cookie.getName(), cookie); return this; } diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/GatewayErrorHandlingServerResponse.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/GatewayErrorHandlingServerResponse.java index e930485020..c33b1a0cd2 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/GatewayErrorHandlingServerResponse.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/GatewayErrorHandlingServerResponse.java @@ -19,6 +19,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.function.BiFunction; import java.util.function.Predicate; @@ -29,7 +30,6 @@ import org.apache.commons.logging.LogFactory; import org.jspecify.annotations.Nullable; -import org.springframework.util.Assert; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.function.RouterFunctions; import org.springframework.web.servlet.function.ServerRequest; @@ -50,8 +50,8 @@ abstract class GatewayErrorHandlingServerResponse implements ServerResponse { protected final void addErrorHandler(Predicate predicate, BiFunction errorHandler) { - Assert.notNull(predicate, "Predicate must not be null"); - Assert.notNull(errorHandler, "ErrorHandler must not be null"); + Objects.requireNonNull(predicate, "Predicate must not be null"); + Objects.requireNonNull(errorHandler, "ErrorHandler must not be null"); this.errorHandlers.add(new ErrorHandler<>(predicate, errorHandler)); } @@ -91,8 +91,8 @@ private static class ErrorHandler { private final BiFunction responseProvider; ErrorHandler(Predicate predicate, BiFunction responseProvider) { - Assert.notNull(predicate, "Predicate must not be null"); - Assert.notNull(responseProvider, "ResponseProvider must not be null"); + Objects.requireNonNull(predicate, "Predicate must not be null"); + Objects.requireNonNull(responseProvider, "ResponseProvider must not be null"); this.predicate = predicate; this.responseProvider = responseProvider; } diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/GatewayRenderingResponseBuilder.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/GatewayRenderingResponseBuilder.java index 8cca4f0c74..71e3192edf 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/GatewayRenderingResponseBuilder.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/GatewayRenderingResponseBuilder.java @@ -21,6 +21,7 @@ import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; +import java.util.Objects; import java.util.function.Consumer; import jakarta.servlet.http.Cookie; @@ -32,7 +33,6 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode; -import org.springframework.util.Assert; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.web.servlet.ModelAndView; @@ -57,7 +57,7 @@ final class GatewayRenderingResponseBuilder implements RenderingResponse.Builder private final Map model = new LinkedHashMap<>(); GatewayRenderingResponseBuilder(RenderingResponse other) { - Assert.notNull(other, "RenderingResponse must not be null"); + Objects.requireNonNull(other, "RenderingResponse must not be null"); this.name = other.name(); this.status = other.statusCode(); this.headers.putAll(other.headers()); @@ -65,13 +65,13 @@ final class GatewayRenderingResponseBuilder implements RenderingResponse.Builder } GatewayRenderingResponseBuilder(String name) { - Assert.notNull(name, "Name must not be null"); + Objects.requireNonNull(name, "Name must not be null"); this.name = name; } @Override public RenderingResponse.Builder status(HttpStatusCode status) { - Assert.notNull(status, "HttpStatusCode must not be null"); + Objects.requireNonNull(status, "HttpStatusCode must not be null"); this.status = status; return this; } @@ -83,7 +83,7 @@ public RenderingResponse.Builder status(int status) { @Override public RenderingResponse.Builder cookie(Cookie cookie) { - Assert.notNull(cookie, "Cookie must not be null"); + Objects.requireNonNull(cookie, "Cookie must not be null"); this.cookies.add(cookie.getName(), cookie); return this; } @@ -96,7 +96,7 @@ public RenderingResponse.Builder cookies(Consumer> @Override public RenderingResponse.Builder modelAttribute(Object attribute) { - Assert.notNull(attribute, "Attribute must not be null"); + Objects.requireNonNull(attribute, "Attribute must not be null"); if (attribute instanceof Collection collection && collection.isEmpty()) { return this; } @@ -105,7 +105,7 @@ public RenderingResponse.Builder modelAttribute(Object attribute) { @Override public RenderingResponse.Builder modelAttribute(String name, @Nullable Object value) { - Assert.notNull(name, "Name must not be null"); + Objects.requireNonNull(name, "Name must not be null"); this.model.put(name, value); return this; } diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/GatewayServerResponseBuilder.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/GatewayServerResponseBuilder.java index 084c64d0da..496dc35f0e 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/GatewayServerResponseBuilder.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/GatewayServerResponseBuilder.java @@ -22,6 +22,7 @@ import java.util.Arrays; import java.util.LinkedHashSet; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.function.Consumer; @@ -36,7 +37,6 @@ import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatusCode; import org.springframework.http.MediaType; -import org.springframework.util.Assert; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.web.servlet.ModelAndView; @@ -57,14 +57,14 @@ class GatewayServerResponseBuilder implements ServerResponse.BodyBuilder { private final MultiValueMap cookies = new LinkedMultiValueMap<>(); GatewayServerResponseBuilder(ServerResponse other) { - Assert.notNull(other, "ServerResponse must not be null"); + Objects.requireNonNull(other, "ServerResponse must not be null"); this.statusCode = other.statusCode(); this.headers.addAll(other.headers()); this.cookies.addAll(other.cookies()); } GatewayServerResponseBuilder(HttpStatusCode status) { - Assert.notNull(status, "HttpStatusCode must not be null"); + Objects.requireNonNull(status, "HttpStatusCode must not be null"); this.statusCode = status; } @@ -84,7 +84,7 @@ public ServerResponse.BodyBuilder headers(Consumer headersConsumer) @Override public ServerResponse.BodyBuilder cookie(Cookie cookie) { - Assert.notNull(cookie, "Cookie must not be null"); + Objects.requireNonNull(cookie, "Cookie must not be null"); this.cookies.add(cookie.getName(), cookie); return this; } @@ -221,7 +221,7 @@ private static class WriteFunctionResponse extends AbstractGatewayServerResponse WriteFunction writeFunction) { super(statusCode, headers, cookies); - Assert.notNull(writeFunction, "WriteFunction must not be null"); + Objects.requireNonNull(writeFunction, "WriteFunction must not be null"); this.writeFunction = writeFunction; } diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/GatewayStreamingServerResponse.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/GatewayStreamingServerResponse.java index 08b1c2794a..0512fa0001 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/GatewayStreamingServerResponse.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/handler/GatewayStreamingServerResponse.java @@ -20,6 +20,7 @@ import java.nio.charset.StandardCharsets; import java.time.Duration; import java.util.List; +import java.util.Objects; import java.util.function.Consumer; import jakarta.servlet.http.Cookie; @@ -34,7 +35,6 @@ import org.springframework.http.server.DelegatingServerHttpResponse; import org.springframework.http.server.ServerHttpResponse; import org.springframework.http.server.ServletServerHttpResponse; -import org.springframework.util.Assert; import org.springframework.util.MultiValueMap; import org.springframework.web.context.request.async.DeferredResult; import org.springframework.web.servlet.ModelAndView; @@ -60,10 +60,10 @@ private GatewayStreamingServerResponse(HttpStatusCode statusCode, HttpHeaders he static ServerResponse create(HttpStatusCode statusCode, HttpHeaders headers, MultiValueMap cookies, Consumer streamConsumer, @Nullable Duration timeout) { - Assert.notNull(statusCode, "statusCode must not be null"); - Assert.notNull(headers, "headers must not be null"); - Assert.notNull(cookies, "cookies must not be null"); - Assert.notNull(streamConsumer, "streamConsumer must not be null"); + Objects.requireNonNull(statusCode, "statusCode must not be null"); + Objects.requireNonNull(headers, "headers must not be null"); + Objects.requireNonNull(cookies, "cookies must not be null"); + Objects.requireNonNull(streamConsumer, "streamConsumer must not be null"); return new GatewayStreamingServerResponse(statusCode, headers, cookies, streamConsumer, timeout); } @@ -110,7 +110,7 @@ public StreamBuilder write(Object object) throws IOException { @Override public StreamBuilder write(Object object, @Nullable MediaType mediaType) throws IOException { - Assert.notNull(object, "data must not be null"); + Objects.requireNonNull(object, "data must not be null"); try { if (object instanceof byte[] bytes) { this.outputMessage.getBody().write(bytes); diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/invoke/InvocationContext.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/invoke/InvocationContext.java index 03c8c506e5..86fe5b06c3 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/invoke/InvocationContext.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/invoke/InvocationContext.java @@ -20,11 +20,10 @@ import java.util.Arrays; import java.util.List; import java.util.Map; +import java.util.Objects; import org.jspecify.annotations.Nullable; -import org.springframework.util.Assert; - /** * The context for the {@link OperationInvoker invocation of an operation}. * @@ -46,7 +45,7 @@ public class InvocationContext { * the operation. */ public InvocationContext(Map arguments, OperationArgumentResolver... argumentResolvers) { - Assert.notNull(arguments, "Arguments must not be null"); + Objects.requireNonNull(arguments, "Arguments must not be null"); this.arguments = arguments; this.argumentResolvers = new ArrayList<>(); if (argumentResolvers != null) { diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/invoke/OperationArgumentResolver.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/invoke/OperationArgumentResolver.java index 649646ad92..3c03ecc138 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/invoke/OperationArgumentResolver.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/invoke/OperationArgumentResolver.java @@ -16,12 +16,11 @@ package org.springframework.cloud.gateway.server.mvc.invoke; +import java.util.Objects; import java.util.function.Supplier; import org.jspecify.annotations.Nullable; -import org.springframework.util.Assert; - /** * Resolver for an argument of an {@link Operation}. * @@ -55,8 +54,8 @@ public interface OperationArgumentResolver { * @return an {@link OperationArgumentResolver} instance */ static OperationArgumentResolver of(Class type, Supplier supplier) { - Assert.notNull(type, "Type must not be null"); - Assert.notNull(supplier, "Supplier must not be null"); + Objects.requireNonNull(type, "Type must not be null"); + Objects.requireNonNull(supplier, "Supplier must not be null"); return new OperationArgumentResolver() { @Override diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/invoke/convert/ConversionServiceParameterValueMapper.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/invoke/convert/ConversionServiceParameterValueMapper.java index c0f6e164f8..20fdfc3b8c 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/invoke/convert/ConversionServiceParameterValueMapper.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/invoke/convert/ConversionServiceParameterValueMapper.java @@ -23,7 +23,6 @@ import org.springframework.cloud.gateway.server.mvc.invoke.ParameterMappingException; import org.springframework.cloud.gateway.server.mvc.invoke.ParameterValueMapper; import org.springframework.core.convert.ConversionService; -import org.springframework.util.Assert; /** * {@link ParameterValueMapper} backed by a {@link ConversionService}. @@ -49,7 +48,7 @@ public ConversionServiceParameterValueMapper() { * @param conversionService the conversion service */ public ConversionServiceParameterValueMapper(ConversionService conversionService) { - Assert.notNull(conversionService, "ConversionService must not be null"); + Objects.requireNonNull(conversionService, "ConversionService must not be null"); this.conversionService = conversionService; } diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/invoke/reflect/DefaultOperationMethod.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/invoke/reflect/DefaultOperationMethod.java index 97975ca6bb..e9cb920a7a 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/invoke/reflect/DefaultOperationMethod.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/invoke/reflect/DefaultOperationMethod.java @@ -17,11 +17,11 @@ package org.springframework.cloud.gateway.server.mvc.invoke.reflect; import java.lang.reflect.Method; +import java.util.Objects; import org.springframework.cloud.gateway.server.mvc.invoke.OperationParameters; import org.springframework.core.DefaultParameterNameDiscoverer; import org.springframework.core.ParameterNameDiscoverer; -import org.springframework.util.Assert; /** * Information describing an operation method on an endpoint method. @@ -43,7 +43,7 @@ public class DefaultOperationMethod implements OperationMethod { * @param method the source method */ public DefaultOperationMethod(Method method) { - Assert.notNull(method, "Method must not be null"); + Objects.requireNonNull(method, "Method must not be null"); this.method = method; this.operationParameters = new OperationMethodParameters(method, DEFAULT_PARAMETER_NAME_DISCOVERER); } diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/invoke/reflect/OperationMethodParameter.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/invoke/reflect/OperationMethodParameter.java index beaf450335..a6547cf733 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/invoke/reflect/OperationMethodParameter.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/invoke/reflect/OperationMethodParameter.java @@ -80,7 +80,7 @@ public String toString() { return this.name + " of type " + this.parameter.getType().getName(); } - private static class Jsr305 { + private static final class Jsr305 { boolean isMandatory(Parameter parameter) { MergedAnnotation annotation = MergedAnnotations.from(parameter).get(Nonnull.class); diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/invoke/reflect/OperationMethodParameters.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/invoke/reflect/OperationMethodParameters.java index 3b87e25662..442dd0d301 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/invoke/reflect/OperationMethodParameters.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/invoke/reflect/OperationMethodParameters.java @@ -30,7 +30,6 @@ import org.springframework.cloud.gateway.server.mvc.invoke.OperationParameter; import org.springframework.cloud.gateway.server.mvc.invoke.OperationParameters; import org.springframework.core.ParameterNameDiscoverer; -import org.springframework.util.Assert; /** * {@link OperationParameters} created from an {@link OperationMethod}. @@ -47,8 +46,8 @@ class OperationMethodParameters implements OperationParameters { * @param parameterNameDiscoverer the parameter name discoverer */ OperationMethodParameters(Method method, ParameterNameDiscoverer parameterNameDiscoverer) { - Assert.notNull(method, "Method must not be null"); - Assert.notNull(parameterNameDiscoverer, "ParameterNameDiscoverer must not be null"); + Objects.requireNonNull(method, "Method must not be null"); + Objects.requireNonNull(parameterNameDiscoverer, "ParameterNameDiscoverer must not be null"); @Nullable String @Nullable [] parameterNames = parameterNameDiscoverer.getParameterNames(method); Parameter[] parameters = method.getParameters(); this.operationParameters = getOperationParameters(parameters, parameterNames); diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/invoke/reflect/ReflectiveOperationInvoker.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/invoke/reflect/ReflectiveOperationInvoker.java index 6e74a931db..f72ff7ed09 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/invoke/reflect/ReflectiveOperationInvoker.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/invoke/reflect/ReflectiveOperationInvoker.java @@ -29,7 +29,6 @@ import org.springframework.cloud.gateway.server.mvc.invoke.OperationParameter; import org.springframework.cloud.gateway.server.mvc.invoke.ParameterValueMapper; import org.springframework.core.style.ToStringCreator; -import org.springframework.util.Assert; import org.springframework.util.ReflectionUtils; /** @@ -71,9 +70,9 @@ public ReflectiveOperationInvoker(OperationMethod operationMethod, ParameterValu */ public ReflectiveOperationInvoker(@Nullable Object target, OperationMethod operationMethod, ParameterValueMapper parameterValueMapper) { - // Assert.notNull(target, "Target must not be null"); - Assert.notNull(operationMethod, "OperationMethod must not be null"); - Assert.notNull(parameterValueMapper, "ParameterValueMapper must not be null"); + // Objects.requireNonNull(target, "Target must not be null"); + Objects.requireNonNull(operationMethod, "OperationMethod must not be null"); + Objects.requireNonNull(parameterValueMapper, "ParameterValueMapper must not be null"); ReflectionUtils.makeAccessible(operationMethod.getMethod()); this.target = target; this.operationMethod = operationMethod; diff --git a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/predicate/GatewayRequestPredicates.java b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/predicate/GatewayRequestPredicates.java index 4913449d9c..aba932ed85 100644 --- a/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/predicate/GatewayRequestPredicates.java +++ b/spring-cloud-gateway-server-webmvc/src/main/java/org/springframework/cloud/gateway/server/mvc/predicate/GatewayRequestPredicates.java @@ -23,6 +23,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.function.Function; import java.util.function.Predicate; @@ -129,7 +130,7 @@ public static RequestPredicate method(HttpMethod... methods) { } public static RequestPredicate host(String pattern) { - Assert.notNull(pattern, "'pattern' must not be null"); + Objects.requireNonNull(pattern, "'pattern' must not be null"); return hostPredicates(DEFAULT_HOST_INSTANCE).apply(pattern); } @@ -156,7 +157,7 @@ public static RequestPredicate host(String... patterns) { * {@code RequestPredicates} instance */ public static Function hostPredicates(PathPatternParser patternParser) { - Assert.notNull(patternParser, "PathPatternParser must not be null"); + Objects.requireNonNull(patternParser, "PathPatternParser must not be null"); return pattern -> new HostPatternPredicate(patternParser.parse(pattern)); } @@ -389,7 +390,7 @@ private static class HostPatternPredicate implements RequestPredicate, ChangePat private PathPattern pattern; HostPatternPredicate(PathPattern pattern) { - Assert.notNull(pattern, "'pattern' must not be null"); + Objects.requireNonNull(pattern, "'pattern' must not be null"); this.pattern = pattern; } @@ -451,7 +452,7 @@ private static class ChangePathPatternParserVisitor implements RouterFunctions.V private final PathPatternParser parser; ChangePathPatternParserVisitor(PathPatternParser parser) { - Assert.notNull(parser, "Parser must not be null"); + Objects.requireNonNull(parser, "Parser must not be null"); this.parser = parser; } diff --git a/spring-cloud-gateway-server-webmvc/src/test/java/org/springframework/cloud/gateway/server/mvc/ServerMvcIntegrationTests.java b/spring-cloud-gateway-server-webmvc/src/test/java/org/springframework/cloud/gateway/server/mvc/ServerMvcIntegrationTests.java index 4766fc7090..d20d6acd35 100644 --- a/spring-cloud-gateway-server-webmvc/src/test/java/org/springframework/cloud/gateway/server/mvc/ServerMvcIntegrationTests.java +++ b/spring-cloud-gateway-server-webmvc/src/test/java/org/springframework/cloud/gateway/server/mvc/ServerMvcIntegrationTests.java @@ -1690,7 +1690,7 @@ public String toString() { } - private static class MyFilter implements Filter, Ordered { + private static final class MyFilter implements Filter, Ordered { @Override public int getOrder() { diff --git a/spring-cloud-gateway-server-webmvc/src/test/java/org/springframework/cloud/gateway/server/mvc/test/HttpbinUriResolver.java b/spring-cloud-gateway-server-webmvc/src/test/java/org/springframework/cloud/gateway/server/mvc/test/HttpbinUriResolver.java index 3d01487a12..7c15b5715d 100644 --- a/spring-cloud-gateway-server-webmvc/src/test/java/org/springframework/cloud/gateway/server/mvc/test/HttpbinUriResolver.java +++ b/spring-cloud-gateway-server-webmvc/src/test/java/org/springframework/cloud/gateway/server/mvc/test/HttpbinUriResolver.java @@ -19,6 +19,7 @@ import java.lang.reflect.UndeclaredThrowableException; import java.net.URI; import java.net.URISyntaxException; +import java.util.Objects; import java.util.function.Function; import org.springframework.cloud.gateway.server.mvc.common.MvcUtils; @@ -37,7 +38,7 @@ protected URI uri(ServerRequest request) { Integer port = context.getEnvironment().getProperty("httpbin.port", Integer.class); String host = context.getEnvironment().getProperty("httpbin.host"); Assert.hasText(host, "httpbin.host is not set, did you initialize HttpbinTestcontainers?"); - Assert.notNull(port, "httpbin.port is not set, did you initialize HttpbinTestcontainers?"); + Objects.requireNonNull(port, "httpbin.port is not set, did you initialize HttpbinTestcontainers?"); URI original = request.uri(); try { return new URI("http", original.getUserInfo(), host, port, original.getPath(), original.getQuery(), diff --git a/spring-cloud-gateway-server-webmvc/src/test/java/org/springframework/cloud/gateway/server/mvc/test/LocalHostUriBuilderFactory.java b/spring-cloud-gateway-server-webmvc/src/test/java/org/springframework/cloud/gateway/server/mvc/test/LocalHostUriBuilderFactory.java index b6dc0c2f5f..b797cb96d2 100644 --- a/spring-cloud-gateway-server-webmvc/src/test/java/org/springframework/cloud/gateway/server/mvc/test/LocalHostUriBuilderFactory.java +++ b/spring-cloud-gateway-server-webmvc/src/test/java/org/springframework/cloud/gateway/server/mvc/test/LocalHostUriBuilderFactory.java @@ -21,11 +21,11 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.Objects; import java.util.Optional; import org.springframework.core.env.Environment; import org.springframework.lang.Nullable; -import org.springframework.util.Assert; import org.springframework.util.MultiValueMap; import org.springframework.util.ObjectUtils; import org.springframework.web.util.DefaultUriBuilderFactory; @@ -67,8 +67,8 @@ public LocalHostUriBuilderFactory(Environment environment) { * @since 1.4.1 */ public LocalHostUriBuilderFactory(Environment environment, String scheme) { - Assert.notNull(environment, "Environment must not be null"); - Assert.notNull(scheme, "Scheme must not be null"); + Objects.requireNonNull(environment, "Environment must not be null"); + Objects.requireNonNull(scheme, "Scheme must not be null"); this.environment = environment; this.scheme = scheme; }