Make URI template variables nullable

Closes gh-34221
This commit is contained in:
Sébastien Deleuze 2025-01-10 11:39:21 +01:00
parent bce7d87151
commit ec48c47886
33 changed files with 172 additions and 165 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2023 the original author or authors. * Copyright 2002-2025 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -119,7 +119,7 @@ public final class MockServerHttpRequest extends AbstractServerHttpRequest {
* @param uriVars zero or more URI variables * @param uriVars zero or more URI variables
* @return the created builder * @return the created builder
*/ */
public static BaseBuilder<?> get(String urlTemplate, Object... uriVars) { public static BaseBuilder<?> get(String urlTemplate, @Nullable Object... uriVars) {
return method(HttpMethod.GET, urlTemplate, uriVars); return method(HttpMethod.GET, urlTemplate, uriVars);
} }
@ -129,7 +129,7 @@ public final class MockServerHttpRequest extends AbstractServerHttpRequest {
* @param uriVars zero or more URI variables * @param uriVars zero or more URI variables
* @return the created builder * @return the created builder
*/ */
public static BaseBuilder<?> head(String urlTemplate, Object... uriVars) { public static BaseBuilder<?> head(String urlTemplate, @Nullable Object... uriVars) {
return method(HttpMethod.HEAD, urlTemplate, uriVars); return method(HttpMethod.HEAD, urlTemplate, uriVars);
} }
@ -139,7 +139,7 @@ public final class MockServerHttpRequest extends AbstractServerHttpRequest {
* @param uriVars zero or more URI variables * @param uriVars zero or more URI variables
* @return the created builder * @return the created builder
*/ */
public static BodyBuilder post(String urlTemplate, Object... uriVars) { public static BodyBuilder post(String urlTemplate, @Nullable Object... uriVars) {
return method(HttpMethod.POST, urlTemplate, uriVars); return method(HttpMethod.POST, urlTemplate, uriVars);
} }
@ -150,7 +150,7 @@ public final class MockServerHttpRequest extends AbstractServerHttpRequest {
* @param uriVars zero or more URI variables * @param uriVars zero or more URI variables
* @return the created builder * @return the created builder
*/ */
public static BodyBuilder put(String urlTemplate, Object... uriVars) { public static BodyBuilder put(String urlTemplate, @Nullable Object... uriVars) {
return method(HttpMethod.PUT, urlTemplate, uriVars); return method(HttpMethod.PUT, urlTemplate, uriVars);
} }
@ -160,7 +160,7 @@ public final class MockServerHttpRequest extends AbstractServerHttpRequest {
* @param uriVars zero or more URI variables * @param uriVars zero or more URI variables
* @return the created builder * @return the created builder
*/ */
public static BodyBuilder patch(String urlTemplate, Object... uriVars) { public static BodyBuilder patch(String urlTemplate, @Nullable Object... uriVars) {
return method(HttpMethod.PATCH, urlTemplate, uriVars); return method(HttpMethod.PATCH, urlTemplate, uriVars);
} }
@ -170,7 +170,7 @@ public final class MockServerHttpRequest extends AbstractServerHttpRequest {
* @param uriVars zero or more URI variables * @param uriVars zero or more URI variables
* @return the created builder * @return the created builder
*/ */
public static BaseBuilder<?> delete(String urlTemplate, Object... uriVars) { public static BaseBuilder<?> delete(String urlTemplate, @Nullable Object... uriVars) {
return method(HttpMethod.DELETE, urlTemplate, uriVars); return method(HttpMethod.DELETE, urlTemplate, uriVars);
} }
@ -180,7 +180,7 @@ public final class MockServerHttpRequest extends AbstractServerHttpRequest {
* @param uriVars zero or more URI variables * @param uriVars zero or more URI variables
* @return the created builder * @return the created builder
*/ */
public static BaseBuilder<?> options(String urlTemplate, Object... uriVars) { public static BaseBuilder<?> options(String urlTemplate, @Nullable Object... uriVars) {
return method(HttpMethod.OPTIONS, urlTemplate, uriVars); return method(HttpMethod.OPTIONS, urlTemplate, uriVars);
} }
@ -205,7 +205,7 @@ public final class MockServerHttpRequest extends AbstractServerHttpRequest {
* @param vars variables to expand into the template * @param vars variables to expand into the template
* @return the created builder * @return the created builder
*/ */
public static BodyBuilder method(HttpMethod method, String uri, Object... vars) { public static BodyBuilder method(HttpMethod method, String uri, @Nullable Object... vars) {
return method(method, toUri(uri, vars)); return method(method, toUri(uri, vars));
} }
@ -220,12 +220,12 @@ public final class MockServerHttpRequest extends AbstractServerHttpRequest {
* @deprecated as of Spring Framework 6.0 in favor of {@link #method(HttpMethod, String, Object...)} * @deprecated as of Spring Framework 6.0 in favor of {@link #method(HttpMethod, String, Object...)}
*/ */
@Deprecated(since = "6.0") @Deprecated(since = "6.0")
public static BodyBuilder method(String httpMethod, String uri, Object... vars) { public static BodyBuilder method(String httpMethod, String uri, @Nullable Object... vars) {
Assert.hasText(httpMethod, "HTTP method is required."); Assert.hasText(httpMethod, "HTTP method is required.");
return new DefaultBodyBuilder(HttpMethod.valueOf(httpMethod), toUri(uri, vars)); return new DefaultBodyBuilder(HttpMethod.valueOf(httpMethod), toUri(uri, vars));
} }
private static URI toUri(String uri, Object[] vars) { private static URI toUri(String uri, @Nullable Object[] vars) {
return UriComponentsBuilder.fromUriString(uri).buildAndExpand(vars).encode().toUri(); return UriComponentsBuilder.fromUriString(uri).buildAndExpand(vars).encode().toUri();
} }

View File

@ -56,7 +56,7 @@ public class UriAssert extends AbstractStringAssert<UriAssert> {
* @param uriVars the values to replace the URI template variables * @param uriVars the values to replace the URI template variables
* @see UriComponentsBuilder#buildAndExpand(Object...) * @see UriComponentsBuilder#buildAndExpand(Object...)
*/ */
public UriAssert isEqualToTemplate(String uriTemplate, Object... uriVars) { public UriAssert isEqualToTemplate(String uriTemplate, @Nullable Object... uriVars) {
String uri = buildUri(uriTemplate, uriVars); String uri = buildUri(uriTemplate, uriVars);
return isEqualTo(uri); return isEqualTo(uri);
} }
@ -81,7 +81,7 @@ public class UriAssert extends AbstractStringAssert<UriAssert> {
} }
private String buildUri(String uriTemplate, Object... uriVars) { private String buildUri(String uriTemplate, @Nullable Object... uriVars) {
try { try {
return UriComponentsBuilder.fromUriString(uriTemplate) return UriComponentsBuilder.fromUriString(uriTemplate)
.buildAndExpand(uriVars).encode().toUriString(); .buildAndExpand(uriVars).encode().toUriString();

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2023 the original author or authors. * Copyright 2002-2025 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -23,6 +23,7 @@ import java.util.Map;
import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathExpressionException;
import org.hamcrest.Matcher; import org.hamcrest.Matcher;
import org.jspecify.annotations.Nullable;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
@ -98,7 +99,7 @@ public abstract class MockRestRequestMatchers {
* @param uriVars zero or more URI variables to populate the expected URI * @param uriVars zero or more URI variables to populate the expected URI
* @return the request matcher * @return the request matcher
*/ */
public static RequestMatcher requestToUriTemplate(String expectedUri, Object... uriVars) { public static RequestMatcher requestToUriTemplate(String expectedUri, @Nullable Object... uriVars) {
Assert.notNull(expectedUri, "'uri' must not be null"); Assert.notNull(expectedUri, "'uri' must not be null");
URI uri = UriComponentsBuilder.fromUriString(expectedUri).buildAndExpand(uriVars).encode().toUri(); URI uri = UriComponentsBuilder.fromUriString(expectedUri).buildAndExpand(uriVars).encode().toUri();
return requestTo(uri); return requestTo(uri);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2024 the original author or authors. * Copyright 2002-2025 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -202,13 +202,13 @@ class DefaultWebTestClient implements WebTestClient {
} }
@Override @Override
public RequestBodySpec uri(String uriTemplate, Object... uriVariables) { public RequestBodySpec uri(String uriTemplate, @Nullable Object... uriVariables) {
this.uriTemplate = uriTemplate; this.uriTemplate = uriTemplate;
return uri(DefaultWebTestClient.this.uriBuilderFactory.expand(uriTemplate, uriVariables)); return uri(DefaultWebTestClient.this.uriBuilderFactory.expand(uriTemplate, uriVariables));
} }
@Override @Override
public RequestBodySpec uri(String uriTemplate, Map<String, ?> uriVariables) { public RequestBodySpec uri(String uriTemplate, Map<String, ? extends @Nullable Object> uriVariables) {
this.uriTemplate = uriTemplate; this.uriTemplate = uriTemplate;
return uri(DefaultWebTestClient.this.uriBuilderFactory.expand(uriTemplate, uriVariables)); return uri(DefaultWebTestClient.this.uriBuilderFactory.expand(uriTemplate, uriVariables));
} }

View File

@ -557,7 +557,7 @@ public interface WebTestClient {
* with a base URI) it will be used to expand the URI template. * with a base URI) it will be used to expand the URI template.
* @return spec to add headers or perform the exchange * @return spec to add headers or perform the exchange
*/ */
S uri(String uri, Object... uriVariables); S uri(String uri, @Nullable Object... uriVariables);
/** /**
* Specify the URI for the request using a URI template and URI variables. * Specify the URI for the request using a URI template and URI variables.
@ -565,7 +565,7 @@ public interface WebTestClient {
* with a base URI) it will be used to expand the URI template. * with a base URI) it will be used to expand the URI template.
* @return spec to add headers or perform the exchange * @return spec to add headers or perform the exchange
*/ */
S uri(String uri, Map<String, ?> uriVariables); S uri(String uri, Map<String, ? extends @Nullable Object> uriVariables);
/** /**
* Build the URI for the request with a {@link UriBuilder} obtained * Build the URI for the request with a {@link UriBuilder} obtained

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2024 the original author or authors. * Copyright 2002-2025 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -151,7 +151,7 @@ public abstract class AbstractMockHttpServletRequestBuilder<B extends AbstractMo
/** /**
* Specify the URI for the request using a URI template and URI variables. * Specify the URI for the request using a URI template and URI variables.
*/ */
public B uri(String uriTemplate, Object... uriVariables) { public B uri(String uriTemplate, @Nullable Object... uriVariables) {
return updateUri(initUri(uriTemplate, uriVariables), uriTemplate); return updateUri(initUri(uriTemplate, uriVariables), uriTemplate);
} }
@ -161,7 +161,7 @@ public abstract class AbstractMockHttpServletRequestBuilder<B extends AbstractMo
return self(); return self();
} }
private static URI initUri(String uri, Object[] vars) { private static URI initUri(String uri, @Nullable Object[] vars) {
Assert.notNull(uri, "'uri' must not be null"); Assert.notNull(uri, "'uri' must not be null");
Assert.isTrue(uri.isEmpty() || uri.startsWith("/") || uri.startsWith("http://") || uri.startsWith("https://"), Assert.isTrue(uri.isEmpty() || uri.startsWith("/") || uri.startsWith("http://") || uri.startsWith("https://"),
() -> "'uri' should start with a path or be a complete HTTP URI: " + uri); () -> "'uri' should start with a path or be a complete HTTP URI: " + uri);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2024 the original author or authors. * Copyright 2002-2025 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -75,7 +75,7 @@ public class MockHttpServletRequestBuilder
} }
@Override @Override
public MockHttpServletRequestBuilder uri(String uriTemplate, Object... uriVariables) { public MockHttpServletRequestBuilder uri(String uriTemplate, @Nullable Object... uriVariables) {
return super.uri(uriTemplate, uriVariables); return super.uri(uriTemplate, uriVariables);
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2024 the original author or authors. * Copyright 2002-2025 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -19,6 +19,7 @@ package org.springframework.test.web.servlet.request;
import java.net.URI; import java.net.URI;
import jakarta.servlet.DispatcherType; import jakarta.servlet.DispatcherType;
import org.jspecify.annotations.Nullable;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletRequest;
@ -52,7 +53,7 @@ public abstract class MockMvcRequestBuilders {
* @param uriTemplate a URI template; the resulting URI will be encoded * @param uriTemplate a URI template; the resulting URI will be encoded
* @param uriVariables zero or more URI variables * @param uriVariables zero or more URI variables
*/ */
public static MockHttpServletRequestBuilder get(String uriTemplate, Object... uriVariables) { public static MockHttpServletRequestBuilder get(String uriTemplate, @Nullable Object... uriVariables) {
return new MockHttpServletRequestBuilder(HttpMethod.GET).uri(uriTemplate, uriVariables); return new MockHttpServletRequestBuilder(HttpMethod.GET).uri(uriTemplate, uriVariables);
} }
@ -70,7 +71,7 @@ public abstract class MockMvcRequestBuilders {
* @param uriTemplate a URI template; the resulting URI will be encoded * @param uriTemplate a URI template; the resulting URI will be encoded
* @param uriVariables zero or more URI variables * @param uriVariables zero or more URI variables
*/ */
public static MockHttpServletRequestBuilder post(String uriTemplate, Object... uriVariables) { public static MockHttpServletRequestBuilder post(String uriTemplate, @Nullable Object... uriVariables) {
return new MockHttpServletRequestBuilder(HttpMethod.POST).uri(uriTemplate, uriVariables); return new MockHttpServletRequestBuilder(HttpMethod.POST).uri(uriTemplate, uriVariables);
} }
@ -88,7 +89,7 @@ public abstract class MockMvcRequestBuilders {
* @param uriTemplate a URI template; the resulting URI will be encoded * @param uriTemplate a URI template; the resulting URI will be encoded
* @param uriVariables zero or more URI variables * @param uriVariables zero or more URI variables
*/ */
public static MockHttpServletRequestBuilder put(String uriTemplate, Object... uriVariables) { public static MockHttpServletRequestBuilder put(String uriTemplate, @Nullable Object... uriVariables) {
return new MockHttpServletRequestBuilder(HttpMethod.PUT).uri(uriTemplate, uriVariables); return new MockHttpServletRequestBuilder(HttpMethod.PUT).uri(uriTemplate, uriVariables);
} }
@ -106,7 +107,7 @@ public abstract class MockMvcRequestBuilders {
* @param uriTemplate a URI template; the resulting URI will be encoded * @param uriTemplate a URI template; the resulting URI will be encoded
* @param uriVariables zero or more URI variables * @param uriVariables zero or more URI variables
*/ */
public static MockHttpServletRequestBuilder patch(String uriTemplate, Object... uriVariables) { public static MockHttpServletRequestBuilder patch(String uriTemplate,@Nullable Object... uriVariables) {
return new MockHttpServletRequestBuilder(HttpMethod.PATCH).uri(uriTemplate, uriVariables); return new MockHttpServletRequestBuilder(HttpMethod.PATCH).uri(uriTemplate, uriVariables);
} }
@ -124,7 +125,7 @@ public abstract class MockMvcRequestBuilders {
* @param uriTemplate a URI template; the resulting URI will be encoded * @param uriTemplate a URI template; the resulting URI will be encoded
* @param uriVariables zero or more URI variables * @param uriVariables zero or more URI variables
*/ */
public static MockHttpServletRequestBuilder delete(String uriTemplate, Object... uriVariables) { public static MockHttpServletRequestBuilder delete(String uriTemplate, @Nullable Object... uriVariables) {
return new MockHttpServletRequestBuilder(HttpMethod.DELETE).uri(uriTemplate, uriVariables); return new MockHttpServletRequestBuilder(HttpMethod.DELETE).uri(uriTemplate, uriVariables);
} }
@ -142,7 +143,7 @@ public abstract class MockMvcRequestBuilders {
* @param uriTemplate a URI template; the resulting URI will be encoded * @param uriTemplate a URI template; the resulting URI will be encoded
* @param uriVariables zero or more URI variables * @param uriVariables zero or more URI variables
*/ */
public static MockHttpServletRequestBuilder options(String uriTemplate, Object... uriVariables) { public static MockHttpServletRequestBuilder options(String uriTemplate, @Nullable Object... uriVariables) {
return new MockHttpServletRequestBuilder(HttpMethod.OPTIONS).uri(uriTemplate, uriVariables); return new MockHttpServletRequestBuilder(HttpMethod.OPTIONS).uri(uriTemplate, uriVariables);
} }
@ -161,7 +162,7 @@ public abstract class MockMvcRequestBuilders {
* @param uriVariables zero or more URI variables * @param uriVariables zero or more URI variables
* @since 4.1 * @since 4.1
*/ */
public static MockHttpServletRequestBuilder head(String uriTemplate, Object... uriVariables) { public static MockHttpServletRequestBuilder head(String uriTemplate, @Nullable Object... uriVariables) {
return new MockHttpServletRequestBuilder(HttpMethod.HEAD).uri(uriTemplate, uriVariables); return new MockHttpServletRequestBuilder(HttpMethod.HEAD).uri(uriTemplate, uriVariables);
} }
@ -180,7 +181,7 @@ public abstract class MockMvcRequestBuilders {
* @param uriTemplate a URI template; the resulting URI will be encoded * @param uriTemplate a URI template; the resulting URI will be encoded
* @param uriVariables zero or more URI variables * @param uriVariables zero or more URI variables
*/ */
public static MockHttpServletRequestBuilder request(HttpMethod method, String uriTemplate, Object... uriVariables) { public static MockHttpServletRequestBuilder request(HttpMethod method, String uriTemplate, @Nullable Object... uriVariables) {
return new MockHttpServletRequestBuilder(method).uri(uriTemplate, uriVariables); return new MockHttpServletRequestBuilder(method).uri(uriTemplate, uriVariables);
} }
@ -213,7 +214,7 @@ public abstract class MockMvcRequestBuilders {
* @param uriVariables zero or more URI variables * @param uriVariables zero or more URI variables
* @since 5.0 * @since 5.0
*/ */
public static MockMultipartHttpServletRequestBuilder multipart(String uriTemplate, Object... uriVariables) { public static MockMultipartHttpServletRequestBuilder multipart(String uriTemplate, @Nullable Object... uriVariables) {
MockMultipartHttpServletRequestBuilder builder = new MockMultipartHttpServletRequestBuilder(); MockMultipartHttpServletRequestBuilder builder = new MockMultipartHttpServletRequestBuilder();
builder.uri(uriTemplate, uriVariables); builder.uri(uriTemplate, uriVariables);
return builder; return builder;
@ -227,7 +228,7 @@ public abstract class MockMvcRequestBuilders {
* @param uriVariables zero or more URI variables * @param uriVariables zero or more URI variables
* @since 5.3.22 * @since 5.3.22
*/ */
public static MockMultipartHttpServletRequestBuilder multipart(HttpMethod httpMethod, String uriTemplate, Object... uriVariables) { public static MockMultipartHttpServletRequestBuilder multipart(HttpMethod httpMethod, String uriTemplate, @Nullable Object... uriVariables) {
MockMultipartHttpServletRequestBuilder builder = new MockMultipartHttpServletRequestBuilder(httpMethod); MockMultipartHttpServletRequestBuilder builder = new MockMultipartHttpServletRequestBuilder(httpMethod);
builder.uri(uriTemplate, uriVariables); builder.uri(uriTemplate, uriVariables);
return builder; return builder;

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2020 the original author or authors. * Copyright 2002-2025 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -98,7 +98,7 @@ public abstract class MockMvcResultMatchers {
* @param uriVars zero or more URI variables to populate the template * @param uriVars zero or more URI variables to populate the template
* @see UriComponentsBuilder#fromUriString(String) * @see UriComponentsBuilder#fromUriString(String)
*/ */
public static ResultMatcher forwardedUrlTemplate(String urlTemplate, Object... uriVars) { public static ResultMatcher forwardedUrlTemplate(String urlTemplate, @Nullable Object... uriVars) {
String uri = UriComponentsBuilder.fromUriString(urlTemplate).buildAndExpand(uriVars).encode().toUriString(); String uri = UriComponentsBuilder.fromUriString(urlTemplate).buildAndExpand(uriVars).encode().toUriString();
return forwardedUrl(uri); return forwardedUrl(uri);
} }
@ -137,7 +137,7 @@ public abstract class MockMvcResultMatchers {
* @param uriVars zero or more URI variables to populate the template * @param uriVars zero or more URI variables to populate the template
* @see UriComponentsBuilder#fromUriString(String) * @see UriComponentsBuilder#fromUriString(String)
*/ */
public static ResultMatcher redirectedUrlTemplate(String urlTemplate, Object... uriVars) { public static ResultMatcher redirectedUrlTemplate(String urlTemplate, @Nullable Object... uriVars) {
String uri = UriComponentsBuilder.fromUriString(urlTemplate).buildAndExpand(uriVars).encode().toUriString(); String uri = UriComponentsBuilder.fromUriString(urlTemplate).buildAndExpand(uriVars).encode().toUriString();
return redirectedUrl(uri); return redirectedUrl(uri);
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2022 the original author or authors. * Copyright 2002-2025 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -304,7 +304,7 @@ public class RequestEntity<T> extends HttpEntity<T> {
* @return the created builder * @return the created builder
* @since 5.3 * @since 5.3
*/ */
public static BodyBuilder method(HttpMethod method, String uriTemplate, Object... uriVariables) { public static BodyBuilder method(HttpMethod method, String uriTemplate, @Nullable Object... uriVariables) {
return new DefaultBodyBuilder(method, uriTemplate, uriVariables); return new DefaultBodyBuilder(method, uriTemplate, uriVariables);
} }
@ -336,7 +336,7 @@ public class RequestEntity<T> extends HttpEntity<T> {
* @return the created builder * @return the created builder
* @since 5.3 * @since 5.3
*/ */
public static HeadersBuilder<?> get(String uriTemplate, Object... uriVariables) { public static HeadersBuilder<?> get(String uriTemplate, @Nullable Object... uriVariables) {
return method(HttpMethod.GET, uriTemplate, uriVariables); return method(HttpMethod.GET, uriTemplate, uriVariables);
} }
@ -356,7 +356,7 @@ public class RequestEntity<T> extends HttpEntity<T> {
* @return the created builder * @return the created builder
* @since 5.3 * @since 5.3
*/ */
public static HeadersBuilder<?> head(String uriTemplate, Object... uriVariables) { public static HeadersBuilder<?> head(String uriTemplate, @Nullable Object... uriVariables) {
return method(HttpMethod.HEAD, uriTemplate, uriVariables); return method(HttpMethod.HEAD, uriTemplate, uriVariables);
} }
@ -376,7 +376,7 @@ public class RequestEntity<T> extends HttpEntity<T> {
* @return the created builder * @return the created builder
* @since 5.3 * @since 5.3
*/ */
public static BodyBuilder post(String uriTemplate, Object... uriVariables) { public static BodyBuilder post(String uriTemplate, @Nullable Object... uriVariables) {
return method(HttpMethod.POST, uriTemplate, uriVariables); return method(HttpMethod.POST, uriTemplate, uriVariables);
} }
@ -396,7 +396,7 @@ public class RequestEntity<T> extends HttpEntity<T> {
* @return the created builder * @return the created builder
* @since 5.3 * @since 5.3
*/ */
public static BodyBuilder put(String uriTemplate, Object... uriVariables) { public static BodyBuilder put(String uriTemplate, @Nullable Object... uriVariables) {
return method(HttpMethod.PUT, uriTemplate, uriVariables); return method(HttpMethod.PUT, uriTemplate, uriVariables);
} }
@ -416,7 +416,7 @@ public class RequestEntity<T> extends HttpEntity<T> {
* @return the created builder * @return the created builder
* @since 5.3 * @since 5.3
*/ */
public static BodyBuilder patch(String uriTemplate, Object... uriVariables) { public static BodyBuilder patch(String uriTemplate, @Nullable Object... uriVariables) {
return method(HttpMethod.PATCH, uriTemplate, uriVariables); return method(HttpMethod.PATCH, uriTemplate, uriVariables);
} }
@ -436,7 +436,7 @@ public class RequestEntity<T> extends HttpEntity<T> {
* @return the created builder * @return the created builder
* @since 5.3 * @since 5.3
*/ */
public static HeadersBuilder<?> delete(String uriTemplate, Object... uriVariables) { public static HeadersBuilder<?> delete(String uriTemplate, @Nullable Object... uriVariables) {
return method(HttpMethod.DELETE, uriTemplate, uriVariables); return method(HttpMethod.DELETE, uriTemplate, uriVariables);
} }
@ -456,7 +456,7 @@ public class RequestEntity<T> extends HttpEntity<T> {
* @return the created builder * @return the created builder
* @since 5.3 * @since 5.3
*/ */
public static HeadersBuilder<?> options(String uriTemplate, Object... uriVariables) { public static HeadersBuilder<?> options(String uriTemplate, @Nullable Object... uriVariables) {
return method(HttpMethod.OPTIONS, uriTemplate, uriVariables); return method(HttpMethod.OPTIONS, uriTemplate, uriVariables);
} }
@ -601,9 +601,9 @@ public class RequestEntity<T> extends HttpEntity<T> {
private final @Nullable String uriTemplate; private final @Nullable String uriTemplate;
private final Object @Nullable [] uriVarsArray; private final @Nullable Object @Nullable [] uriVarsArray;
private final @Nullable Map<String, ?> uriVarsMap; private final @Nullable Map<String, ? extends @Nullable Object> uriVarsMap;
DefaultBodyBuilder(HttpMethod method, URI url) { DefaultBodyBuilder(HttpMethod method, URI url) {
this.method = method; this.method = method;
@ -613,7 +613,7 @@ public class RequestEntity<T> extends HttpEntity<T> {
this.uriVarsMap = null; this.uriVarsMap = null;
} }
DefaultBodyBuilder(HttpMethod method, String uriTemplate, Object... uriVars) { DefaultBodyBuilder(HttpMethod method, String uriTemplate, @Nullable Object... uriVars) {
this.method = method; this.method = method;
this.uri = null; this.uri = null;
this.uriTemplate = uriTemplate; this.uriTemplate = uriTemplate;
@ -621,7 +621,7 @@ public class RequestEntity<T> extends HttpEntity<T> {
this.uriVarsMap = null; this.uriVarsMap = null;
} }
DefaultBodyBuilder(HttpMethod method, String uriTemplate, Map<String, ?> uriVars) { DefaultBodyBuilder(HttpMethod method, String uriTemplate, Map<String, ? extends @Nullable Object> uriVars) {
this.method = method; this.method = method;
this.uri = null; this.uri = null;
this.uriTemplate = uriTemplate; this.uriTemplate = uriTemplate;

View File

@ -305,7 +305,7 @@ final class DefaultRestClient implements RestClient {
} }
@Override @Override
public RequestBodySpec uri(String uriTemplate, Object... uriVariables) { public RequestBodySpec uri(String uriTemplate, @Nullable Object... uriVariables) {
UriBuilder uriBuilder = uriBuilderFactory.uriString(uriTemplate); UriBuilder uriBuilder = uriBuilderFactory.uriString(uriTemplate);
attribute(URI_TEMPLATE_ATTRIBUTE, uriBuilder.toUriString()); attribute(URI_TEMPLATE_ATTRIBUTE, uriBuilder.toUriString());
return uri(DefaultRestClient.this.uriBuilderFactory.expand(uriTemplate, uriVariables)); return uri(DefaultRestClient.this.uriBuilderFactory.expand(uriTemplate, uriVariables));

View File

@ -503,14 +503,14 @@ public interface RestClient {
* <p>If a {@link UriBuilderFactory} was configured for the client (for example, * <p>If a {@link UriBuilderFactory} was configured for the client (for example,
* with a base URI) it will be used to expand the URI template. * with a base URI) it will be used to expand the URI template.
*/ */
S uri(String uri, Object... uriVariables); S uri(String uri, @Nullable Object... uriVariables);
/** /**
* Specify the URI for the request using a URI template and URI variables. * Specify the URI for the request using a URI template and URI variables.
* <p>If a {@link UriBuilderFactory} was configured for the client (for example, * <p>If a {@link UriBuilderFactory} was configured for the client (for example,
* with a base URI) it will be used to expand the URI template. * with a base URI) it will be used to expand the URI template.
*/ */
S uri(String uri, Map<String, ?> uriVariables); S uri(String uri, Map<String, ? extends @Nullable Object> uriVariables);
/** /**
* Specify the URI starting with a URI template and finishing off with a * Specify the URI starting with a URI template and finishing off with a

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2024 the original author or authors. * Copyright 2002-2025 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -53,7 +53,7 @@ public interface RestOperations {
* @param uriVariables the variables to expand the template * @param uriVariables the variables to expand the template
* @return the converted object * @return the converted object
*/ */
<T> @Nullable T getForObject(String url, Class<T> responseType, Object... uriVariables) throws RestClientException; <T> @Nullable T getForObject(String url, Class<T> responseType, @Nullable Object... uriVariables) throws RestClientException;
/** /**
* Retrieve a representation by doing a GET on the URI template. * Retrieve a representation by doing a GET on the URI template.
@ -64,7 +64,7 @@ public interface RestOperations {
* @param uriVariables the map containing variables for the URI template * @param uriVariables the map containing variables for the URI template
* @return the converted object * @return the converted object
*/ */
<T> @Nullable T getForObject(String url, Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException; <T> @Nullable T getForObject(String url, Class<T> responseType, Map<String, ? extends @Nullable Object> uriVariables) throws RestClientException;
/** /**
* Retrieve a representation by doing a GET on the URL. * Retrieve a representation by doing a GET on the URL.
@ -85,7 +85,7 @@ public interface RestOperations {
* @return the entity * @return the entity
* @since 3.0.2 * @since 3.0.2
*/ */
<T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... uriVariables) <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, @Nullable Object... uriVariables)
throws RestClientException; throws RestClientException;
/** /**
@ -98,7 +98,7 @@ public interface RestOperations {
* @return the converted object * @return the converted object
* @since 3.0.2 * @since 3.0.2
*/ */
<T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Map<String, ?> uriVariables) <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Map<String, ? extends @Nullable Object> uriVariables)
throws RestClientException; throws RestClientException;
/** /**
@ -121,7 +121,7 @@ public interface RestOperations {
* @param uriVariables the variables to expand the template * @param uriVariables the variables to expand the template
* @return all HTTP headers of that resource * @return all HTTP headers of that resource
*/ */
HttpHeaders headForHeaders(String url, Object... uriVariables) throws RestClientException; HttpHeaders headForHeaders(String url, @Nullable Object... uriVariables) throws RestClientException;
/** /**
* Retrieve all headers of the resource specified by the URI template. * Retrieve all headers of the resource specified by the URI template.
@ -130,7 +130,7 @@ public interface RestOperations {
* @param uriVariables the map containing variables for the URI template * @param uriVariables the map containing variables for the URI template
* @return all HTTP headers of that resource * @return all HTTP headers of that resource
*/ */
HttpHeaders headForHeaders(String url, Map<String, ?> uriVariables) throws RestClientException; HttpHeaders headForHeaders(String url, Map<String, ? extends @Nullable Object> uriVariables) throws RestClientException;
/** /**
* Retrieve all headers of the resource specified by the URL. * Retrieve all headers of the resource specified by the URL.
@ -159,7 +159,7 @@ public interface RestOperations {
* @return the value for the {@code Location} header * @return the value for the {@code Location} header
* @see HttpEntity * @see HttpEntity
*/ */
@Nullable URI postForLocation(String url, @Nullable Object request, Object... uriVariables) throws RestClientException; @Nullable URI postForLocation(String url, @Nullable Object request, @Nullable Object... uriVariables) throws RestClientException;
/** /**
* Create a new resource by POSTing the given object to the URI template, and return the value of * Create a new resource by POSTing the given object to the URI template, and return the value of
@ -178,7 +178,7 @@ public interface RestOperations {
* @return the value for the {@code Location} header * @return the value for the {@code Location} header
* @see HttpEntity * @see HttpEntity
*/ */
@Nullable URI postForLocation(String url, @Nullable Object request, Map<String, ?> uriVariables) @Nullable URI postForLocation(String url, @Nullable Object request, Map<String, ? extends @Nullable Object> uriVariables)
throws RestClientException; throws RestClientException;
/** /**
@ -217,7 +217,7 @@ public interface RestOperations {
* @see HttpEntity * @see HttpEntity
*/ */
<T> @Nullable T postForObject(String url, @Nullable Object request, Class<T> responseType, <T> @Nullable T postForObject(String url, @Nullable Object request, Class<T> responseType,
Object... uriVariables) throws RestClientException; @Nullable Object... uriVariables) throws RestClientException;
/** /**
* Create a new resource by POSTing the given object to the URI template, * Create a new resource by POSTing the given object to the URI template,
@ -238,7 +238,7 @@ public interface RestOperations {
* @see HttpEntity * @see HttpEntity
*/ */
<T> @Nullable T postForObject(String url, @Nullable Object request, Class<T> responseType, <T> @Nullable T postForObject(String url, @Nullable Object request, Class<T> responseType,
Map<String, ?> uriVariables) throws RestClientException; Map<String, ? extends @Nullable Object> uriVariables) throws RestClientException;
/** /**
* Create a new resource by POSTing the given object to the URL, * Create a new resource by POSTing the given object to the URL,
@ -277,7 +277,7 @@ public interface RestOperations {
* @see HttpEntity * @see HttpEntity
*/ */
<T> ResponseEntity<T> postForEntity(String url, @Nullable Object request, Class<T> responseType, <T> ResponseEntity<T> postForEntity(String url, @Nullable Object request, Class<T> responseType,
Object... uriVariables) throws RestClientException; @Nullable Object... uriVariables) throws RestClientException;
/** /**
* Create a new resource by POSTing the given object to the URI template, * Create a new resource by POSTing the given object to the URI template,
@ -298,7 +298,7 @@ public interface RestOperations {
* @see HttpEntity * @see HttpEntity
*/ */
<T> ResponseEntity<T> postForEntity(String url, @Nullable Object request, Class<T> responseType, <T> ResponseEntity<T> postForEntity(String url, @Nullable Object request, Class<T> responseType,
Map<String, ?> uriVariables) throws RestClientException; Map<String, ? extends @Nullable Object> uriVariables) throws RestClientException;
/** /**
* Create a new resource by POSTing the given object to the URL, * Create a new resource by POSTing the given object to the URL,
@ -332,7 +332,7 @@ public interface RestOperations {
* @param uriVariables the variables to expand the template * @param uriVariables the variables to expand the template
* @see HttpEntity * @see HttpEntity
*/ */
void put(String url, @Nullable Object request, Object... uriVariables) throws RestClientException; void put(String url, @Nullable Object request, @Nullable Object... uriVariables) throws RestClientException;
/** /**
* Creates a new resource by PUTting the given object to URI template. * Creates a new resource by PUTting the given object to URI template.
@ -344,7 +344,7 @@ public interface RestOperations {
* @param uriVariables the variables to expand the template * @param uriVariables the variables to expand the template
* @see HttpEntity * @see HttpEntity
*/ */
void put(String url, @Nullable Object request, Map<String, ?> uriVariables) throws RestClientException; void put(String url, @Nullable Object request, Map<String, ? extends @Nullable Object> uriVariables) throws RestClientException;
/** /**
* Creates a new resource by PUTting the given object to URL. * Creates a new resource by PUTting the given object to URL.
@ -377,7 +377,7 @@ public interface RestOperations {
* @see RestTemplate#setRequestFactory * @see RestTemplate#setRequestFactory
* @see org.springframework.http.client.HttpComponentsClientHttpRequestFactory * @see org.springframework.http.client.HttpComponentsClientHttpRequestFactory
*/ */
<T> @Nullable T patchForObject(String url, @Nullable Object request, Class<T> responseType, Object... uriVariables) <T> @Nullable T patchForObject(String url, @Nullable Object request, Class<T> responseType, @Nullable Object... uriVariables)
throws RestClientException; throws RestClientException;
/** /**
@ -399,7 +399,7 @@ public interface RestOperations {
* @see org.springframework.http.client.HttpComponentsClientHttpRequestFactory * @see org.springframework.http.client.HttpComponentsClientHttpRequestFactory
*/ */
<T> @Nullable T patchForObject(String url, @Nullable Object request, Class<T> responseType, <T> @Nullable T patchForObject(String url, @Nullable Object request, Class<T> responseType,
Map<String, ?> uriVariables) throws RestClientException; Map<String, ? extends @Nullable Object> uriVariables) throws RestClientException;
/** /**
* Update a resource by PATCHing the given object to the URL, * Update a resource by PATCHing the given object to the URL,
@ -430,7 +430,7 @@ public interface RestOperations {
* @param url the URL * @param url the URL
* @param uriVariables the variables to expand in the template * @param uriVariables the variables to expand in the template
*/ */
void delete(String url, Object... uriVariables) throws RestClientException; void delete(String url, @Nullable Object... uriVariables) throws RestClientException;
/** /**
* Delete the resources at the specified URI. * Delete the resources at the specified URI.
@ -438,7 +438,7 @@ public interface RestOperations {
* @param url the URL * @param url the URL
* @param uriVariables the variables to expand the template * @param uriVariables the variables to expand the template
*/ */
void delete(String url, Map<String, ?> uriVariables) throws RestClientException; void delete(String url, Map<String, ? extends @Nullable Object> uriVariables) throws RestClientException;
/** /**
* Delete the resources at the specified URL. * Delete the resources at the specified URL.
@ -456,7 +456,7 @@ public interface RestOperations {
* @param uriVariables the variables to expand in the template * @param uriVariables the variables to expand in the template
* @return the value of the {@code Allow} header * @return the value of the {@code Allow} header
*/ */
Set<HttpMethod> optionsForAllow(String url, Object... uriVariables) throws RestClientException; Set<HttpMethod> optionsForAllow(String url, @Nullable Object... uriVariables) throws RestClientException;
/** /**
* Return the value of the {@code Allow} header for the given URI. * Return the value of the {@code Allow} header for the given URI.
@ -465,7 +465,7 @@ public interface RestOperations {
* @param uriVariables the variables to expand in the template * @param uriVariables the variables to expand in the template
* @return the value of the {@code Allow} header * @return the value of the {@code Allow} header
*/ */
Set<HttpMethod> optionsForAllow(String url, Map<String, ?> uriVariables) throws RestClientException; Set<HttpMethod> optionsForAllow(String url, Map<String, ? extends @Nullable Object> uriVariables) throws RestClientException;
/** /**
* Return the value of the {@code Allow} header for the given URL. * Return the value of the {@code Allow} header for the given URL.
@ -491,7 +491,7 @@ public interface RestOperations {
* @since 3.0.2 * @since 3.0.2
*/ */
<T> ResponseEntity<T> exchange(String url, HttpMethod method, @Nullable HttpEntity<?> requestEntity, <T> ResponseEntity<T> exchange(String url, HttpMethod method, @Nullable HttpEntity<?> requestEntity,
Class<T> responseType, Object... uriVariables) throws RestClientException; Class<T> responseType, @Nullable Object... uriVariables) throws RestClientException;
/** /**
* Execute the HTTP method to the given URI template, writing the given request entity to the request, * Execute the HTTP method to the given URI template, writing the given request entity to the request,
@ -507,7 +507,7 @@ public interface RestOperations {
* @since 3.0.2 * @since 3.0.2
*/ */
<T> ResponseEntity<T> exchange(String url, HttpMethod method, @Nullable HttpEntity<?> requestEntity, <T> ResponseEntity<T> exchange(String url, HttpMethod method, @Nullable HttpEntity<?> requestEntity,
Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException; Class<T> responseType, Map<String, ? extends @Nullable Object> uriVariables) throws RestClientException;
/** /**
* Execute the HTTP method to the given URI template, writing the given request entity to the request, * Execute the HTTP method to the given URI template, writing the given request entity to the request,
@ -544,7 +544,7 @@ public interface RestOperations {
* @since 3.2 * @since 3.2
*/ */
<T> ResponseEntity<T> exchange(String url,HttpMethod method, @Nullable HttpEntity<?> requestEntity, <T> ResponseEntity<T> exchange(String url,HttpMethod method, @Nullable HttpEntity<?> requestEntity,
ParameterizedTypeReference<T> responseType, Object... uriVariables) throws RestClientException; ParameterizedTypeReference<T> responseType, @Nullable Object... uriVariables) throws RestClientException;
/** /**
* Execute the HTTP method to the given URI template, writing the given * Execute the HTTP method to the given URI template, writing the given
@ -567,7 +567,7 @@ public interface RestOperations {
* @since 3.2 * @since 3.2
*/ */
<T> ResponseEntity<T> exchange(String url, HttpMethod method, @Nullable HttpEntity<?> requestEntity, <T> ResponseEntity<T> exchange(String url, HttpMethod method, @Nullable HttpEntity<?> requestEntity,
ParameterizedTypeReference<T> responseType, Map<String, ?> uriVariables) throws RestClientException; ParameterizedTypeReference<T> responseType, Map<String, ? extends @Nullable Object> uriVariables) throws RestClientException;
/** /**
* Execute the HTTP method to the given URI template, writing the given * Execute the HTTP method to the given URI template, writing the given
@ -648,7 +648,7 @@ public interface RestOperations {
* @return an arbitrary object, as returned by the {@link ResponseExtractor} * @return an arbitrary object, as returned by the {@link ResponseExtractor}
*/ */
<T> @Nullable T execute(String uriTemplate, HttpMethod method, @Nullable RequestCallback requestCallback, <T> @Nullable T execute(String uriTemplate, HttpMethod method, @Nullable RequestCallback requestCallback,
@Nullable ResponseExtractor<T> responseExtractor, Object... uriVariables) @Nullable ResponseExtractor<T> responseExtractor, @Nullable Object... uriVariables)
throws RestClientException; throws RestClientException;
/** /**
@ -663,7 +663,7 @@ public interface RestOperations {
* @return an arbitrary object, as returned by the {@link ResponseExtractor} * @return an arbitrary object, as returned by the {@link ResponseExtractor}
*/ */
<T> @Nullable T execute(String uriTemplate, HttpMethod method, @Nullable RequestCallback requestCallback, <T> @Nullable T execute(String uriTemplate, HttpMethod method, @Nullable RequestCallback requestCallback,
@Nullable ResponseExtractor<T> responseExtractor, Map<String, ?> uriVariables) @Nullable ResponseExtractor<T> responseExtractor, Map<String, ? extends @Nullable Object> uriVariables)
throws RestClientException; throws RestClientException;
/** /**

View File

@ -330,7 +330,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
* @param uriVars the default URI variable values * @param uriVars the default URI variable values
* @since 4.3 * @since 4.3
*/ */
public void setDefaultUriVariables(Map<String, ?> uriVars) { public void setDefaultUriVariables(Map<String, ? extends @Nullable Object> uriVars) {
if (this.uriTemplateHandler instanceof DefaultUriBuilderFactory factory) { if (this.uriTemplateHandler instanceof DefaultUriBuilderFactory factory) {
factory.setDefaultUriVariables(uriVars); factory.setDefaultUriVariables(uriVars);
} }
@ -405,7 +405,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
// GET // GET
@Override @Override
public <T> @Nullable T getForObject(String url, Class<T> responseType, Object... uriVariables) throws RestClientException { public <T> @Nullable T getForObject(String url, Class<T> responseType, @Nullable Object... uriVariables) throws RestClientException {
RequestCallback requestCallback = acceptHeaderRequestCallback(responseType); RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
HttpMessageConverterExtractor<T> responseExtractor = HttpMessageConverterExtractor<T> responseExtractor =
new HttpMessageConverterExtractor<>(responseType, getMessageConverters(), logger); new HttpMessageConverterExtractor<>(responseType, getMessageConverters(), logger);
@ -429,7 +429,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
} }
@Override @Override
public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... uriVariables) public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, @Nullable Object... uriVariables)
throws RestClientException { throws RestClientException {
RequestCallback requestCallback = acceptHeaderRequestCallback(responseType); RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
@ -438,7 +438,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
} }
@Override @Override
public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Map<String, ?> uriVariables) public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Map<String, ? extends @Nullable Object> uriVariables)
throws RestClientException { throws RestClientException {
RequestCallback requestCallback = acceptHeaderRequestCallback(responseType); RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
@ -457,12 +457,12 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
// HEAD // HEAD
@Override @Override
public HttpHeaders headForHeaders(String url, Object... uriVariables) throws RestClientException { public HttpHeaders headForHeaders(String url, @Nullable Object... uriVariables) throws RestClientException {
return nonNull(execute(url, HttpMethod.HEAD, null, headersExtractor(), uriVariables)); return nonNull(execute(url, HttpMethod.HEAD, null, headersExtractor(), uriVariables));
} }
@Override @Override
public HttpHeaders headForHeaders(String url, Map<String, ?> uriVariables) throws RestClientException { public HttpHeaders headForHeaders(String url, Map<String, ? extends @Nullable Object> uriVariables) throws RestClientException {
return nonNull(execute(url, HttpMethod.HEAD, null, headersExtractor(), uriVariables)); return nonNull(execute(url, HttpMethod.HEAD, null, headersExtractor(), uriVariables));
} }
@ -475,7 +475,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
// POST // POST
@Override @Override
public @Nullable URI postForLocation(String url, @Nullable Object request, Object... uriVariables) public @Nullable URI postForLocation(String url, @Nullable Object request, @Nullable Object... uriVariables)
throws RestClientException { throws RestClientException {
RequestCallback requestCallback = httpEntityCallback(request); RequestCallback requestCallback = httpEntityCallback(request);
@ -484,7 +484,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
} }
@Override @Override
public @Nullable URI postForLocation(String url, @Nullable Object request, Map<String, ?> uriVariables) public @Nullable URI postForLocation(String url, @Nullable Object request, Map<String, ? extends @Nullable Object> uriVariables)
throws RestClientException { throws RestClientException {
RequestCallback requestCallback = httpEntityCallback(request); RequestCallback requestCallback = httpEntityCallback(request);
@ -501,7 +501,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
@Override @Override
public <T> @Nullable T postForObject(String url, @Nullable Object request, Class<T> responseType, public <T> @Nullable T postForObject(String url, @Nullable Object request, Class<T> responseType,
Object... uriVariables) throws RestClientException { @Nullable Object... uriVariables) throws RestClientException {
RequestCallback requestCallback = httpEntityCallback(request, responseType); RequestCallback requestCallback = httpEntityCallback(request, responseType);
HttpMessageConverterExtractor<T> responseExtractor = HttpMessageConverterExtractor<T> responseExtractor =
@ -511,7 +511,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
@Override @Override
public <T> @Nullable T postForObject(String url, @Nullable Object request, Class<T> responseType, public <T> @Nullable T postForObject(String url, @Nullable Object request, Class<T> responseType,
Map<String, ?> uriVariables) throws RestClientException { Map<String, ? extends @Nullable Object> uriVariables) throws RestClientException {
RequestCallback requestCallback = httpEntityCallback(request, responseType); RequestCallback requestCallback = httpEntityCallback(request, responseType);
HttpMessageConverterExtractor<T> responseExtractor = HttpMessageConverterExtractor<T> responseExtractor =
@ -531,7 +531,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
@Override @Override
public <T> ResponseEntity<T> postForEntity(String url, @Nullable Object request, public <T> ResponseEntity<T> postForEntity(String url, @Nullable Object request,
Class<T> responseType, Object... uriVariables) throws RestClientException { Class<T> responseType, @Nullable Object... uriVariables) throws RestClientException {
RequestCallback requestCallback = httpEntityCallback(request, responseType); RequestCallback requestCallback = httpEntityCallback(request, responseType);
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType); ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
@ -540,7 +540,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
@Override @Override
public <T> ResponseEntity<T> postForEntity(String url, @Nullable Object request, public <T> ResponseEntity<T> postForEntity(String url, @Nullable Object request,
Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException { Class<T> responseType, Map<String, ? extends @Nullable Object> uriVariables) throws RestClientException {
RequestCallback requestCallback = httpEntityCallback(request, responseType); RequestCallback requestCallback = httpEntityCallback(request, responseType);
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType); ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
@ -560,7 +560,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
// PUT // PUT
@Override @Override
public void put(String url, @Nullable Object request, Object... uriVariables) public void put(String url, @Nullable Object request, @Nullable Object... uriVariables)
throws RestClientException { throws RestClientException {
RequestCallback requestCallback = httpEntityCallback(request); RequestCallback requestCallback = httpEntityCallback(request);
@ -568,7 +568,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
} }
@Override @Override
public void put(String url, @Nullable Object request, Map<String, ?> uriVariables) public void put(String url, @Nullable Object request, Map<String, ? extends @Nullable Object> uriVariables)
throws RestClientException { throws RestClientException {
RequestCallback requestCallback = httpEntityCallback(request); RequestCallback requestCallback = httpEntityCallback(request);
@ -586,7 +586,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
@Override @Override
public <T> @Nullable T patchForObject(String url, @Nullable Object request, Class<T> responseType, public <T> @Nullable T patchForObject(String url, @Nullable Object request, Class<T> responseType,
Object... uriVariables) throws RestClientException { @Nullable Object... uriVariables) throws RestClientException {
RequestCallback requestCallback = httpEntityCallback(request, responseType); RequestCallback requestCallback = httpEntityCallback(request, responseType);
HttpMessageConverterExtractor<T> responseExtractor = HttpMessageConverterExtractor<T> responseExtractor =
@ -596,7 +596,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
@Override @Override
public <T> @Nullable T patchForObject(String url, @Nullable Object request, Class<T> responseType, public <T> @Nullable T patchForObject(String url, @Nullable Object request, Class<T> responseType,
Map<String, ?> uriVariables) throws RestClientException { Map<String, ? extends @Nullable Object> uriVariables) throws RestClientException {
RequestCallback requestCallback = httpEntityCallback(request, responseType); RequestCallback requestCallback = httpEntityCallback(request, responseType);
HttpMessageConverterExtractor<T> responseExtractor = HttpMessageConverterExtractor<T> responseExtractor =
@ -618,12 +618,12 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
// DELETE // DELETE
@Override @Override
public void delete(String url, Object... uriVariables) throws RestClientException { public void delete(String url, @Nullable Object... uriVariables) throws RestClientException {
execute(url, HttpMethod.DELETE, null, null, uriVariables); execute(url, HttpMethod.DELETE, null, null, uriVariables);
} }
@Override @Override
public void delete(String url, Map<String, ?> uriVariables) throws RestClientException { public void delete(String url, Map<String, ? extends @Nullable Object> uriVariables) throws RestClientException {
execute(url, HttpMethod.DELETE, null, null, uriVariables); execute(url, HttpMethod.DELETE, null, null, uriVariables);
} }
@ -636,14 +636,14 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
// OPTIONS // OPTIONS
@Override @Override
public Set<HttpMethod> optionsForAllow(String url, Object... uriVariables) throws RestClientException { public Set<HttpMethod> optionsForAllow(String url, @Nullable Object... uriVariables) throws RestClientException {
ResponseExtractor<HttpHeaders> headersExtractor = headersExtractor(); ResponseExtractor<HttpHeaders> headersExtractor = headersExtractor();
HttpHeaders headers = execute(url, HttpMethod.OPTIONS, null, headersExtractor, uriVariables); HttpHeaders headers = execute(url, HttpMethod.OPTIONS, null, headersExtractor, uriVariables);
return (headers != null ? headers.getAllow() : Collections.emptySet()); return (headers != null ? headers.getAllow() : Collections.emptySet());
} }
@Override @Override
public Set<HttpMethod> optionsForAllow(String url, Map<String, ?> uriVariables) throws RestClientException { public Set<HttpMethod> optionsForAllow(String url, Map<String, ? extends @Nullable Object> uriVariables) throws RestClientException {
ResponseExtractor<HttpHeaders> headersExtractor = headersExtractor(); ResponseExtractor<HttpHeaders> headersExtractor = headersExtractor();
HttpHeaders headers = execute(url, HttpMethod.OPTIONS, null, headersExtractor, uriVariables); HttpHeaders headers = execute(url, HttpMethod.OPTIONS, null, headersExtractor, uriVariables);
return (headers != null ? headers.getAllow() : Collections.emptySet()); return (headers != null ? headers.getAllow() : Collections.emptySet());
@ -661,7 +661,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
@Override @Override
public <T> ResponseEntity<T> exchange(String url, HttpMethod method, public <T> ResponseEntity<T> exchange(String url, HttpMethod method,
@Nullable HttpEntity<?> requestEntity, Class<T> responseType, Object... uriVariables) @Nullable HttpEntity<?> requestEntity, Class<T> responseType, @Nullable Object... uriVariables)
throws RestClientException { throws RestClientException {
RequestCallback requestCallback = httpEntityCallback(requestEntity, responseType); RequestCallback requestCallback = httpEntityCallback(requestEntity, responseType);
@ -671,7 +671,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
@Override @Override
public <T> ResponseEntity<T> exchange(String url, HttpMethod method, public <T> ResponseEntity<T> exchange(String url, HttpMethod method,
@Nullable HttpEntity<?> requestEntity, Class<T> responseType, Map<String, ?> uriVariables) @Nullable HttpEntity<?> requestEntity, Class<T> responseType, Map<String, ? extends @Nullable Object> uriVariables)
throws RestClientException { throws RestClientException {
RequestCallback requestCallback = httpEntityCallback(requestEntity, responseType); RequestCallback requestCallback = httpEntityCallback(requestEntity, responseType);
@ -690,7 +690,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
@Override @Override
public <T> ResponseEntity<T> exchange(String url, HttpMethod method, @Nullable HttpEntity<?> requestEntity, public <T> ResponseEntity<T> exchange(String url, HttpMethod method, @Nullable HttpEntity<?> requestEntity,
ParameterizedTypeReference<T> responseType, Object... uriVariables) throws RestClientException { ParameterizedTypeReference<T> responseType, @Nullable Object... uriVariables) throws RestClientException {
Type type = responseType.getType(); Type type = responseType.getType();
RequestCallback requestCallback = httpEntityCallback(requestEntity, type); RequestCallback requestCallback = httpEntityCallback(requestEntity, type);
@ -700,7 +700,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
@Override @Override
public <T> ResponseEntity<T> exchange(String url, HttpMethod method, @Nullable HttpEntity<?> requestEntity, public <T> ResponseEntity<T> exchange(String url, HttpMethod method, @Nullable HttpEntity<?> requestEntity,
ParameterizedTypeReference<T> responseType, Map<String, ?> uriVariables) throws RestClientException { ParameterizedTypeReference<T> responseType, Map<String, ? extends @Nullable Object> uriVariables) throws RestClientException {
Type type = responseType.getType(); Type type = responseType.getType();
RequestCallback requestCallback = httpEntityCallback(requestEntity, type); RequestCallback requestCallback = httpEntityCallback(requestEntity, type);
@ -779,7 +779,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
*/ */
@Override @Override
public <T> @Nullable T execute(String uriTemplate, HttpMethod method, @Nullable RequestCallback requestCallback, public <T> @Nullable T execute(String uriTemplate, HttpMethod method, @Nullable RequestCallback requestCallback,
@Nullable ResponseExtractor<T> responseExtractor, Object... uriVariables) throws RestClientException { @Nullable ResponseExtractor<T> responseExtractor, @Nullable Object... uriVariables) throws RestClientException {
URI url = getUriTemplateHandler().expand(uriTemplate, uriVariables); URI url = getUriTemplateHandler().expand(uriTemplate, uriVariables);
return doExecute(url, uriTemplate, method, requestCallback, responseExtractor); return doExecute(url, uriTemplate, method, requestCallback, responseExtractor);
@ -798,7 +798,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
*/ */
@Override @Override
public <T> @Nullable T execute(String uriTemplate, HttpMethod method, @Nullable RequestCallback requestCallback, public <T> @Nullable T execute(String uriTemplate, HttpMethod method, @Nullable RequestCallback requestCallback,
@Nullable ResponseExtractor<T> responseExtractor, Map<String, ?> uriVariables) @Nullable ResponseExtractor<T> responseExtractor, Map<String, ? extends @Nullable Object> uriVariables)
throws RestClientException { throws RestClientException {
URI url = getUriTemplateHandler().expand(uriTemplate, uriVariables); URI url = getUriTemplateHandler().expand(uriTemplate, uriVariables);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2024 the original author or authors. * Copyright 2002-2025 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -49,7 +49,7 @@ public class DefaultUriBuilderFactory implements UriBuilderFactory {
private EncodingMode encodingMode = EncodingMode.TEMPLATE_AND_VALUES; private EncodingMode encodingMode = EncodingMode.TEMPLATE_AND_VALUES;
private @Nullable Map<String, Object> defaultUriVariables; private @Nullable Map<String, @Nullable Object> defaultUriVariables;
private boolean parsePath = true; private boolean parsePath = true;
@ -140,7 +140,7 @@ public class DefaultUriBuilderFactory implements UriBuilderFactory {
* with a Map of variables. * with a Map of variables.
* @param defaultUriVariables default URI variable values * @param defaultUriVariables default URI variable values
*/ */
public void setDefaultUriVariables(@Nullable Map<String, ?> defaultUriVariables) { public void setDefaultUriVariables(@Nullable Map<String, ? extends @Nullable Object> defaultUriVariables) {
if (defaultUriVariables != null) { if (defaultUriVariables != null) {
if (this.defaultUriVariables == null) { if (this.defaultUriVariables == null) {
this.defaultUriVariables = new HashMap<>(defaultUriVariables); this.defaultUriVariables = new HashMap<>(defaultUriVariables);
@ -192,12 +192,12 @@ public class DefaultUriBuilderFactory implements UriBuilderFactory {
// UriTemplateHandler // UriTemplateHandler
@Override @Override
public URI expand(String uriTemplate, Map<String, ?> uriVars) { public URI expand(String uriTemplate, Map<String, ? extends @Nullable Object> uriVars) {
return uriString(uriTemplate).build(uriVars); return uriString(uriTemplate).build(uriVars);
} }
@Override @Override
public URI expand(String uriTemplate, Object... uriVars) { public URI expand(String uriTemplate, @Nullable Object... uriVars) {
return uriString(uriTemplate).build(uriVars); return uriString(uriTemplate).build(uriVars);
} }
@ -446,7 +446,7 @@ public class DefaultUriBuilderFactory implements UriBuilderFactory {
} }
@Override @Override
public URI build(Object... uriVars) { public URI build(@Nullable Object... uriVars) {
if (ObjectUtils.isEmpty(uriVars) && !CollectionUtils.isEmpty(defaultUriVariables)) { if (ObjectUtils.isEmpty(uriVars) && !CollectionUtils.isEmpty(defaultUriVariables)) {
return build(Collections.emptyMap()); return build(Collections.emptyMap());
} }

View File

@ -261,7 +261,7 @@ public interface UriBuilder {
* @param uriVariables the map of URI variables * @param uriVariables the map of URI variables
* @return the URI * @return the URI
*/ */
URI build(Object... uriVariables); URI build(@Nullable Object... uriVariables);
/** /**
* Build a {@link URI} instance and replaces URI template variables * Build a {@link URI} instance and replaces URI template variables
@ -269,7 +269,7 @@ public interface UriBuilder {
* @param uriVariables the map of URI variables * @param uriVariables the map of URI variables
* @return the URI * @return the URI
*/ */
URI build(Map<String, ?> uriVariables); URI build(Map<String, ? extends @Nullable Object> uriVariables);
/** /**
* Return a String representation of the URI by concatenating all URI * Return a String representation of the URI by concatenating all URI

View File

@ -148,7 +148,7 @@ public abstract class UriComponents implements Serializable {
* @param uriVariables the map of URI variables * @param uriVariables the map of URI variables
* @return the expanded URI components * @return the expanded URI components
*/ */
public final UriComponents expand(Map<String, ?> uriVariables) { public final UriComponents expand(Map<String, ? extends @Nullable Object> uriVariables) {
Assert.notNull(uriVariables, "'uriVariables' must not be null"); Assert.notNull(uriVariables, "'uriVariables' must not be null");
return expandInternal(new MapTemplateVariables(uriVariables)); return expandInternal(new MapTemplateVariables(uriVariables));
} }
@ -159,7 +159,7 @@ public abstract class UriComponents implements Serializable {
* @param uriVariableValues the URI variable values * @param uriVariableValues the URI variable values
* @return the expanded URI components * @return the expanded URI components
*/ */
public final UriComponents expand(Object... uriVariableValues) { public final UriComponents expand(@Nullable Object... uriVariableValues) {
Assert.notNull(uriVariableValues, "'uriVariableValues' must not be null"); Assert.notNull(uriVariableValues, "'uriVariableValues' must not be null");
return expandInternal(new VarArgsTemplateVariables(uriVariableValues)); return expandInternal(new VarArgsTemplateVariables(uriVariableValues));
} }
@ -324,9 +324,9 @@ public abstract class UriComponents implements Serializable {
*/ */
private static class MapTemplateVariables implements UriTemplateVariables { private static class MapTemplateVariables implements UriTemplateVariables {
private final Map<String, ?> uriVariables; private final Map<String, ? extends @Nullable Object> uriVariables;
public MapTemplateVariables(Map<String, ?> uriVariables) { public MapTemplateVariables(Map<String, ? extends @Nullable Object> uriVariables) {
this.uriVariables = uriVariables; this.uriVariables = uriVariables;
} }
@ -347,7 +347,7 @@ public abstract class UriComponents implements Serializable {
private final Iterator<Object> valueIterator; private final Iterator<Object> valueIterator;
public VarArgsTemplateVariables(Object... uriVariableValues) { public VarArgsTemplateVariables(@Nullable Object... uriVariableValues) {
this.valueIterator = Arrays.asList(uriVariableValues).iterator(); this.valueIterator = Arrays.asList(uriVariableValues).iterator();
} }

View File

@ -337,17 +337,17 @@ public class UriComponentsBuilder implements UriBuilder, Cloneable {
* @param uriVariableValues the URI variable values * @param uriVariableValues the URI variable values
* @return the URI components with expanded values * @return the URI components with expanded values
*/ */
public UriComponents buildAndExpand(Object... uriVariableValues) { public UriComponents buildAndExpand(@Nullable Object... uriVariableValues) {
return build().expand(uriVariableValues); return build().expand(uriVariableValues);
} }
@Override @Override
public URI build(Object... uriVariables) { public URI build(@Nullable Object... uriVariables) {
return buildInternal(EncodingHint.ENCODE_TEMPLATE).expand(uriVariables).toUri(); return buildInternal(EncodingHint.ENCODE_TEMPLATE).expand(uriVariables).toUri();
} }
@Override @Override
public URI build(Map<String, ?> uriVariables) { public URI build(Map<String, ? extends @Nullable Object> uriVariables) {
return buildInternal(EncodingHint.ENCODE_TEMPLATE).expand(uriVariables).toUri(); return buildInternal(EncodingHint.ENCODE_TEMPLATE).expand(uriVariables).toUri();
} }

View File

@ -19,6 +19,8 @@ package org.springframework.web.util;
import java.net.URI; import java.net.URI;
import java.util.Map; import java.util.Map;
import org.jspecify.annotations.Nullable;
/** /**
* Defines methods for expanding a URI template with variables. * Defines methods for expanding a URI template with variables.
* *
@ -34,7 +36,7 @@ public interface UriTemplateHandler {
* @param uriVariables variable values * @param uriVariables variable values
* @return the created URI instance * @return the created URI instance
*/ */
URI expand(String uriTemplate, Map<String, ?> uriVariables); URI expand(String uriTemplate, Map<String, ? extends @Nullable Object> uriVariables);
/** /**
* Expand the given URI template with an array of URI variables. * Expand the given URI template with an array of URI variables.
@ -42,6 +44,6 @@ public interface UriTemplateHandler {
* @param uriVariables variable values * @param uriVariables variable values
* @return the created URI instance * @return the created URI instance
*/ */
URI expand(String uriTemplate, Object... uriVariables); URI expand(String uriTemplate, @Nullable Object... uriVariables);
} }

View File

@ -325,7 +325,7 @@ public abstract class UriUtils {
* @return the encoded String * @return the encoded String
* @since 5.0 * @since 5.0
*/ */
public static Map<String, String> encodeUriVariables(Map<String, ?> uriVariables) { public static Map<String, String> encodeUriVariables(Map<String, ? extends @Nullable Object> uriVariables) {
Map<String, String> result = CollectionUtils.newLinkedHashMap(uriVariables.size()); Map<String, String> result = CollectionUtils.newLinkedHashMap(uriVariables.size());
uriVariables.forEach((key, value) -> { uriVariables.forEach((key, value) -> {
String stringValue = (value != null ? value.toString() : ""); String stringValue = (value != null ? value.toString() : "");
@ -341,7 +341,7 @@ public abstract class UriUtils {
* @return the encoded String * @return the encoded String
* @since 5.0 * @since 5.0
*/ */
public static Object[] encodeUriVariables(Object... uriVariables) { public static Object[] encodeUriVariables(@Nullable Object... uriVariables) {
return Arrays.stream(uriVariables) return Arrays.stream(uriVariables)
.map(value -> { .map(value -> {
String stringValue = (value != null ? value.toString() : ""); String stringValue = (value != null ? value.toString() : "");

View File

@ -36,7 +36,7 @@ import kotlin.reflect.KClass
* @since 5.0 * @since 5.0
*/ */
@Throws(RestClientException::class) @Throws(RestClientException::class)
inline fun <reified T> RestOperations.getForObject(url: String, vararg uriVariables: Any): T = inline fun <reified T> RestOperations.getForObject(url: String, vararg uriVariables: Any?): T =
getForObject(url, T::class.java as Class<*>, *uriVariables) as T getForObject(url, T::class.java as Class<*>, *uriVariables) as T
/** /**
@ -92,7 +92,7 @@ inline fun <reified T: Any> RestOperations.getForEntity(url: URI): ResponseEntit
* @since 5.0 * @since 5.0
*/ */
@Throws(RestClientException::class) @Throws(RestClientException::class)
inline fun <reified T: Any> RestOperations.getForEntity(url: String, vararg uriVariables: Any): ResponseEntity<T> = inline fun <reified T: Any> RestOperations.getForEntity(url: String, vararg uriVariables: Any?): ResponseEntity<T> =
getForEntity(url, T::class.java, *uriVariables) getForEntity(url, T::class.java, *uriVariables)
/** /**
@ -119,7 +119,7 @@ inline fun <reified T: Any> RestOperations.getForEntity(url: String, uriVariable
*/ */
@Throws(RestClientException::class) @Throws(RestClientException::class)
inline fun <reified T> RestOperations.patchForObject(url: String, request: Any? = null, inline fun <reified T> RestOperations.patchForObject(url: String, request: Any? = null,
vararg uriVariables: Any): T = vararg uriVariables: Any?): T =
patchForObject(url, request, T::class.java as Class<*>, *uriVariables) as T patchForObject(url, request, T::class.java as Class<*>, *uriVariables) as T
/** /**
@ -161,7 +161,7 @@ inline fun <reified T> RestOperations.patchForObject(url: URI, request: Any? = n
*/ */
@Throws(RestClientException::class) @Throws(RestClientException::class)
inline fun <reified T> RestOperations.postForObject(url: String, request: Any? = null, inline fun <reified T> RestOperations.postForObject(url: String, request: Any? = null,
vararg uriVariables: Any): T = vararg uriVariables: Any?): T =
postForObject(url, request, T::class.java as Class<*>, *uriVariables) as T postForObject(url, request, T::class.java as Class<*>, *uriVariables) as T
/** /**
@ -205,7 +205,7 @@ inline fun <reified T> RestOperations.postForObject(url: URI, request: Any? = nu
*/ */
@Throws(RestClientException::class) @Throws(RestClientException::class)
inline fun <reified T : Any> RestOperations.postForEntity(url: String, request: Any? = null, inline fun <reified T : Any> RestOperations.postForEntity(url: String, request: Any? = null,
vararg uriVariables: Any): ResponseEntity<T> = vararg uriVariables: Any?): ResponseEntity<T> =
postForEntity(url, request, T::class.java, *uriVariables) postForEntity(url, request, T::class.java, *uriVariables)
/** /**
@ -248,7 +248,7 @@ inline fun <reified T: Any> RestOperations.postForEntity(url: URI, request: Any?
*/ */
@Throws(RestClientException::class) @Throws(RestClientException::class)
inline fun <reified T: Any> RestOperations.exchange(url: String, method: HttpMethod, inline fun <reified T: Any> RestOperations.exchange(url: String, method: HttpMethod,
requestEntity: HttpEntity<*>? = null, vararg uriVariables: Any): ResponseEntity<T> = requestEntity: HttpEntity<*>? = null, vararg uriVariables: Any?): ResponseEntity<T> =
exchange(url, method, requestEntity, object : ParameterizedTypeReference<T>() {}, *uriVariables) exchange(url, method, requestEntity, object : ParameterizedTypeReference<T>() {}, *uriVariables)
/** /**

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2023 the original author or authors. * Copyright 2002-2025 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -120,7 +120,7 @@ public final class MockServerHttpRequest extends AbstractServerHttpRequest {
* @param uriVars zero or more URI variables * @param uriVars zero or more URI variables
* @return the created builder * @return the created builder
*/ */
public static BaseBuilder<?> get(String urlTemplate, Object... uriVars) { public static BaseBuilder<?> get(String urlTemplate, @Nullable Object... uriVars) {
return method(HttpMethod.GET, urlTemplate, uriVars); return method(HttpMethod.GET, urlTemplate, uriVars);
} }
@ -130,7 +130,7 @@ public final class MockServerHttpRequest extends AbstractServerHttpRequest {
* @param uriVars zero or more URI variables * @param uriVars zero or more URI variables
* @return the created builder * @return the created builder
*/ */
public static BaseBuilder<?> head(String urlTemplate, Object... uriVars) { public static BaseBuilder<?> head(String urlTemplate, @Nullable Object... uriVars) {
return method(HttpMethod.HEAD, urlTemplate, uriVars); return method(HttpMethod.HEAD, urlTemplate, uriVars);
} }
@ -140,7 +140,7 @@ public final class MockServerHttpRequest extends AbstractServerHttpRequest {
* @param uriVars zero or more URI variables * @param uriVars zero or more URI variables
* @return the created builder * @return the created builder
*/ */
public static BodyBuilder post(String urlTemplate, Object... uriVars) { public static BodyBuilder post(String urlTemplate, @Nullable Object... uriVars) {
return method(HttpMethod.POST, urlTemplate, uriVars); return method(HttpMethod.POST, urlTemplate, uriVars);
} }
@ -151,7 +151,7 @@ public final class MockServerHttpRequest extends AbstractServerHttpRequest {
* @param uriVars zero or more URI variables * @param uriVars zero or more URI variables
* @return the created builder * @return the created builder
*/ */
public static BodyBuilder put(String urlTemplate, Object... uriVars) { public static BodyBuilder put(String urlTemplate, @Nullable Object... uriVars) {
return method(HttpMethod.PUT, urlTemplate, uriVars); return method(HttpMethod.PUT, urlTemplate, uriVars);
} }
@ -161,7 +161,7 @@ public final class MockServerHttpRequest extends AbstractServerHttpRequest {
* @param uriVars zero or more URI variables * @param uriVars zero or more URI variables
* @return the created builder * @return the created builder
*/ */
public static BodyBuilder patch(String urlTemplate, Object... uriVars) { public static BodyBuilder patch(String urlTemplate, @Nullable Object... uriVars) {
return method(HttpMethod.PATCH, urlTemplate, uriVars); return method(HttpMethod.PATCH, urlTemplate, uriVars);
} }
@ -171,7 +171,7 @@ public final class MockServerHttpRequest extends AbstractServerHttpRequest {
* @param uriVars zero or more URI variables * @param uriVars zero or more URI variables
* @return the created builder * @return the created builder
*/ */
public static BaseBuilder<?> delete(String urlTemplate, Object... uriVars) { public static BaseBuilder<?> delete(String urlTemplate, @Nullable Object... uriVars) {
return method(HttpMethod.DELETE, urlTemplate, uriVars); return method(HttpMethod.DELETE, urlTemplate, uriVars);
} }
@ -181,7 +181,7 @@ public final class MockServerHttpRequest extends AbstractServerHttpRequest {
* @param uriVars zero or more URI variables * @param uriVars zero or more URI variables
* @return the created builder * @return the created builder
*/ */
public static BaseBuilder<?> options(String urlTemplate, Object... uriVars) { public static BaseBuilder<?> options(String urlTemplate, @Nullable Object... uriVars) {
return method(HttpMethod.OPTIONS, urlTemplate, uriVars); return method(HttpMethod.OPTIONS, urlTemplate, uriVars);
} }
@ -206,7 +206,7 @@ public final class MockServerHttpRequest extends AbstractServerHttpRequest {
* @param vars variables to expand into the template * @param vars variables to expand into the template
* @return the created builder * @return the created builder
*/ */
public static BodyBuilder method(HttpMethod method, String uri, Object... vars) { public static BodyBuilder method(HttpMethod method, String uri, @Nullable Object... vars) {
return method(method, toUri(uri, vars)); return method(method, toUri(uri, vars));
} }
@ -221,12 +221,12 @@ public final class MockServerHttpRequest extends AbstractServerHttpRequest {
* @deprecated in favor of {@link #method(HttpMethod, String, Object...)} * @deprecated in favor of {@link #method(HttpMethod, String, Object...)}
*/ */
@Deprecated @Deprecated
public static BodyBuilder method(String httpMethod, String uri, Object... vars) { public static BodyBuilder method(String httpMethod, String uri, @Nullable Object... vars) {
Assert.isTrue(StringUtils.hasText(httpMethod), "HTTP method is required."); Assert.isTrue(StringUtils.hasText(httpMethod), "HTTP method is required.");
return new DefaultBodyBuilder(HttpMethod.valueOf(httpMethod), toUri(uri, vars)); return new DefaultBodyBuilder(HttpMethod.valueOf(httpMethod), toUri(uri, vars));
} }
private static URI toUri(String uri, Object[] vars) { private static URI toUri(String uri, @Nullable Object[] vars) {
return UriComponentsBuilder.fromUriString(uri).buildAndExpand(vars).encode().toUri(); return UriComponentsBuilder.fromUriString(uri).buildAndExpand(vars).encode().toUri();
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2024 the original author or authors. * Copyright 2002-2025 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -216,7 +216,7 @@ final class DefaultWebClient implements WebClient {
} }
@Override @Override
public RequestBodySpec uri(String uriTemplate, Object... uriVariables) { public RequestBodySpec uri(String uriTemplate, @Nullable Object... uriVariables) {
UriBuilder uriBuilder = uriBuilderFactory.uriString(uriTemplate); UriBuilder uriBuilder = uriBuilderFactory.uriString(uriTemplate);
attribute(URI_TEMPLATE_ATTRIBUTE, uriBuilder.toUriString()); attribute(URI_TEMPLATE_ATTRIBUTE, uriBuilder.toUriString());
return uri(uriBuilder.build(uriVariables)); return uri(uriBuilder.build(uriVariables));

View File

@ -28,6 +28,7 @@ import java.util.function.Predicate;
import io.micrometer.observation.ObservationConvention; import io.micrometer.observation.ObservationConvention;
import io.micrometer.observation.ObservationRegistry; import io.micrometer.observation.ObservationRegistry;
import org.jspecify.annotations.Nullable;
import org.reactivestreams.Publisher; import org.reactivestreams.Publisher;
import reactor.core.publisher.Flux; import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
@ -391,7 +392,7 @@ public interface WebClient {
* If a {@link UriBuilderFactory} was configured for the client (for example, * If a {@link UriBuilderFactory} was configured for the client (for example,
* with a base URI) it will be used to expand the URI template. * with a base URI) it will be used to expand the URI template.
*/ */
S uri(String uri, Object... uriVariables); S uri(String uri, @Nullable Object... uriVariables);
/** /**
* Specify the URI for the request using a URI template and URI variables. * Specify the URI for the request using a URI template and URI variables.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2024 the original author or authors. * Copyright 2002-2025 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -61,7 +61,7 @@ public abstract class AbstractWebSocketClient implements WebSocketClient {
@Override @Override
public CompletableFuture<WebSocketSession> execute(WebSocketHandler webSocketHandler, public CompletableFuture<WebSocketSession> execute(WebSocketHandler webSocketHandler,
String uriTemplate, Object... uriVars) { String uriTemplate, @Nullable Object... uriVars) {
Assert.notNull(uriTemplate, "'uriTemplate' must not be null"); Assert.notNull(uriTemplate, "'uriTemplate' must not be null");
URI uri = UriComponentsBuilder.fromUriString(uriTemplate).buildAndExpand(uriVars).encode().toUri(); URI uri = UriComponentsBuilder.fromUriString(uriTemplate).buildAndExpand(uriVars).encode().toUri();

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2023 the original author or authors. * Copyright 2002-2025 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -20,6 +20,7 @@ import java.net.URI;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.Nullable;
import org.springframework.context.SmartLifecycle; import org.springframework.context.SmartLifecycle;
import org.springframework.web.util.UriComponentsBuilder; import org.springframework.web.util.UriComponentsBuilder;
@ -52,7 +53,7 @@ public abstract class ConnectionManagerSupport implements SmartLifecycle {
/** /**
* Constructor with a URI template and variables. * Constructor with a URI template and variables.
*/ */
public ConnectionManagerSupport(String uriTemplate, Object... uriVariables) { public ConnectionManagerSupport(String uriTemplate, @Nullable Object... uriVariables) {
this.uri = UriComponentsBuilder.fromUriString(uriTemplate).buildAndExpand(uriVariables).encode().toUri(); this.uri = UriComponentsBuilder.fromUriString(uriTemplate).buildAndExpand(uriVariables).encode().toUri();
} }

View File

@ -46,7 +46,7 @@ public interface WebSocketClient {
* @since 6.0 * @since 6.0
*/ */
CompletableFuture<WebSocketSession> execute(WebSocketHandler webSocketHandler, CompletableFuture<WebSocketSession> execute(WebSocketHandler webSocketHandler,
String uriTemplate, Object... uriVariables); String uriTemplate, @Nullable Object... uriVariables);
/** /**
* Execute a handshake request to the given url and handle the resulting * Execute a handshake request to the given url and handle the resulting

View File

@ -53,7 +53,7 @@ public class WebSocketConnectionManager extends ConnectionManagerSupport {
* Constructor with the client to use and a handler to handle messages with. * Constructor with the client to use and a handler to handle messages with.
*/ */
public WebSocketConnectionManager(WebSocketClient client, public WebSocketConnectionManager(WebSocketClient client,
WebSocketHandler webSocketHandler, String uriTemplate, Object... uriVariables) { WebSocketHandler webSocketHandler, String uriTemplate, @Nullable Object... uriVariables) {
super(uriTemplate, uriVariables); super(uriTemplate, uriVariables);
this.client = client; this.client = client;

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2022 the original author or authors. * Copyright 2002-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -51,13 +51,13 @@ public class AnnotatedEndpointConnectionManager extends ConnectionManagerSupport
private volatile @Nullable Session session; private volatile @Nullable Session session;
public AnnotatedEndpointConnectionManager(Object endpoint, String uriTemplate, Object... uriVariables) { public AnnotatedEndpointConnectionManager(Object endpoint, String uriTemplate, @Nullable Object... uriVariables) {
super(uriTemplate, uriVariables); super(uriTemplate, uriVariables);
this.endpoint = endpoint; this.endpoint = endpoint;
this.endpointProvider = null; this.endpointProvider = null;
} }
public AnnotatedEndpointConnectionManager(Class<?> endpointClass, String uriTemplate, Object... uriVariables) { public AnnotatedEndpointConnectionManager(Class<?> endpointClass, String uriTemplate, @Nullable Object... uriVariables) {
super(uriTemplate, uriVariables); super(uriTemplate, uriVariables);
this.endpoint = null; this.endpoint = null;
this.endpointProvider = new BeanCreatingHandlerProvider<>(endpointClass); this.endpointProvider = new BeanCreatingHandlerProvider<>(endpointClass);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2022 the original author or authors. * Copyright 2002-2025 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -62,14 +62,14 @@ public class EndpointConnectionManager extends ConnectionManagerSupport implemen
private volatile @Nullable Session session; private volatile @Nullable Session session;
public EndpointConnectionManager(Endpoint endpoint, String uriTemplate, Object... uriVariables) { public EndpointConnectionManager(Endpoint endpoint, String uriTemplate, @Nullable Object... uriVariables) {
super(uriTemplate, uriVariables); super(uriTemplate, uriVariables);
Assert.notNull(endpoint, "endpoint must not be null"); Assert.notNull(endpoint, "endpoint must not be null");
this.endpoint = endpoint; this.endpoint = endpoint;
this.endpointProvider = null; this.endpointProvider = null;
} }
public EndpointConnectionManager(Class<? extends Endpoint> endpointClass, String uriTemplate, Object... uriVars) { public EndpointConnectionManager(Class<? extends Endpoint> endpointClass, String uriTemplate, @Nullable Object... uriVars) {
super(uriTemplate, uriVars); super(uriTemplate, uriVars);
Assert.notNull(endpointClass, "endpointClass must not be null"); Assert.notNull(endpointClass, "endpointClass must not be null");
this.endpoint = null; this.endpoint = null;

View File

@ -235,7 +235,7 @@ public class WebSocketStompClient extends StompClientSupport implements SmartLif
* @return a CompletableFuture for access to the session when ready for use * @return a CompletableFuture for access to the session when ready for use
* @since 6.0 * @since 6.0
*/ */
public CompletableFuture<StompSession> connectAsync(String url, StompSessionHandler handler, Object... uriVars) { public CompletableFuture<StompSession> connectAsync(String url, StompSessionHandler handler, @Nullable Object... uriVars) {
return connectAsync(url, null, handler, uriVars); return connectAsync(url, null, handler, uriVars);
} }
@ -251,7 +251,7 @@ public class WebSocketStompClient extends StompClientSupport implements SmartLif
* @since 6.0 * @since 6.0
*/ */
public CompletableFuture<StompSession> connectAsync(String url, @Nullable WebSocketHttpHeaders handshakeHeaders, public CompletableFuture<StompSession> connectAsync(String url, @Nullable WebSocketHttpHeaders handshakeHeaders,
StompSessionHandler handler, Object... uriVariables) { StompSessionHandler handler, @Nullable Object... uriVariables) {
return connectAsync(url, handshakeHeaders, null, handler, uriVariables); return connectAsync(url, handshakeHeaders, null, handler, uriVariables);
} }
@ -270,7 +270,7 @@ public class WebSocketStompClient extends StompClientSupport implements SmartLif
* @since 6.0 * @since 6.0
*/ */
public CompletableFuture<StompSession> connectAsync(String url, @Nullable WebSocketHttpHeaders handshakeHeaders, public CompletableFuture<StompSession> connectAsync(String url, @Nullable WebSocketHttpHeaders handshakeHeaders,
@Nullable StompHeaders connectHeaders, StompSessionHandler handler, Object... uriVariables) { @Nullable StompHeaders connectHeaders, StompSessionHandler handler, @Nullable Object... uriVariables) {
Assert.notNull(url, "'url' must not be null"); Assert.notNull(url, "'url' must not be null");
URI uri = UriComponentsBuilder.fromUriString(url).buildAndExpand(uriVariables).encode().toUri(); URI uri = UriComponentsBuilder.fromUriString(url).buildAndExpand(uriVariables).encode().toUri();

View File

@ -218,7 +218,7 @@ public class SockJsClient implements WebSocketClient, Lifecycle {
@Override @Override
public CompletableFuture<WebSocketSession> execute( public CompletableFuture<WebSocketSession> execute(
WebSocketHandler handler, String uriTemplate, Object... uriVars) { WebSocketHandler handler, String uriTemplate, @Nullable Object... uriVars) {
Assert.notNull(uriTemplate, "uriTemplate must not be null"); Assert.notNull(uriTemplate, "uriTemplate must not be null");
URI uri = UriComponentsBuilder.fromUriString(uriTemplate).buildAndExpand(uriVars).encode().toUri(); URI uri = UriComponentsBuilder.fromUriString(uriTemplate).buildAndExpand(uriVars).encode().toUri();

View File

@ -20,6 +20,7 @@ import java.net.URI;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.context.Lifecycle; import org.springframework.context.Lifecycle;
@ -110,7 +111,7 @@ class WebSocketConnectionManagerTests {
@Override @Override
public CompletableFuture<WebSocketSession> execute(WebSocketHandler handler, public CompletableFuture<WebSocketSession> execute(WebSocketHandler handler,
String uriTemplate, Object... uriVars) { String uriTemplate, @Nullable Object... uriVars) {
URI uri = UriComponentsBuilder.fromUriString(uriTemplate).buildAndExpand(uriVars).encode().toUri(); URI uri = UriComponentsBuilder.fromUriString(uriTemplate).buildAndExpand(uriVars).encode().toUri();
return execute(handler, null, uri); return execute(handler, null, uri);