Add nullability annotations to module/spring-boot-webclient

See gh-46587
This commit is contained in:
Moritz Halbritter 2025-08-06 14:11:39 +02:00
parent 544e7281d6
commit 840fc57d7a
9 changed files with 42 additions and 17 deletions

View File

@ -44,10 +44,10 @@ public final class ClientHttpConnectors {
private final ObjectFactory<SslBundles> sslBundles; private final ObjectFactory<SslBundles> sslBundles;
private final AbstractClientHttpConnectorProperties[] orderedProperties; private final @Nullable AbstractClientHttpConnectorProperties[] orderedProperties;
public ClientHttpConnectors(ObjectFactory<SslBundles> sslBundles, public ClientHttpConnectors(ObjectFactory<SslBundles> sslBundles,
AbstractClientHttpConnectorProperties... orderedProperties) { @Nullable AbstractClientHttpConnectorProperties... orderedProperties) {
this.sslBundles = sslBundles; this.sslBundles = sslBundles;
this.orderedProperties = orderedProperties; this.orderedProperties = orderedProperties;
} }

View File

@ -20,6 +20,8 @@ import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.jspecify.annotations.Nullable;
import org.springframework.boot.context.properties.NestedConfigurationProperty; import org.springframework.boot.context.properties.NestedConfigurationProperty;
import org.springframework.boot.http.client.autoconfigure.ApiversionProperties; import org.springframework.boot.http.client.autoconfigure.ApiversionProperties;
import org.springframework.boot.http.client.autoconfigure.reactive.AbstractClientHttpConnectorProperties; import org.springframework.boot.http.client.autoconfigure.reactive.AbstractClientHttpConnectorProperties;
@ -40,7 +42,7 @@ public abstract class AbstractWebClientProperties extends AbstractClientHttpConn
* Base url to set in the underlying HTTP client group. By default, set to * Base url to set in the underlying HTTP client group. By default, set to
* {@code null}. * {@code null}.
*/ */
private String baseUrl; private @Nullable String baseUrl;
/** /**
* Default request headers for interface client group. By default, set to empty * Default request headers for interface client group. By default, set to empty
@ -54,11 +56,11 @@ public abstract class AbstractWebClientProperties extends AbstractClientHttpConn
@NestedConfigurationProperty @NestedConfigurationProperty
private final ApiversionProperties apiversion = new ApiversionProperties(); private final ApiversionProperties apiversion = new ApiversionProperties();
public String getBaseUrl() { public @Nullable String getBaseUrl() {
return this.baseUrl; return this.baseUrl;
} }
public void setBaseUrl(String baseUrl) { public void setBaseUrl(@Nullable String baseUrl) {
this.baseUrl = baseUrl; this.baseUrl = baseUrl;
} }

View File

@ -21,6 +21,8 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Consumer; import java.util.function.Consumer;
import org.jspecify.annotations.Nullable;
import org.springframework.boot.context.properties.PropertyMapper; import org.springframework.boot.context.properties.PropertyMapper;
import org.springframework.boot.http.client.autoconfigure.ApiversionProperties; import org.springframework.boot.http.client.autoconfigure.ApiversionProperties;
import org.springframework.boot.http.client.autoconfigure.PropertiesApiVersionInserter; import org.springframework.boot.http.client.autoconfigure.PropertiesApiVersionInserter;
@ -29,6 +31,7 @@ import org.springframework.http.HttpHeaders;
import org.springframework.web.client.ApiVersionFormatter; import org.springframework.web.client.ApiVersionFormatter;
import org.springframework.web.client.ApiVersionInserter; import org.springframework.web.client.ApiVersionInserter;
import org.springframework.web.reactive.function.client.WebClient; import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.client.WebClient.Builder;
/** /**
* {@link WebClientCustomizer} to apply {@link AbstractWebClientProperties}. * {@link WebClientCustomizer} to apply {@link AbstractWebClientProperties}.
@ -38,18 +41,19 @@ import org.springframework.web.reactive.function.client.WebClient;
*/ */
public class PropertiesWebClientCustomizer implements WebClientCustomizer { public class PropertiesWebClientCustomizer implements WebClientCustomizer {
private final AbstractWebClientProperties[] orderedProperties; private final @Nullable AbstractWebClientProperties[] orderedProperties;
private ApiVersionInserter apiVersionInserter; private final @Nullable ApiVersionInserter apiVersionInserter;
public PropertiesWebClientCustomizer(ApiVersionInserter apiVersionInserter, ApiVersionFormatter apiVersionFormatter, public PropertiesWebClientCustomizer(@Nullable ApiVersionInserter apiVersionInserter,
AbstractWebClientProperties... orderedProperties) { @Nullable ApiVersionFormatter apiVersionFormatter,
@Nullable AbstractWebClientProperties... orderedProperties) {
this.orderedProperties = orderedProperties; this.orderedProperties = orderedProperties;
this.apiVersionInserter = PropertiesApiVersionInserter.get(apiVersionInserter, apiVersionFormatter, this.apiVersionInserter = PropertiesApiVersionInserter.get(apiVersionInserter, apiVersionFormatter,
Arrays.stream(orderedProperties).map(this::getApiVersion)); Arrays.stream(orderedProperties).map(this::getApiVersion));
} }
private ApiversionProperties getApiVersion(AbstractWebClientProperties properties) { private @Nullable ApiversionProperties getApiVersion(@Nullable AbstractWebClientProperties properties) {
return (properties != null) ? properties.getApiversion() : null; return (properties != null) ? properties.getApiversion() : null;
} }
@ -62,13 +66,16 @@ public class PropertiesWebClientCustomizer implements WebClientCustomizer {
if (properties != null) { if (properties != null) {
map.from(properties::getBaseUrl).whenHasText().to(builder::baseUrl); map.from(properties::getBaseUrl).whenHasText().to(builder::baseUrl);
map.from(properties::getDefaultHeader).as(this::putAllHeaders).to(builder::defaultHeaders); map.from(properties::getDefaultHeader).as(this::putAllHeaders).to(builder::defaultHeaders);
map.from(properties.getApiversion()) setDefaultApiVersion(builder, map, properties);
.as(ApiversionProperties::getDefaultVersion)
.to(builder::defaultApiVersion);
} }
} }
} }
@SuppressWarnings("NullAway") // Lambda isn't detected with the correct nullability
private void setDefaultApiVersion(Builder builder, PropertyMapper map, AbstractWebClientProperties properties) {
map.from(properties.getApiversion()).as(ApiversionProperties::getDefaultVersion).to(builder::defaultApiVersion);
}
private Consumer<HttpHeaders> putAllHeaders(Map<String, List<String>> defaultHeaders) { private Consumer<HttpHeaders> putAllHeaders(Map<String, List<String>> defaultHeaders) {
return (httpHeaders) -> httpHeaders.putAll(defaultHeaders); return (httpHeaders) -> httpHeaders.putAll(defaultHeaders);
} }

