Skip to content

Commit 57f566e

Browse files
committed
Adds jspecify nullability to gateway server webmvc
Fixes gh-3952
1 parent b9b8dde commit 57f566e

32 files changed

+305
-75
lines changed

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

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
import java.util.concurrent.atomic.AtomicReference;
2323
import java.util.function.Function;
2424

25+
import org.jspecify.annotations.Nullable;
26+
2527
import org.springframework.beans.BeansException;
2628
import org.springframework.beans.factory.config.BeanPostProcessor;
2729
import org.springframework.cloud.gateway.server.mvc.common.ArgumentSupplier.ArgumentSuppliedEvent;
@@ -63,7 +65,7 @@ public Object postProcessBeforeInitialization(Object bean, String beanName) thro
6365
return bean;
6466
}
6567

66-
class RouterFunctionVisitor implements RouterFunctions.Visitor {
68+
static class RouterFunctionVisitor implements RouterFunctions.Visitor {
6769

6870
private final PredicateVisitor predicateVisitor;
6971

@@ -102,18 +104,19 @@ public void unknown(RouterFunction<?> routerFunction) {
102104

103105
}
104106

105-
class PredicateVisitor implements RequestPredicates.Visitor {
107+
static class PredicateVisitor implements RequestPredicates.Visitor {
106108

107-
private final AtomicReference<Map<String, Object>> attributesRef = new AtomicReference<>();
109+
private final AtomicReference<@Nullable Map<String, Object>> attributesRef = new AtomicReference<>();
108110

109-
private ArgumentSupplier argumentSupplier;
111+
private @Nullable ArgumentSupplier<?> argumentSupplier;
110112

111-
private Map<String, Object> attributes;
113+
private @Nullable Map<String, Object> attributes;
112114

113115
@Override
116+
@SuppressWarnings("rawtypes")
114117
public void unknown(RequestPredicate predicate) {
115-
if (predicate instanceof ArgumentSupplier argumentSupplier) {
116-
this.argumentSupplier = argumentSupplier;
118+
if (predicate instanceof ArgumentSupplier argSupplier) {
119+
this.argumentSupplier = argSupplier;
117120
this.attributes = attributesRef.get();
118121
}
119122
}
@@ -129,6 +132,7 @@ public void path(String pattern) {
129132
}
130133

131134
@Override
135+
@SuppressWarnings("removal")
132136
public void pathExtension(String extension) {
133137

134138
}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,14 @@
1818

1919
import java.util.Locale;
2020

21+
import org.jspecify.annotations.NullUnmarked;
22+
2123
import org.springframework.core.style.ToStringCreator;
2224
import org.springframework.http.HttpStatus;
2325
import org.springframework.http.HttpStatusCode;
2426
import org.springframework.util.Assert;
2527

28+
@NullUnmarked
2629
public class HttpStatusHolder {
2730

2831
private final HttpStatusCode httpStatus;

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

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333

3434
import org.apache.commons.logging.Log;
3535
import org.apache.commons.logging.LogFactory;
36+
import org.jspecify.annotations.Nullable;
3637

3738
import org.springframework.context.ApplicationContext;
3839
import org.springframework.core.log.LogMessage;
@@ -123,7 +124,7 @@ public static ByteArrayInputStream cacheBody(ServerRequest request) {
123124
try {
124125
byte[] bytes = StreamUtils.copyToByteArray(request.servletRequest().getInputStream());
125126
ByteArrayInputStream body = new ByteArrayInputStream(bytes);
126-
putAttribute(request, MvcUtils.CACHED_REQUEST_BODY_ATTR, body);
127+
putAttribute(request, CACHED_REQUEST_BODY_ATTR, body);
127128
return body;
128129
}
129130
catch (IOException e) {
@@ -132,7 +133,7 @@ public static ByteArrayInputStream cacheBody(ServerRequest request) {
132133
}
133134

134135
public static ByteArrayInputStream getOrCacheBody(ServerRequest request) {
135-
ByteArrayInputStream body = getAttribute(request, MvcUtils.CACHED_REQUEST_BODY_ATTR);
136+
ByteArrayInputStream body = getAttribute(request, CACHED_REQUEST_BODY_ATTR);
136137
if (body != null) {
137138
return body;
138139
}
@@ -157,11 +158,11 @@ public static String expand(ServerRequest request, String template) {
157158
}
158159

159160
public static List<String> expandMultiple(ServerRequest request, Collection<String> templates) {
160-
return templates.stream().map(value -> MvcUtils.expand(request, value)).toList();
161+
return templates.stream().map(value -> expand(request, value)).toList();
161162
}
162163

163164
public static String[] expandMultiple(ServerRequest request, String... templates) {
164-
List<String> expanded = Arrays.stream(templates).map(value -> MvcUtils.expand(request, value)).toList();
165+
List<String> expanded = Arrays.stream(templates).map(value -> expand(request, value)).toList();
165166
return expanded.toArray(new String[0]);
166167
}
167168

@@ -175,7 +176,7 @@ public static ApplicationContext getApplicationContext(ServerRequest request) {
175176
}
176177

177178
@SuppressWarnings("unchecked")
178-
public static <T> T getAttribute(ServerRequest request, String key) {
179+
public static <T> @Nullable T getAttribute(ServerRequest request, String key) {
179180
if (request.attributes().containsKey(key)) {
180181
return (T) request.attributes().get(key);
181182
}
@@ -202,7 +203,7 @@ public static Map<String, Object> getUriTemplateVariables(ServerRequest request)
202203
return merged;
203204
}
204205

205-
public static void putAttribute(ServerRequest request, String key, Object value) {
206+
public static void putAttribute(ServerRequest request, String key, @Nullable Object value) {
206207
request.attributes().put(key, value);
207208
getGatewayAttributes(request).put(key, value);
208209
}
@@ -237,7 +238,7 @@ public static <K, V> Map<K, V> mergeMaps(Map<K, V> left, Map<K, V> right) {
237238
}
238239
}
239240

240-
@SuppressWarnings("unchecked")
241+
@SuppressWarnings({ "unchecked", "rawtypes" })
241242
public static <T> Optional<T> readBody(ServerRequest request, ByteArrayInputStream body, Class<T> toClass) {
242243
try {
243244
HttpInputMessage inputMessage = new ByteArrayInputMessage(request, body);

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import jakarta.validation.constraints.Min;
2020
import jakarta.validation.constraints.NotEmpty;
21+
import org.jspecify.annotations.Nullable;
2122

2223
import org.springframework.core.style.ToStringCreator;
2324
import org.springframework.validation.annotation.Validated;
@@ -33,15 +34,15 @@ public class WeightConfig {
3334
@NotEmpty
3435
private String group;
3536

36-
private String routeId;
37+
private @Nullable String routeId;
3738

3839
@Min(0)
3940
private int weight;
4041

4142
private WeightConfig() {
4243
}
4344

44-
public WeightConfig(String routeId, String group, int weight) {
45+
public WeightConfig(@Nullable String routeId, String group, int weight) {
4546
this.routeId = routeId;
4647
this.group = group;
4748
this.weight = weight;
@@ -60,7 +61,7 @@ public WeightConfig setGroup(String group) {
6061
return this;
6162
}
6263

63-
public String getRouteId() {
64+
public @Nullable String getRouteId() {
6465
return routeId;
6566
}
6667

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* Copyright 2013-present the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
/**
18+
* Package that contains commons shared classes and interfaces.
19+
*/
20+
@NullMarked
21+
package org.springframework.cloud.gateway.server.mvc.common;
22+
23+
import org.jspecify.annotations.NullMarked;
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* Copyright 2013-present the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
/**
18+
* Package that contains implementation of creating RouterFunctions from external
19+
* configuration.
20+
*/
21+
@NullMarked
22+
package org.springframework.cloud.gateway.server.mvc.config;
23+
24+
import org.jspecify.annotations.NullMarked;

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import com.fasterxml.jackson.databind.JsonNode;
2929
import com.fasterxml.jackson.databind.ObjectMapper;
3030
import com.fasterxml.jackson.databind.node.ObjectNode;
31+
import org.jspecify.annotations.Nullable;
3132

3233
import org.springframework.cloud.gateway.server.mvc.common.HttpStatusHolder;
3334
import org.springframework.cloud.gateway.server.mvc.common.MvcUtils;
@@ -75,7 +76,8 @@ public static BiFunction<ServerRequest, ServerResponse, ServerResponse> dedupeRe
7576
};
7677
}
7778

78-
private static void dedupeHeaders(HttpHeaders headers, String names, DedupeStrategy strategy) {
79+
private static void dedupeHeaders(@Nullable HttpHeaders headers, @Nullable String names,
80+
@Nullable DedupeStrategy strategy) {
7981
if (headers == null || names == null || strategy == null) {
8082
return;
8183
}

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

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

3030
import org.apache.commons.logging.Log;
3131
import org.apache.commons.logging.LogFactory;
32+
import org.jspecify.annotations.Nullable;
3233

3334
import org.springframework.cloud.gateway.server.mvc.common.KeyValues.KeyValue;
3435
import org.springframework.cloud.gateway.server.mvc.common.MvcUtils;
@@ -155,7 +156,7 @@ public static Function<ServerRequest, ServerRequest> fallbackHeaders(
155156
.orElse(request);
156157
}
157158

158-
private static Throwable getRootCause(Throwable throwable) {
159+
private static @Nullable Throwable getRootCause(Throwable throwable) {
159160
List<Throwable> list = getThrowableList(throwable);
160161
return list.isEmpty() ? null : list.get(list.size() - 1);
161162
}
@@ -307,7 +308,7 @@ public static Function<ServerRequest, ServerRequest> requestSize(DataSize maxSiz
307308
if (contentLength > maxSize.toBytes()) {
308309
String errorMessage = String.format(REQUEST_SIZE_ERROR_MSG, DataSize.ofBytes(contentLength),
309310
maxSize);
310-
throw new ResponseStatusException(HttpStatus.PAYLOAD_TOO_LARGE, errorMessage) {
311+
throw new ResponseStatusException(HttpStatus.CONTENT_TOO_LARGE, errorMessage) {
311312
@Override
312313
public HttpHeaders getHeaders() {
313314
HttpHeaders httpHeaders = new HttpHeaders();

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import jakarta.servlet.http.HttpServletRequestWrapper;
4242
import jakarta.servlet.http.HttpSession;
4343
import jakarta.servlet.http.Part;
44+
import org.jspecify.annotations.Nullable;
4445

4546
import org.springframework.cloud.gateway.server.mvc.common.MvcUtils;
4647
import org.springframework.core.ParameterizedTypeReference;
@@ -102,7 +103,7 @@ public HttpServletRequest servletRequest() {
102103

103104
@SuppressWarnings("unchecked")
104105
public static <T, R> Function<ServerRequest, ServerRequest> modifyRequestBody(Class<T> inClass, Class<R> outClass,
105-
String newContentType, RewriteFunction<T, R> rewriteFunction) {
106+
@Nullable String newContentType, RewriteFunction<T, R> rewriteFunction) {
106107
return request -> cacheAndReadBody(request, inClass).map(body -> {
107108
R convertedBody = rewriteFunction.apply(request, body);
108109
// TODO: cache converted body
@@ -146,7 +147,7 @@ public static <T, R> Function<ServerRequest, ServerRequest> modifyRequestBody(Cl
146147

147148
@SuppressWarnings({ "unchecked", "rawtypes" })
148149
public static <T, R> BiFunction<ServerRequest, ServerResponse, ServerResponse> modifyResponseBody(Class<T> inClass,
149-
Class<R> outClass, String newContentType, RewriteResponseFunction<T, R> rewriteFunction) {
150+
Class<R> outClass, @Nullable String newContentType, RewriteResponseFunction<T, R> rewriteFunction) {
150151
return (request, response) -> {
151152
Object o = request.attributes().get(MvcUtils.CLIENT_RESPONSE_INPUT_STREAM_ATTR);
152153
if (o instanceof InputStream inputStream) {

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import java.util.stream.Collectors;
2828

2929
import jakarta.servlet.ServletException;
30+
import org.jspecify.annotations.Nullable;
3031

3132
import org.springframework.cloud.client.circuitbreaker.CircuitBreaker;
3233
import org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory;
@@ -137,7 +138,7 @@ public static class CircuitBreakerConfig {
137138

138139
private String id;
139140

140-
private String fallbackPath;
141+
private @Nullable String fallbackPath;
141142

142143
private Set<String> statusCodes = new HashSet<>();
143144

@@ -150,7 +151,7 @@ public CircuitBreakerConfig setId(String id) {
150151
return this;
151152
}
152153

153-
public String getFallbackPath() {
154+
public @Nullable String getFallbackPath() {
154155
return fallbackPath;
155156
}
156157

@@ -160,7 +161,7 @@ public CircuitBreakerConfig setFallbackUri(String fallbackUri) {
160161
return this;
161162
}
162163

163-
public CircuitBreakerConfig setFallbackUri(URI fallbackUri) {
164+
public CircuitBreakerConfig setFallbackUri(@Nullable URI fallbackUri) {
164165
if (fallbackUri != null) {
165166
Assert.isTrue(fallbackUri.getScheme().equalsIgnoreCase("forward"),
166167
() -> "Scheme must be forward, but is " + fallbackUri.getScheme());

0 commit comments

Comments
 (0)