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 AbstractClientHttpConnectorProperties[] orderedProperties;
private final @Nullable AbstractClientHttpConnectorProperties[] orderedProperties;
public ClientHttpConnectors(ObjectFactory<SslBundles> sslBundles,
AbstractClientHttpConnectorProperties... orderedProperties) {
@Nullable AbstractClientHttpConnectorProperties... orderedProperties) {
this.sslBundles = sslBundles;
this.orderedProperties = orderedProperties;
}

View File

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

View File

@ -21,6 +21,8 @@ import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import org.jspecify.annotations.Nullable;
import org.springframework.boot.context.properties.PropertyMapper;
import org.springframework.boot.http.client.autoconfigure.ApiversionProperties;
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.ApiVersionInserter;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.client.WebClient.Builder;
/**
* {@link WebClientCustomizer} to apply {@link AbstractWebClientProperties}.
@ -38,18 +41,19 @@ import org.springframework.web.reactive.function.client.WebClient;
*/
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,
AbstractWebClientProperties... orderedProperties) {
public PropertiesWebClientCustomizer(@Nullable ApiVersionInserter apiVersionInserter,
@Nullable ApiVersionFormatter apiVersionFormatter,
@Nullable AbstractWebClientProperties... orderedProperties) {
this.orderedProperties = orderedProperties;
this.apiVersionInserter = PropertiesApiVersionInserter.get(apiVersionInserter, apiVersionFormatter,
Arrays.stream(orderedProperties).map(this::getApiVersion));
}
private ApiversionProperties getApiVersion(AbstractWebClientProperties properties) {
private @Nullable ApiversionProperties getApiVersion(@Nullable AbstractWebClientProperties properties) {
return (properties != null) ? properties.getApiversion() : null;
}
@ -62,13 +66,16 @@ public class PropertiesWebClientCustomizer implements WebClientCustomizer {
if (properties != null) {
map.from(properties::getBaseUrl).whenHasText().to(builder::baseUrl);
map.from(properties::getDefaultHeader).as(this::putAllHeaders).to(builder::defaultHeaders);
map.from(properties.getApiversion())
.as(ApiversionProperties::getDefaultVersion)
.to(builder::defaultApiVersion);
setDefaultApiVersion(builder, map, properties);
}
}
}
@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) {
return (httpHeaders) -> httpHeaders.putAll(defaultHeaders);
}

View File

@ -17,4 +17,7 @@
/**
* Auto-configuration for Spring Framework's functional web client.
*/
@NullMarked
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)
public final class ReactiveHttpServiceClientAutoConfiguration implements BeanClassLoaderAware {
@SuppressWarnings("NullAway.Init")
private ClassLoader beanClassLoader;
ReactiveHttpServiceClientAutoConfiguration() {

View File

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

View File

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

View File

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

View File

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