View File

@ -17,4 +17,7 @@
/** /**
* Auto-configuration for Spring Framework's functional web client. * Auto-configuration for Spring Framework's functional web client.
*/ */
@NullMarked
package org.springframework.boot.webclient.autoconfigure; package org.springframework.boot.webclient.autoconfigure;
import org.jspecify.annotations.NullMarked;

View File

@ -53,6 +53,7 @@ import org.springframework.web.service.registry.ImportHttpServices;
@EnableConfigurationProperties(ReactiveHttpClientServiceProperties.class) @EnableConfigurationProperties(ReactiveHttpClientServiceProperties.class)
public final class ReactiveHttpServiceClientAutoConfiguration implements BeanClassLoaderAware { public final class ReactiveHttpServiceClientAutoConfiguration implements BeanClassLoaderAware {
@SuppressWarnings("NullAway.Init")
private ClassLoader beanClassLoader; private ClassLoader beanClassLoader;
ReactiveHttpServiceClientAutoConfiguration() { ReactiveHttpServiceClientAutoConfiguration() {

View File

@ -16,6 +16,8 @@
package org.springframework.boot.webclient.autoconfigure.service; package org.springframework.boot.webclient.autoconfigure.service;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.http.client.autoconfigure.reactive.ClientHttpConnectors; import org.springframework.boot.http.client.autoconfigure.reactive.ClientHttpConnectors;
import org.springframework.boot.http.client.autoconfigure.reactive.HttpReactiveClientProperties; import org.springframework.boot.http.client.autoconfigure.reactive.HttpReactiveClientProperties;
@ -54,9 +56,9 @@ class WebClientPropertiesHttpServiceGroupConfigurer implements WebClientHttpServ
private final ObjectProvider<ClientHttpConnectorSettings> clientConnectorSettings; private final ObjectProvider<ClientHttpConnectorSettings> clientConnectorSettings;
private final ApiVersionInserter apiVersionInserter; private final @Nullable ApiVersionInserter apiVersionInserter;
private final ApiVersionFormatter apiVersionFormatter; private final @Nullable ApiVersionFormatter apiVersionFormatter;
WebClientPropertiesHttpServiceGroupConfigurer(ClassLoader classLoader, ObjectProvider<SslBundles> sslBundles, WebClientPropertiesHttpServiceGroupConfigurer(ClassLoader classLoader, ObjectProvider<SslBundles> sslBundles,
HttpReactiveClientProperties clientProperties, ReactiveHttpClientServiceProperties serviceProperties, HttpReactiveClientProperties clientProperties, ReactiveHttpClientServiceProperties serviceProperties,
@ -91,12 +93,13 @@ class WebClientPropertiesHttpServiceGroupConfigurer implements WebClientHttpServ
} }
private PropertiesWebClientCustomizer getPropertiesWebClientCustomizer( private PropertiesWebClientCustomizer getPropertiesWebClientCustomizer(
ReactiveHttpClientServiceProperties.Group groupProperties) { ReactiveHttpClientServiceProperties.@Nullable Group groupProperties) {
return new PropertiesWebClientCustomizer(this.apiVersionInserter, this.apiVersionFormatter, groupProperties, return new PropertiesWebClientCustomizer(this.apiVersionInserter, this.apiVersionFormatter, groupProperties,
this.serviceProperties); this.serviceProperties);
} }
private ClientHttpConnector getClientConnector(ReactiveHttpClientServiceProperties.Group groupProperties) { private ClientHttpConnector getClientConnector(
ReactiveHttpClientServiceProperties.@Nullable Group groupProperties) {
ClientHttpConnectors connectors = new ClientHttpConnectors(this.sslBundles, groupProperties, ClientHttpConnectors connectors = new ClientHttpConnectors(this.sslBundles, groupProperties,
this.serviceProperties, this.clientProperties); this.serviceProperties, this.clientProperties);
ClientHttpConnectorBuilder<?> builder = this.clientConnectorBuilder ClientHttpConnectorBuilder<?> builder = this.clientConnectorBuilder

View File

@ -17,4 +17,7 @@
/** /**
* Auto-Configuration for Spring's Reactive HTTP Service Interface Clients. * Auto-Configuration for Spring's Reactive HTTP Service Interface Clients.
*/ */
@NullMarked
package org.springframework.boot.webclient.autoconfigure.service; package org.springframework.boot.webclient.autoconfigure.service;
import org.jspecify.annotations.NullMarked;

View File

@ -17,4 +17,7 @@
/** /**
* Observation integration for WebClient. * Observation integration for WebClient.
*/ */
@NullMarked
package org.springframework.boot.webclient.observation; package org.springframework.boot.webclient.observation;
import org.jspecify.annotations.NullMarked;

View File

@ -17,4 +17,7 @@
/** /**
* Spring WebFlux WebClient support abstractions. * Spring WebFlux WebClient support abstractions.
*/ */
@NullMarked
package org.springframework.boot.webclient; package org.springframework.boot.webclient;
import org.jspecify.annotations.NullMarked;