Skip to content

Commit 75c5b42

Browse files
committed
Adds jspecify nullability to gateway proxyexchange webmvc & webflux
Fixes gh-3953
1 parent 57f566e commit 75c5b42

File tree

11 files changed

+148
-27
lines changed

11 files changed

+148
-27
lines changed

spring-cloud-gateway-proxyexchange-webflux/src/main/java/org/springframework/cloud/gateway/webflux/config/ProxyExchangeArgumentResolver.java

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,13 @@
2222
import java.lang.reflect.WildcardType;
2323
import java.util.Set;
2424

25+
import org.jspecify.annotations.Nullable;
2526
import reactor.core.publisher.Mono;
2627

2728
import org.springframework.cloud.gateway.webflux.ProxyExchange;
2829
import org.springframework.core.MethodParameter;
2930
import org.springframework.http.HttpHeaders;
31+
import org.springframework.util.CollectionUtils;
3032
import org.springframework.web.reactive.BindingContext;
3133
import org.springframework.web.reactive.function.client.WebClient;
3234
import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolver;
@@ -38,13 +40,13 @@
3840
*/
3941
public class ProxyExchangeArgumentResolver implements HandlerMethodArgumentResolver {
4042

41-
private WebClient rest;
43+
private final WebClient rest;
4244

43-
private HttpHeaders headers;
45+
private @Nullable HttpHeaders headers;
4446

45-
private Set<String> autoForwardedHeaders;
47+
private @Nullable Set<String> autoForwardedHeaders;
4648

47-
private Set<String> excluded;
49+
private @Nullable Set<String> excluded;
4850

4951
public ProxyExchangeArgumentResolver(WebClient builder) {
5052
this.rest = builder;
@@ -58,7 +60,7 @@ public void setAutoForwardedHeaders(Set<String> autoForwardedHeaders) {
5860
this.autoForwardedHeaders = autoForwardedHeaders;
5961
}
6062

61-
public void setExcluded(Set<String> excluded) {
63+
public void setExcluded(@Nullable Set<String> excluded) {
6264
this.excluded = excluded;
6365
}
6466

@@ -82,11 +84,13 @@ private Type type(MethodParameter parameter) {
8284
public Mono<Object> resolveArgument(MethodParameter parameter, BindingContext bindingContext,
8385
ServerWebExchange exchange) {
8486
ProxyExchange<?> proxy = new ProxyExchange<>(rest, exchange, bindingContext, type(parameter));
85-
proxy.headers(headers);
86-
if (this.autoForwardedHeaders.size() > 0) {
87+
if (this.headers != null) {
88+
proxy.headers(headers);
89+
}
90+
if (!CollectionUtils.isEmpty(this.autoForwardedHeaders)) {
8791
proxy.headers(extractAutoForwardedHeaders(exchange));
8892
}
89-
if (excluded != null) {
93+
if (!CollectionUtils.isEmpty(excluded)) {
9094
proxy.excluded(excluded.toArray(new String[0]));
9195
}
9296
return Mono.just(proxy);
@@ -95,7 +99,7 @@ public Mono<Object> resolveArgument(MethodParameter parameter, BindingContext bi
9599
private HttpHeaders extractAutoForwardedHeaders(ServerWebExchange exchange) {
96100
HttpHeaders headers = new HttpHeaders();
97101
exchange.getRequest().getHeaders().forEach((header, values) -> {
98-
if (this.autoForwardedHeaders.contains(header)) {
102+
if (this.autoForwardedHeaders != null && this.autoForwardedHeaders.contains(header)) {
99103
headers.addAll(header, values);
100104
}
101105
});

spring-cloud-gateway-proxyexchange-webflux/src/main/java/org/springframework/cloud/gateway/webflux/config/ProxyResponseAutoConfiguration.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.springframework.context.ApplicationContext;
3030
import org.springframework.context.annotation.Bean;
3131
import org.springframework.context.annotation.Configuration;
32+
import org.springframework.util.CollectionUtils;
3233
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
3334
import org.springframework.web.reactive.config.WebFluxConfigurer;
3435
import org.springframework.web.reactive.function.client.WebClient;
@@ -60,10 +61,10 @@ public ProxyExchangeArgumentResolver proxyExchangeArgumentResolver(Optional<WebC
6061
resolver.setHeaders(properties.convertHeaders());
6162
resolver.setAutoForwardedHeaders(properties.getAutoForward());
6263
Set<String> excludedHeaderNames = new HashSet<>();
63-
if (properties.getSensitive() != null) {
64+
if (!CollectionUtils.isEmpty(properties.getSensitive())) {
6465
excludedHeaderNames.addAll(properties.getSensitive());
6566
}
66-
if (properties.getSkipped() != null) {
67+
if (!CollectionUtils.isEmpty(properties.getSkipped())) {
6768
excludedHeaderNames.addAll(properties.getSkipped());
6869
}
6970
resolver.setExcluded(excludedHeaderNames);
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+
* Configuration classes for WebFlux ProxyExchange.
19+
*/
20+
@NullMarked
21+
package org.springframework.cloud.gateway.webflux.config;
22+
23+
import org.jspecify.annotations.NullMarked;
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+
* Lightweight WebFlux Controller annotation-based API Gateway via ProxyExchange.
19+
*/
20+
@NullMarked
21+
package org.springframework.cloud.gateway.webflux;
22+
23+
import org.jspecify.annotations.NullMarked;

spring-cloud-gateway-proxyexchange-webmvc/src/main/java/org/springframework/cloud/gateway/mvc/config/ProxyExchangeArgumentResolver.java

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,12 @@
2424
import java.util.Set;
2525

2626
import jakarta.servlet.http.HttpServletRequest;
27+
import org.jspecify.annotations.Nullable;
2728

2829
import org.springframework.cloud.gateway.mvc.ProxyExchange;
2930
import org.springframework.core.MethodParameter;
3031
import org.springframework.http.HttpHeaders;
31-
import org.springframework.util.ObjectUtils;
32+
import org.springframework.util.CollectionUtils;
3233
import org.springframework.web.bind.support.WebDataBinderFactory;
3334
import org.springframework.web.client.RestTemplate;
3435
import org.springframework.web.context.request.NativeWebRequest;
@@ -45,11 +46,11 @@ public class ProxyExchangeArgumentResolver implements HandlerMethodArgumentResol
4546

4647
private final RestTemplate rest;
4748

48-
private HttpHeaders headers;
49+
private @Nullable HttpHeaders headers;
4950

50-
private Set<String> autoForwardedHeaders;
51+
private @Nullable Set<String> autoForwardedHeaders;
5152

52-
private Set<String> excluded;
53+
private @Nullable Set<String> excluded;
5354

5455
public ProxyExchangeArgumentResolver(RestTemplate builder) {
5556
this.rest = builder;
@@ -59,12 +60,12 @@ public void setHeaders(HttpHeaders headers) {
5960
this.headers = headers;
6061
}
6162

62-
public void setAutoForwardedHeaders(Set<String> autoForwardedHeaders) {
63+
public void setAutoForwardedHeaders(@Nullable Set<String> autoForwardedHeaders) {
6364
this.autoForwardedHeaders = autoForwardedHeaders == null ? null
6465
: autoForwardedHeaders.stream().map(String::toLowerCase).collect(toSet());
6566
}
6667

67-
public void setExcluded(Set<String> excluded) {
68+
public void setExcluded(@Nullable Set<String> excluded) {
6869
this.excluded = excluded;
6970
}
7071

@@ -111,13 +112,13 @@ private void configureHeaders(final ProxyExchange<?> proxy) {
111112
}
112113

113114
private void configureAutoForwardedHeaders(final ProxyExchange<?> proxy, final NativeWebRequest webRequest) {
114-
if (!ObjectUtils.isEmpty(autoForwardedHeaders)) {
115+
if (!CollectionUtils.isEmpty(this.autoForwardedHeaders)) {
115116
proxy.headers(extractAutoForwardedHeaders(webRequest));
116117
}
117118
}
118119

119120
private void configureExcluded(final ProxyExchange<?> proxy) {
120-
if (excluded != null) {
121+
if (!CollectionUtils.isEmpty(excluded)) {
121122
proxy.excluded(excluded.toArray(new String[0]));
122123
}
123124
}

spring-cloud-gateway-proxyexchange-webmvc/src/main/java/org/springframework/cloud/gateway/mvc/config/ProxyResponseAutoConfiguration.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import org.springframework.http.HttpStatusCode;
4040
import org.springframework.http.client.ClientHttpResponse;
4141
import org.springframework.http.converter.ByteArrayHttpMessageConverter;
42+
import org.springframework.util.CollectionUtils;
4243
import org.springframework.web.client.DefaultResponseErrorHandler;
4344
import org.springframework.web.client.RestTemplate;
4445
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
@@ -78,10 +79,10 @@ public boolean supports(Class<?> clazz) {
7879
resolver.setHeaders(properties.convertHeaders());
7980
resolver.setAutoForwardedHeaders(properties.getAutoForward());
8081
Set<String> excludedHeaderNames = new HashSet<>();
81-
if (properties.getSensitive() != null) {
82+
if (!CollectionUtils.isEmpty(properties.getSensitive())) {
8283
excludedHeaderNames.addAll(properties.getSensitive());
8384
}
84-
if (properties.getSkipped() != null) {
85+
if (!CollectionUtils.isEmpty(properties.getSkipped())) {
8586
excludedHeaderNames.addAll(properties.getSkipped());
8687
}
8788
resolver.setExcluded(excludedHeaderNames);
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+
* Configuration classes for WebMVC ProxyExchange.
19+
*/
20+
@NullMarked
21+
package org.springframework.cloud.gateway.mvc.config;
22+
23+
import org.jspecify.annotations.NullMarked;
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+
* Lightweight WebMVC Controller annotation-based API Gateway via ProxyExchange.
19+
*/
20+
@NullMarked
21+
package org.springframework.cloud.gateway.mvc;
22+
23+
import org.jspecify.annotations.NullMarked;

spring-cloud-gateway-proxyexchange-webmvc/src/test/java/org/springframework/cloud/gateway/mvc/http/GetWithBodyRequestClientHttpRequestFactory.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import org.apache.http.client.protocol.HttpClientContext;
3636
import org.apache.http.impl.client.HttpClients;
3737
import org.apache.http.protocol.HttpContext;
38+
import org.jspecify.annotations.Nullable;
3839

3940
import org.springframework.beans.factory.DisposableBean;
4041
import org.springframework.http.HttpMethod;
@@ -99,7 +100,7 @@ else if (httpMethod.equals(HttpMethod.TRACE)) {
99100
throw new IllegalArgumentException("Invalid HTTP method: " + httpMethod);
100101
}
101102

102-
private RequestConfig createRequestConfig(final HttpClient client) {
103+
private @Nullable RequestConfig createRequestConfig(final HttpClient client) {
103104
if (client instanceof Configurable) {
104105
return ((Configurable) client).getConfig();
105106
}

spring-cloud-gateway-proxyexchange-webmvc/src/test/java/org/springframework/cloud/gateway/mvc/http/HttpComponentsClientHttpResponse.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,19 +24,17 @@
2424
import org.apache.http.HttpEntity;
2525
import org.apache.http.HttpResponse;
2626
import org.apache.http.util.EntityUtils;
27+
import org.jspecify.annotations.Nullable;
2728

2829
import org.springframework.http.HttpHeaders;
2930
import org.springframework.http.HttpStatusCode;
3031
import org.springframework.http.client.ClientHttpResponse;
31-
import org.springframework.lang.Nullable;
32-
import org.springframework.util.StreamUtils;
3332

3433
final class HttpComponentsClientHttpResponse implements ClientHttpResponse {
3534

3635
private final HttpResponse response;
3736

38-
@Nullable
39-
private HttpHeaders headers;
37+
private @Nullable HttpHeaders headers;
4038

4139
HttpComponentsClientHttpResponse(final HttpResponse response) {
4240
this.response = response;
@@ -67,7 +65,7 @@ public HttpHeaders getHeaders() {
6765
@Override
6866
public InputStream getBody() throws IOException {
6967
final HttpEntity entity = response.getEntity();
70-
return entity != null ? entity.getContent() : StreamUtils.emptyInput();
68+
return entity != null ? entity.getContent() : InputStream.nullInputStream();
7169
}
7270

7371
@Override

0 commit comments

Comments
 (0)