mirror of
https://github.com/spring-projects/spring-framework.git
synced 2026-09-17 16:39:29 +00:00
Add MediaType parameter to ApiVersionInserter
Closes gh-35259
This commit is contained in:
@@ -57,7 +57,7 @@ public interface ApiVersionInserter {
|
||||
* @param header the name of a header to hold the version
|
||||
*/
|
||||
static ApiVersionInserter useHeader(@Nullable String header) {
|
||||
return new DefaultApiVersionInserterBuilder(header, null, null).build();
|
||||
return new DefaultApiVersionInserterBuilder(header, null, null, null).build();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,7 +65,15 @@ public interface ApiVersionInserter {
|
||||
* @param queryParam the name of a query parameter to hold the version
|
||||
*/
|
||||
static ApiVersionInserter useQueryParam(@Nullable String queryParam) {
|
||||
return new DefaultApiVersionInserterBuilder(null, queryParam, null).build();
|
||||
return new DefaultApiVersionInserterBuilder(null, queryParam, null, null).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an inserter to set a MediaType parameter on the "Content-Type" header.
|
||||
* @param mediaTypeParam the name of the media type parameter to hold the version
|
||||
*/
|
||||
static ApiVersionInserter useMediaTypeParam(@Nullable String mediaTypeParam) {
|
||||
return new DefaultApiVersionInserterBuilder(null, null, mediaTypeParam, null).build();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -73,14 +81,14 @@ public interface ApiVersionInserter {
|
||||
* @param pathSegmentIndex the index of the path segment to hold the version
|
||||
*/
|
||||
static ApiVersionInserter usePathSegment(@Nullable Integer pathSegmentIndex) {
|
||||
return new DefaultApiVersionInserterBuilder(null, null, pathSegmentIndex).build();
|
||||
return new DefaultApiVersionInserterBuilder(null, null, null, pathSegmentIndex).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a builder for an {@link ApiVersionInserter}.
|
||||
*/
|
||||
static Builder builder() {
|
||||
return new DefaultApiVersionInserterBuilder(null, null, null);
|
||||
return new DefaultApiVersionInserterBuilder(null, null, null, null);
|
||||
}
|
||||
|
||||
|
||||
@@ -101,6 +109,12 @@ public interface ApiVersionInserter {
|
||||
*/
|
||||
Builder useQueryParam(@Nullable String queryParam);
|
||||
|
||||
/**
|
||||
* Create an inserter to set a MediaType parameter on the "Content-Type" header.
|
||||
* @param param the name of the media type parameter to hold the version
|
||||
*/
|
||||
Builder useMediaTypeParam(@Nullable String param);
|
||||
|
||||
/**
|
||||
* Configure the inserter to insert a path segment.
|
||||
* @param pathSegmentIndex the index of the path segment to hold the version
|
||||
|
||||
+21
-5
@@ -18,11 +18,14 @@ package org.springframework.web.client;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
@@ -39,20 +42,23 @@ final class DefaultApiVersionInserter implements ApiVersionInserter {
|
||||
|
||||
private final @Nullable String queryParam;
|
||||
|
||||
private final @Nullable String mediaTypeParam;
|
||||
|
||||
private final @Nullable Integer pathSegmentIndex;
|
||||
|
||||
private final ApiVersionFormatter versionFormatter;
|
||||
|
||||
|
||||
DefaultApiVersionInserter(
|
||||
@Nullable String header, @Nullable String queryParam, @Nullable Integer pathSegmentIndex,
|
||||
@Nullable ApiVersionFormatter formatter) {
|
||||
@Nullable String header, @Nullable String queryParam, @Nullable String mediaTypeParam,
|
||||
@Nullable Integer pathSegmentIndex, @Nullable ApiVersionFormatter formatter) {
|
||||
|
||||
Assert.isTrue(header != null || queryParam != null || pathSegmentIndex != null,
|
||||
"Expected 'header', 'queryParam', or 'pathSegmentIndex' to be configured");
|
||||
Assert.isTrue(header != null || queryParam != null || mediaTypeParam != null || pathSegmentIndex != null,
|
||||
"Expected 'header', 'queryParam', 'mediaTypeParam', or 'pathSegmentIndex' to be configured");
|
||||
|
||||
this.header = header;
|
||||
this.queryParam = queryParam;
|
||||
this.mediaTypeParam = mediaTypeParam;
|
||||
this.pathSegmentIndex = pathSegmentIndex;
|
||||
this.versionFormatter = (formatter != null ? formatter : Object::toString);
|
||||
}
|
||||
@@ -86,7 +92,17 @@ final class DefaultApiVersionInserter implements ApiVersionInserter {
|
||||
@Override
|
||||
public void insertVersion(Object version, HttpHeaders headers) {
|
||||
if (this.header != null) {
|
||||
headers.set(this.header, this.versionFormatter.formatVersion(version));
|
||||
String formattedVersion = this.versionFormatter.formatVersion(version);
|
||||
headers.set(this.header, formattedVersion);
|
||||
}
|
||||
if (this.mediaTypeParam != null) {
|
||||
MediaType contentType = headers.getContentType();
|
||||
if (contentType != null) {
|
||||
Map<String, String> params = new LinkedHashMap<>(contentType.getParameters());
|
||||
params.put(this.mediaTypeParam, this.versionFormatter.formatVersion(version));
|
||||
contentType = new MediaType(contentType, params);
|
||||
headers.setContentType(contentType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+17
-18
@@ -33,16 +33,20 @@ final class DefaultApiVersionInserterBuilder implements ApiVersionInserter.Build
|
||||
|
||||
private @Nullable String queryParam;
|
||||
|
||||
private @Nullable String mediaTypeParam;
|
||||
|
||||
private @Nullable Integer pathSegmentIndex;
|
||||
|
||||
private @Nullable ApiVersionFormatter versionFormatter;
|
||||
|
||||
|
||||
DefaultApiVersionInserterBuilder(
|
||||
@Nullable String header, @Nullable String queryParam, @Nullable Integer pathSegmentIndex) {
|
||||
@Nullable String header, @Nullable String queryParam, @Nullable String mediaTypeParam,
|
||||
@Nullable Integer pathSegmentIndex) {
|
||||
|
||||
this.header = header;
|
||||
this.queryParam = queryParam;
|
||||
this.mediaTypeParam = mediaTypeParam;
|
||||
this.pathSegmentIndex = pathSegmentIndex;
|
||||
}
|
||||
|
||||
@@ -50,45 +54,40 @@ final class DefaultApiVersionInserterBuilder implements ApiVersionInserter.Build
|
||||
* Configure the inserter to set a header.
|
||||
* @param header the name of the header to hold the version
|
||||
*/
|
||||
@Override
|
||||
public ApiVersionInserter.Builder useHeader(@Nullable String header) {
|
||||
this.header = header;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the inserter to set a query parameter.
|
||||
* @param queryParam the name of the query parameter to hold the version
|
||||
*/
|
||||
@Override
|
||||
public ApiVersionInserter.Builder useQueryParam(@Nullable String queryParam) {
|
||||
this.queryParam = queryParam;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the inserter to insert a path segment.
|
||||
* @param pathSegmentIndex the index of the path segment to hold the version
|
||||
*/
|
||||
@Override
|
||||
public ApiVersionInserter.Builder useMediaTypeParam(@Nullable String param) {
|
||||
this.mediaTypeParam = param;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiVersionInserter.Builder usePathSegment(@Nullable Integer pathSegmentIndex) {
|
||||
this.pathSegmentIndex = pathSegmentIndex;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the version Object into a String using the given {@link ApiVersionFormatter}.
|
||||
* <p>By default, the version is formatted with {@link Object#toString()}.
|
||||
* @param versionFormatter the formatter to use
|
||||
*/
|
||||
@Override
|
||||
public ApiVersionInserter.Builder withVersionFormatter(ApiVersionFormatter versionFormatter) {
|
||||
this.versionFormatter = versionFormatter;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the inserter.
|
||||
*/
|
||||
public ApiVersionInserter build() {
|
||||
return new DefaultApiVersionInserter(
|
||||
this.header, this.queryParam, this.pathSegmentIndex, this.versionFormatter);
|
||||
this.header, this.queryParam, this.mediaTypeParam, this.pathSegmentIndex,
|
||||
this.versionFormatter);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.client.JdkClientHttpRequestFactory;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -73,6 +74,12 @@ public class RestClientVersionTests {
|
||||
expectRequest(request -> assertThat(request.getTarget()).isEqualTo("/path?api-version=1.2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void mediaTypeParam() {
|
||||
performRequest(ApiVersionInserter.useMediaTypeParam("v"));
|
||||
expectRequest(request -> assertThat(request.getHeaders().get("Content-Type")).isEqualTo("application/json;v=1.2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void pathSegmentIndexLessThanSize() {
|
||||
performRequest(ApiVersionInserter.builder().usePathSegment(0).withVersionFormatter(v -> "v" + v).build());
|
||||
@@ -103,7 +110,8 @@ public class RestClientVersionTests {
|
||||
|
||||
private void performRequest(ApiVersionInserter versionInserter) {
|
||||
restClientBuilder.apiVersionInserter(versionInserter).build()
|
||||
.get().uri("/path")
|
||||
.post().uri("/path")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.apiVersion(1.2)
|
||||
.retrieve()
|
||||
.body(String.class);
|
||||
|
||||
Reference in New Issue
Block a user