Remove APIs marked as deprecated for removal
Closes gh-33809
This commit is contained in:
@@ -1961,21 +1961,6 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
||||
return (headers instanceof ReadOnlyHttpHeaders ? headers : new ReadOnlyHttpHeaders(headers.headers));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove any read-only wrapper that may have been previously applied around
|
||||
* the given headers via {@link #readOnlyHttpHeaders(HttpHeaders)}.
|
||||
* <p>Once the writable instance is mutated, the read-only instance is likely
|
||||
* to be out of sync and should be discarded.
|
||||
* @param headers the headers to expose
|
||||
* @return a writable variant of the headers, or the original headers as-is
|
||||
* @since 5.1.1
|
||||
* @deprecated as of 6.2 in favor of {@link #HttpHeaders(MultiValueMap)}.
|
||||
*/
|
||||
@Deprecated(since = "6.2", forRemoval = true)
|
||||
public static HttpHeaders writableHttpHeaders(HttpHeaders headers) {
|
||||
return new HttpHeaders(headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helps to format HTTP header values, as HTTP header values themselves can
|
||||
* contain comma-separated values, can become confusing with regular
|
||||
|
||||
@@ -22,7 +22,6 @@ import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -100,23 +99,6 @@ public class MediaType extends MimeType implements Serializable {
|
||||
*/
|
||||
public static final String APPLICATION_FORM_URLENCODED_VALUE = "application/x-www-form-urlencoded";
|
||||
|
||||
/**
|
||||
* Public constant media type for {@code application/graphql+json}.
|
||||
* @since 5.3.19
|
||||
* @see <a href="https://github.com/graphql/graphql-over-http/pull/215">GraphQL over HTTP spec change</a>
|
||||
* @deprecated as of 6.0.3, in favor of {@link MediaType#APPLICATION_GRAPHQL_RESPONSE}
|
||||
*/
|
||||
@Deprecated(since = "6.0.3", forRemoval = true)
|
||||
public static final MediaType APPLICATION_GRAPHQL;
|
||||
|
||||
/**
|
||||
* A String equivalent of {@link MediaType#APPLICATION_GRAPHQL}.
|
||||
* @since 5.3.19
|
||||
* @deprecated as of 6.0.3, in favor of {@link MediaType#APPLICATION_GRAPHQL_RESPONSE_VALUE}
|
||||
*/
|
||||
@Deprecated(since = "6.0.3", forRemoval = true)
|
||||
public static final String APPLICATION_GRAPHQL_VALUE = "application/graphql+json";
|
||||
|
||||
/**
|
||||
* Public constant media type for {@code application/graphql-response+json}.
|
||||
* @since 6.0.3
|
||||
@@ -456,7 +438,6 @@ public class MediaType extends MimeType implements Serializable {
|
||||
APPLICATION_ATOM_XML = new MediaType("application", "atom+xml");
|
||||
APPLICATION_CBOR = new MediaType("application", "cbor");
|
||||
APPLICATION_FORM_URLENCODED = new MediaType("application", "x-www-form-urlencoded");
|
||||
APPLICATION_GRAPHQL = new MediaType("application", "graphql+json");
|
||||
APPLICATION_GRAPHQL_RESPONSE = new MediaType("application", "graphql-response+json");
|
||||
APPLICATION_JSON = new MediaType("application", "json");
|
||||
APPLICATION_JSON_UTF8 = new MediaType("application", "json", StandardCharsets.UTF_8);
|
||||
@@ -847,141 +828,4 @@ public class MediaType extends MimeType implements Serializable {
|
||||
return MimeTypeUtils.toString(mediaTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts the given list of {@code MediaType} objects by specificity.
|
||||
* <p>Given two media types:
|
||||
* <ol>
|
||||
* <li>if either media type has a {@linkplain #isWildcardType() wildcard type}, then the media type without the
|
||||
* wildcard is ordered before the other.</li>
|
||||
* <li>if the two media types have different {@linkplain #getType() types}, then they are considered equal and
|
||||
* remain their current order.</li>
|
||||
* <li>if either media type has a {@linkplain #isWildcardSubtype() wildcard subtype}, then the media type without
|
||||
* the wildcard is sorted before the other.</li>
|
||||
* <li>if the two media types have different {@linkplain #getSubtype() subtypes}, then they are considered equal
|
||||
* and remain their current order.</li>
|
||||
* <li>if the two media types have different {@linkplain #getQualityValue() quality value}, then the media type
|
||||
* with the highest quality value is ordered before the other.</li>
|
||||
* <li>if the two media types have a different amount of {@linkplain #getParameter(String) parameters}, then the
|
||||
* media type with the most parameters is ordered before the other.</li>
|
||||
* </ol>
|
||||
* <p>For example:
|
||||
* <blockquote>audio/basic < audio/* < */*</blockquote>
|
||||
* <blockquote>audio/* < audio/*;q=0.7; audio/*;q=0.3</blockquote>
|
||||
* <blockquote>audio/basic;level=1 < audio/basic</blockquote>
|
||||
* <blockquote>audio/basic == text/html</blockquote>
|
||||
* <blockquote>audio/basic == audio/wave</blockquote>
|
||||
* @param mediaTypes the list of media types to be sorted
|
||||
* @deprecated As of 6.0, in favor of {@link MimeTypeUtils#sortBySpecificity(List)}
|
||||
*/
|
||||
@Deprecated(since = "6.0", forRemoval = true)
|
||||
public static void sortBySpecificity(List<MediaType> mediaTypes) {
|
||||
Assert.notNull(mediaTypes, "'mediaTypes' must not be null");
|
||||
if (mediaTypes.size() > 1) {
|
||||
mediaTypes.sort(SPECIFICITY_COMPARATOR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts the given list of {@code MediaType} objects by quality value.
|
||||
* <p>Given two media types:
|
||||
* <ol>
|
||||
* <li>if the two media types have different {@linkplain #getQualityValue() quality value}, then the media type
|
||||
* with the highest quality value is ordered before the other.</li>
|
||||
* <li>if either media type has a {@linkplain #isWildcardType() wildcard type}, then the media type without the
|
||||
* wildcard is ordered before the other.</li>
|
||||
* <li>if the two media types have different {@linkplain #getType() types}, then they are considered equal and
|
||||
* remain their current order.</li>
|
||||
* <li>if either media type has a {@linkplain #isWildcardSubtype() wildcard subtype}, then the media type without
|
||||
* the wildcard is sorted before the other.</li>
|
||||
* <li>if the two media types have different {@linkplain #getSubtype() subtypes}, then they are considered equal
|
||||
* and remain their current order.</li>
|
||||
* <li>if the two media types have a different amount of {@linkplain #getParameter(String) parameters}, then the
|
||||
* media type with the most parameters is ordered before the other.</li>
|
||||
* </ol>
|
||||
* @param mediaTypes the list of media types to be sorted
|
||||
* @see #getQualityValue()
|
||||
* @deprecated As of 6.0, with no direct replacement
|
||||
*/
|
||||
@Deprecated(since = "6.0", forRemoval = true)
|
||||
public static void sortByQualityValue(List<MediaType> mediaTypes) {
|
||||
Assert.notNull(mediaTypes, "'mediaTypes' must not be null");
|
||||
if (mediaTypes.size() > 1) {
|
||||
mediaTypes.sort(QUALITY_VALUE_COMPARATOR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts the given list of {@code MediaType} objects by specificity as the
|
||||
* primary criteria and quality value the secondary.
|
||||
* @deprecated As of 6.0, in favor of {@link MimeTypeUtils#sortBySpecificity(List)}
|
||||
*/
|
||||
@Deprecated(since = "6.0")
|
||||
public static void sortBySpecificityAndQuality(List<MediaType> mediaTypes) {
|
||||
Assert.notNull(mediaTypes, "'mediaTypes' must not be null");
|
||||
if (mediaTypes.size() > 1) {
|
||||
mediaTypes.sort(MediaType.SPECIFICITY_COMPARATOR.thenComparing(MediaType.QUALITY_VALUE_COMPARATOR));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Comparator used by {@link #sortByQualityValue(List)}.
|
||||
* @deprecated As of 6.0, with no direct replacement
|
||||
*/
|
||||
@Deprecated(since = "6.0", forRemoval = true)
|
||||
public static final Comparator<MediaType> QUALITY_VALUE_COMPARATOR = (mediaType1, mediaType2) -> {
|
||||
double quality1 = mediaType1.getQualityValue();
|
||||
double quality2 = mediaType2.getQualityValue();
|
||||
int qualityComparison = Double.compare(quality2, quality1);
|
||||
if (qualityComparison != 0) {
|
||||
return qualityComparison; // audio/*;q=0.7 < audio/*;q=0.3
|
||||
}
|
||||
else if (mediaType1.isWildcardType() && !mediaType2.isWildcardType()) { // */* < audio/*
|
||||
return 1;
|
||||
}
|
||||
else if (mediaType2.isWildcardType() && !mediaType1.isWildcardType()) { // audio/* > */*
|
||||
return -1;
|
||||
}
|
||||
else if (!mediaType1.getType().equals(mediaType2.getType())) { // audio/basic == text/html
|
||||
return 0;
|
||||
}
|
||||
else { // mediaType1.getType().equals(mediaType2.getType())
|
||||
if (mediaType1.isWildcardSubtype() && !mediaType2.isWildcardSubtype()) { // audio/* < audio/basic
|
||||
return 1;
|
||||
}
|
||||
else if (mediaType2.isWildcardSubtype() && !mediaType1.isWildcardSubtype()) { // audio/basic > audio/*
|
||||
return -1;
|
||||
}
|
||||
else if (!mediaType1.getSubtype().equals(mediaType2.getSubtype())) { // audio/basic == audio/wave
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
int paramsSize1 = mediaType1.getParameters().size();
|
||||
int paramsSize2 = mediaType2.getParameters().size();
|
||||
return Integer.compare(paramsSize2, paramsSize1); // audio/basic;level=1 < audio/basic
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Comparator used by {@link #sortBySpecificity(List)}.
|
||||
* @deprecated As of 6.0, with no direct replacement
|
||||
*/
|
||||
@Deprecated(since = "6.0", forRemoval = true)
|
||||
@SuppressWarnings("removal")
|
||||
public static final Comparator<MediaType> SPECIFICITY_COMPARATOR = new SpecificityComparator<>() {
|
||||
|
||||
@Override
|
||||
protected int compareParameters(MediaType mediaType1, MediaType mediaType2) {
|
||||
double quality1 = mediaType1.getQualityValue();
|
||||
double quality2 = mediaType2.getQualityValue();
|
||||
int qualityComparison = Double.compare(quality2, quality1);
|
||||
if (qualityComparison != 0) {
|
||||
return qualityComparison; // audio/*;q=0.7 < audio/*;q=0.3
|
||||
}
|
||||
return super.compareParameters(mediaType1, mediaType2);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -42,19 +42,6 @@ public interface ClientHttpResponse extends HttpInputMessage, Closeable {
|
||||
*/
|
||||
HttpStatusCode getStatusCode() throws IOException;
|
||||
|
||||
/**
|
||||
* Get the HTTP status code as an integer.
|
||||
* @return the HTTP status as an integer value
|
||||
* @throws IOException in case of I/O errors
|
||||
* @since 3.1.1
|
||||
* @see #getStatusCode()
|
||||
* @deprecated in favor of {@link #getStatusCode()}, for removal in 7.0
|
||||
*/
|
||||
@Deprecated(since = "6.0", forRemoval = true)
|
||||
default int getRawStatusCode() throws IOException {
|
||||
return getStatusCode().value();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the HTTP status text of the response.
|
||||
* @return the HTTP status text
|
||||
|
||||
@@ -209,18 +209,6 @@ public class HttpComponentsClientHttpRequestFactory implements ClientHttpRequest
|
||||
this.readTimeout = readTimeout.toMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this request factory should buffer the request body internally.
|
||||
* <p>Default is {@code true}. When sending large amounts of data via POST or PUT, it is
|
||||
* recommended to change this property to {@code false}, so as not to run out of memory.
|
||||
* @since 4.0
|
||||
* @deprecated since 6.1 requests are never buffered, as if this property is {@code false}
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public void setBufferRequestBody(boolean bufferRequestBody) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure a factory to pre-create the {@link HttpContext} for each request.
|
||||
* <p>This may be useful for example in mutual TLS authentication where a
|
||||
|
||||
@@ -1,142 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.http.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
|
||||
import okhttp3.MediaType;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.RequestBody;
|
||||
import okio.BufferedSink;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link ClientHttpRequest} implementation based on OkHttp 3.x.
|
||||
*
|
||||
* <p>Created via the {@link OkHttp3ClientHttpRequestFactory}.
|
||||
*
|
||||
* @author Luciano Leggieri
|
||||
* @author Arjen Poutsma
|
||||
* @author Roy Clarkson
|
||||
* @since 4.3
|
||||
* @deprecated since 6.1, in favor of other HTTP client libraries;
|
||||
* scheduled for removal in 7.0
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
class OkHttp3ClientHttpRequest extends AbstractStreamingClientHttpRequest {
|
||||
|
||||
private final OkHttpClient client;
|
||||
|
||||
private final URI uri;
|
||||
|
||||
private final HttpMethod method;
|
||||
|
||||
|
||||
public OkHttp3ClientHttpRequest(OkHttpClient client, URI uri, HttpMethod method) {
|
||||
this.client = client;
|
||||
this.uri = uri;
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public HttpMethod getMethod() {
|
||||
return this.method;
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI getURI() {
|
||||
return this.uri;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("removal")
|
||||
protected ClientHttpResponse executeInternal(HttpHeaders headers, @Nullable Body body) throws IOException {
|
||||
|
||||
RequestBody requestBody;
|
||||
if (body != null) {
|
||||
requestBody = new BodyRequestBody(headers, body);
|
||||
}
|
||||
else if (okhttp3.internal.http.HttpMethod.requiresRequestBody(getMethod().name())) {
|
||||
String header = headers.getFirst(HttpHeaders.CONTENT_TYPE);
|
||||
MediaType contentType = (header != null) ? MediaType.parse(header) : null;
|
||||
requestBody = RequestBody.create(contentType, new byte[0]);
|
||||
}
|
||||
else {
|
||||
requestBody = null;
|
||||
}
|
||||
Request.Builder builder = new Request.Builder()
|
||||
.url(this.uri.toURL());
|
||||
builder.method(this.method.name(), requestBody);
|
||||
headers.forEach((headerName, headerValues) -> {
|
||||
for (String headerValue : headerValues) {
|
||||
builder.addHeader(headerName, headerValue);
|
||||
}
|
||||
});
|
||||
Request request = builder.build();
|
||||
return new OkHttp3ClientHttpResponse(this.client.newCall(request).execute());
|
||||
}
|
||||
|
||||
|
||||
private static class BodyRequestBody extends RequestBody {
|
||||
|
||||
private final HttpHeaders headers;
|
||||
|
||||
private final Body body;
|
||||
|
||||
|
||||
public BodyRequestBody(HttpHeaders headers, Body body) {
|
||||
this.headers = headers;
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long contentLength() {
|
||||
return this.headers.getContentLength();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public MediaType contentType() {
|
||||
String contentType = this.headers.getFirst(HttpHeaders.CONTENT_TYPE);
|
||||
if (StringUtils.hasText(contentType)) {
|
||||
return MediaType.parse(contentType);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(BufferedSink sink) throws IOException {
|
||||
this.body.writeTo(sink.outputStream());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOneShot() {
|
||||
return !this.body.repeatable();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,153 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.http.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.time.Duration;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import okhttp3.Cache;
|
||||
import okhttp3.OkHttpClient;
|
||||
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link ClientHttpRequestFactory} implementation that uses
|
||||
* <a href="https://square.github.io/okhttp/">OkHttp</a> 3.x to create requests.
|
||||
*
|
||||
* @author Luciano Leggieri
|
||||
* @author Arjen Poutsma
|
||||
* @author Roy Clarkson
|
||||
* @since 4.3
|
||||
* @deprecated since 6.1, in favor of other {@link ClientHttpRequestFactory} implementations;
|
||||
* scheduled for removal in 7.0
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public class OkHttp3ClientHttpRequestFactory implements ClientHttpRequestFactory, DisposableBean {
|
||||
|
||||
private OkHttpClient client;
|
||||
|
||||
private final boolean defaultClient;
|
||||
|
||||
|
||||
/**
|
||||
* Create a factory with a default {@link OkHttpClient} instance.
|
||||
*/
|
||||
public OkHttp3ClientHttpRequestFactory() {
|
||||
this.client = new OkHttpClient();
|
||||
this.defaultClient = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a factory with the given {@link OkHttpClient} instance.
|
||||
* @param client the client to use
|
||||
*/
|
||||
public OkHttp3ClientHttpRequestFactory(OkHttpClient client) {
|
||||
Assert.notNull(client, "OkHttpClient must not be null");
|
||||
this.client = client;
|
||||
this.defaultClient = false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the underlying read timeout in milliseconds.
|
||||
* A value of 0 specifies an infinite timeout.
|
||||
*/
|
||||
public void setReadTimeout(int readTimeout) {
|
||||
this.client = this.client.newBuilder()
|
||||
.readTimeout(readTimeout, TimeUnit.MILLISECONDS)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the underlying read timeout in milliseconds.
|
||||
* A value of 0 specifies an infinite timeout.
|
||||
* @since 6.1
|
||||
*/
|
||||
public void setReadTimeout(Duration readTimeout) {
|
||||
this.client = this.client.newBuilder()
|
||||
.readTimeout(readTimeout)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the underlying write timeout in milliseconds.
|
||||
* A value of 0 specifies an infinite timeout.
|
||||
*/
|
||||
public void setWriteTimeout(int writeTimeout) {
|
||||
this.client = this.client.newBuilder()
|
||||
.writeTimeout(writeTimeout, TimeUnit.MILLISECONDS)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the underlying write timeout in milliseconds.
|
||||
* A value of 0 specifies an infinite timeout.
|
||||
* @since 6.1
|
||||
*/
|
||||
public void setWriteTimeout(Duration writeTimeout) {
|
||||
this.client = this.client.newBuilder()
|
||||
.writeTimeout(writeTimeout)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the underlying connect timeout in milliseconds.
|
||||
* A value of 0 specifies an infinite timeout.
|
||||
*/
|
||||
public void setConnectTimeout(int connectTimeout) {
|
||||
this.client = this.client.newBuilder()
|
||||
.connectTimeout(connectTimeout, TimeUnit.MILLISECONDS)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the underlying connect timeout in milliseconds.
|
||||
* A value of 0 specifies an infinite timeout.
|
||||
* @since 6.1
|
||||
*/
|
||||
public void setConnectTimeout(Duration connectTimeout) {
|
||||
this.client = this.client.newBuilder()
|
||||
.connectTimeout(connectTimeout)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("removal")
|
||||
public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) {
|
||||
return new OkHttp3ClientHttpRequest(this.client, uri, httpMethod);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void destroy() throws IOException {
|
||||
if (this.defaultClient) {
|
||||
// Clean up the client if we created it in the constructor
|
||||
Cache cache = this.client.cache();
|
||||
if (cache != null) {
|
||||
cache.close();
|
||||
}
|
||||
this.client.dispatcher().executorService().shutdown();
|
||||
this.client.connectionPool().evictAll();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.http.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import okhttp3.Response;
|
||||
import okhttp3.ResponseBody;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatusCode;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link ClientHttpResponse} implementation based on OkHttp 3.x.
|
||||
*
|
||||
* @author Luciano Leggieri
|
||||
* @author Arjen Poutsma
|
||||
* @author Roy Clarkson
|
||||
* @since 4.3
|
||||
* @deprecated since 6.1, in favor of other HTTP client libraries;
|
||||
* scheduled for removal in 7.0
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
class OkHttp3ClientHttpResponse implements ClientHttpResponse {
|
||||
|
||||
private final Response response;
|
||||
|
||||
@Nullable
|
||||
private volatile HttpHeaders headers;
|
||||
|
||||
|
||||
public OkHttp3ClientHttpResponse(Response response) {
|
||||
Assert.notNull(response, "Response must not be null");
|
||||
this.response = response;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public HttpStatusCode getStatusCode() throws IOException {
|
||||
return HttpStatusCode.valueOf(this.response.code());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStatusText() {
|
||||
return this.response.message();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getBody() throws IOException {
|
||||
ResponseBody body = this.response.body();
|
||||
return (body != null ? body.byteStream() : InputStream.nullInputStream());
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpHeaders getHeaders() {
|
||||
HttpHeaders headers = this.headers;
|
||||
if (headers == null) {
|
||||
headers = new HttpHeaders();
|
||||
for (String headerName : this.response.headers().names()) {
|
||||
for (String headerValue : this.response.headers(headerName)) {
|
||||
headers.add(headerName, headerValue);
|
||||
}
|
||||
}
|
||||
this.headers = headers;
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
ResponseBody body = this.response.body();
|
||||
if (body != null) {
|
||||
body.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -81,24 +81,6 @@ final class ReactorClientHttpRequest extends AbstractStreamingClientHttpRequest
|
||||
this.exchangeTimeout = exchangeTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Original constructor with timeout values.
|
||||
* @deprecated without a replacement; readTimeout is now applied to the
|
||||
* underlying client via {@link HttpClient#responseTimeout(Duration)}, and the
|
||||
* value passed here is not used; exchangeTimeout is deprecated and superseded
|
||||
* by Reactor Netty timeout configuration, but applied if set.
|
||||
*/
|
||||
@Deprecated(since = "6.2", forRemoval = true)
|
||||
public ReactorClientHttpRequest(
|
||||
HttpClient httpClient, URI uri, HttpMethod method,
|
||||
@Nullable Duration exchangeTimeout, @Nullable Duration readTimeout) {
|
||||
|
||||
this.httpClient = httpClient;
|
||||
this.method = method;
|
||||
this.uri = uri;
|
||||
this.exchangeTimeout = exchangeTimeout;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public HttpMethod getMethod() {
|
||||
|
||||
@@ -180,36 +180,6 @@ public class ReactorClientHttpRequestFactory implements ClientHttpRequestFactory
|
||||
setReadTimeout(Duration.ofMillis(readTimeout));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the timeout for the HTTP exchange in milliseconds.
|
||||
* <p>By default, as of 6.2 this is no longer set.
|
||||
* @see #setConnectTimeout(int)
|
||||
* @see #setReadTimeout(Duration)
|
||||
* @see <a href="https://projectreactor.io/docs/netty/release/reference/index.html#timeout-configuration">Timeout Configuration</a>
|
||||
* @deprecated as of 6.2 and no longer set by default (previously 5 seconds)
|
||||
* in favor of using Reactor Netty HttpClient timeout configuration.
|
||||
*/
|
||||
@Deprecated(since = "6.2", forRemoval = true)
|
||||
public void setExchangeTimeout(long exchangeTimeout) {
|
||||
Assert.isTrue(exchangeTimeout > 0, "Timeout must be a positive value");
|
||||
this.exchangeTimeout = Duration.ofMillis(exchangeTimeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Variant of {@link #setExchangeTimeout(long)} with a Duration value.
|
||||
* <p>By default, as of 6.2 this is no longer set.
|
||||
* @see #setConnectTimeout(int)
|
||||
* @see #setReadTimeout(Duration)
|
||||
* @see <a href="https://projectreactor.io/docs/netty/release/reference/index.html#timeout-configuration">Timeout Configuration</a>
|
||||
* @deprecated as of 6.2 and no longer set by default (previously 5 seconds)
|
||||
* in favor of using Reactor Netty HttpClient timeout configuration.
|
||||
*/
|
||||
@Deprecated(since = "6.2", forRemoval = true)
|
||||
public void setExchangeTimeout(Duration exchangeTimeout) {
|
||||
Assert.notNull(exchangeTimeout, "ExchangeTimeout must not be null");
|
||||
setExchangeTimeout((int) exchangeTimeout.toMillis());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException {
|
||||
|
||||
@@ -18,12 +18,10 @@ package org.springframework.http.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.time.Duration;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import org.reactivestreams.FlowAdapters;
|
||||
import reactor.netty.Connection;
|
||||
import reactor.netty.http.client.HttpClient;
|
||||
import reactor.netty.http.client.HttpClientResponse;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
@@ -64,21 +62,6 @@ final class ReactorClientHttpResponse implements ClientHttpResponse {
|
||||
new Netty4HeadersAdapter(response.responseHeaders()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Original constructor.
|
||||
* @deprecated without a replacement; readTimeout is now applied to the
|
||||
* underlying client via {@link HttpClient#responseTimeout(Duration)}, and the
|
||||
* value passed here is not used.
|
||||
*/
|
||||
@Deprecated(since = "6.2", forRemoval = true)
|
||||
public ReactorClientHttpResponse(
|
||||
HttpClientResponse response, Connection connection, @Nullable Duration readTimeout) {
|
||||
|
||||
this.response = response;
|
||||
this.connection = connection;
|
||||
this.headers = HttpHeaders.readOnlyHttpHeaders(new Netty4HeadersAdapter(response.responseHeaders()));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public HttpStatusCode getStatusCode() {
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.http.client;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import reactor.netty.http.client.HttpClient;
|
||||
|
||||
/**
|
||||
* Reactor-Netty implementation of {@link ClientHttpRequestFactory}.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @author Juergen Hoeller
|
||||
* @since 6.1
|
||||
* @deprecated in favor of the renamed {@link ReactorClientHttpRequestFactory}
|
||||
*/
|
||||
@Deprecated(since = "6.2", forRemoval = true)
|
||||
public class ReactorNettyClientRequestFactory extends ReactorClientHttpRequestFactory {
|
||||
|
||||
/**
|
||||
* Superseded by {@link ReactorClientHttpRequestFactory}.
|
||||
* @see ReactorClientHttpRequestFactory#ReactorClientHttpRequestFactory()
|
||||
*/
|
||||
public ReactorNettyClientRequestFactory() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Superseded by {@link ReactorClientHttpRequestFactory}.
|
||||
* @see ReactorClientHttpRequestFactory#ReactorClientHttpRequestFactory(HttpClient)
|
||||
*/
|
||||
public ReactorNettyClientRequestFactory(HttpClient httpClient) {
|
||||
super(httpClient);
|
||||
}
|
||||
|
||||
/**
|
||||
* Superseded by {@link ReactorClientHttpRequestFactory}.
|
||||
* @see ReactorClientHttpRequestFactory#ReactorClientHttpRequestFactory(ReactorResourceFactory, Function)
|
||||
*/
|
||||
public ReactorNettyClientRequestFactory(ReactorResourceFactory resourceFactory, Function<HttpClient, HttpClient> mapper) {
|
||||
super(resourceFactory, mapper);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -59,24 +59,6 @@ public class SimpleClientHttpRequestFactory implements ClientHttpRequestFactory
|
||||
this.proxy = proxy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate whether this request factory should buffer the
|
||||
* {@linkplain ClientHttpRequest#getBody() request body} internally.
|
||||
* <p>Default is {@code true}. When sending large amounts of data via POST or PUT,
|
||||
* it is recommended to change this property to {@code false}, so as not to run
|
||||
* out of memory. This will result in a {@link ClientHttpRequest} that either
|
||||
* streams directly to the underlying {@link HttpURLConnection} (if the
|
||||
* {@link org.springframework.http.HttpHeaders#getContentLength() Content-Length}
|
||||
* is known in advance), or that will use "Chunked transfer encoding"
|
||||
* (if the {@code Content-Length} is not known in advance).
|
||||
* @see #setChunkSize(int)
|
||||
* @see HttpURLConnection#setFixedLengthStreamingMode(int)
|
||||
* @deprecated since 6.1 requests are never buffered, as if this property is {@code false}
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public void setBufferRequestBody(boolean bufferRequestBody) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the number of bytes to write in each chunk when not buffering request
|
||||
* bodies locally.
|
||||
@@ -134,20 +116,6 @@ public class SimpleClientHttpRequestFactory implements ClientHttpRequestFactory
|
||||
this.readTimeout = (int) readTimeout.toMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set if the underlying URLConnection can be set to 'output streaming' mode.
|
||||
* Default is {@code true}.
|
||||
* <p>When output streaming is enabled, authentication and redirection cannot be handled automatically.
|
||||
* If output streaming is disabled, the {@link HttpURLConnection#setFixedLengthStreamingMode} and
|
||||
* {@link HttpURLConnection#setChunkedStreamingMode} methods of the underlying connection will never
|
||||
* be called.
|
||||
* @param outputStreaming if output streaming is enabled
|
||||
* @deprecated as of 6.1 requests are always streamed, as if this property is {@code true}
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public void setOutputStreaming(boolean outputStreaming) {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException {
|
||||
|
||||
@@ -46,18 +46,6 @@ public interface ClientHttpResponse extends ReactiveHttpInputMessage {
|
||||
*/
|
||||
HttpStatusCode getStatusCode();
|
||||
|
||||
/**
|
||||
* Return the HTTP status code as an integer.
|
||||
* @return the HTTP status as an integer value
|
||||
* @since 5.0.6
|
||||
* @see #getStatusCode()
|
||||
* @deprecated in favor of {@link #getStatusCode()}, for removal in 7.0
|
||||
*/
|
||||
@Deprecated(since = "6.0", forRemoval = true)
|
||||
default int getRawStatusCode() {
|
||||
return getStatusCode().value();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a read-only map of response cookies received from the server.
|
||||
*/
|
||||
|
||||
@@ -76,14 +76,6 @@ class ReactorNetty2ServerHttpResponse extends AbstractServerHttpResponse impleme
|
||||
return (status != null ? status : HttpStatusCode.valueOf(this.response.status().code()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
@SuppressWarnings("removal")
|
||||
public Integer getRawStatusCode() {
|
||||
Integer status = super.getRawStatusCode();
|
||||
return (status != null ? status : this.response.status().code());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyStatusCode() {
|
||||
HttpStatusCode status = super.getStatusCode();
|
||||
|
||||
@@ -75,14 +75,6 @@ class ReactorServerHttpResponse extends AbstractServerHttpResponse implements Ze
|
||||
return (status != null ? status : HttpStatusCode.valueOf(this.response.status().code()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
@SuppressWarnings("removal")
|
||||
public Integer getRawStatusCode() {
|
||||
Integer status = super.getRawStatusCode();
|
||||
return (status != null ? status : this.response.status().code());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyStatusCode() {
|
||||
HttpStatusCode status = super.getStatusCode();
|
||||
|
||||
@@ -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");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -60,20 +60,6 @@ public interface ServerHttpResponse extends ReactiveHttpOutputMessage {
|
||||
return setStatusCode(value != null ? HttpStatusCode.valueOf(value) : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the status code that has been set, or otherwise fall back on the
|
||||
* status of the response from the underlying server. The return value may
|
||||
* be {@code null} if there is no default value from the underlying server.
|
||||
* @since 5.2.4
|
||||
* @deprecated in favor of {@link #getStatusCode()}, for removal in 7.0
|
||||
*/
|
||||
@Deprecated(since = "6.0", forRemoval = true)
|
||||
@Nullable
|
||||
default Integer getRawStatusCode() {
|
||||
HttpStatusCode httpStatus = getStatusCode();
|
||||
return (httpStatus != null ? httpStatus.value() : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a mutable map with the cookies to send to the server.
|
||||
*/
|
||||
|
||||
@@ -71,14 +71,6 @@ public class ServerHttpResponseDecorator implements ServerHttpResponse {
|
||||
return getDelegate().setRawStatusCode(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
@Deprecated
|
||||
@SuppressWarnings("removal")
|
||||
public Integer getRawStatusCode() {
|
||||
return getDelegate().getRawStatusCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpHeaders getHeaders() {
|
||||
return getDelegate().getHeaders();
|
||||
|
||||
@@ -104,14 +104,6 @@ class ServletServerHttpResponse extends AbstractListenerServerHttpResponse {
|
||||
return (status != null ? status : HttpStatusCode.valueOf(this.response.getStatus()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
@SuppressWarnings("removal")
|
||||
public Integer getRawStatusCode() {
|
||||
Integer status = super.getRawStatusCode();
|
||||
return (status != null ? status : this.response.getStatus());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyStatusCode() {
|
||||
HttpStatusCode status = super.getStatusCode();
|
||||
|
||||
@@ -87,14 +87,6 @@ class UndertowServerHttpResponse extends AbstractListenerServerHttpResponse impl
|
||||
return (status != null ? status : HttpStatusCode.valueOf(this.exchange.getStatusCode()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
@SuppressWarnings("removal")
|
||||
public Integer getRawStatusCode() {
|
||||
Integer status = super.getRawStatusCode();
|
||||
return (status != null ? status : this.exchange.getStatusCode());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyStatusCode() {
|
||||
HttpStatusCode status = super.getStatusCode();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -66,25 +66,6 @@ public class MissingServletRequestParameterException extends MissingRequestValue
|
||||
getBody().setDetail(initBodyDetail(this.parameterName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for use when a value was present but converted to {@code null}.
|
||||
* @param parameterName the name of the missing parameter
|
||||
* @param parameterType the expected type of the missing parameter
|
||||
* @param missingAfterConversion whether the value became null after conversion
|
||||
* @since 5.3.6
|
||||
* @deprecated in favor of {@link #MissingServletRequestParameterException(String, MethodParameter, boolean)}
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public MissingServletRequestParameterException(
|
||||
String parameterName, String parameterType, boolean missingAfterConversion) {
|
||||
|
||||
super("", missingAfterConversion, null, new Object[] {parameterName});
|
||||
this.parameterName = parameterName;
|
||||
this.parameterType = parameterType;
|
||||
this.parameter = null;
|
||||
getBody().setDetail(initBodyDetail(this.parameterName));
|
||||
}
|
||||
|
||||
private static String initBodyDetail(String name) {
|
||||
return "Required parameter '" + name + "' is not present.";
|
||||
}
|
||||
|
||||
@@ -136,31 +136,9 @@ public class DefaultResponseErrorHandler implements ResponseErrorHandler {
|
||||
*/
|
||||
@Override
|
||||
public void handleError(URI url, HttpMethod method, ClientHttpResponse response) throws IOException {
|
||||
|
||||
// For backwards compatibility try handle(response) first
|
||||
HandleErrorResponseDecorator decorator = new HandleErrorResponseDecorator(response);
|
||||
handleError(decorator);
|
||||
if (decorator.isHandled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
handleError(response, response.getStatusCode(), url, method);
|
||||
}
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
@Override
|
||||
public void handleError(ClientHttpResponse response) throws IOException {
|
||||
|
||||
// Called via handleError(url, method, response)
|
||||
if (response instanceof HandleErrorResponseDecorator decorator) {
|
||||
decorator.setNotHandled();
|
||||
return;
|
||||
}
|
||||
|
||||
// Called directly, so do handle
|
||||
handleError(response, response.getStatusCode(), null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the error based on the resolved status code.
|
||||
* <p>The default implementation delegates to
|
||||
@@ -288,22 +266,4 @@ public class DefaultResponseErrorHandler implements ResponseErrorHandler {
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
private static class HandleErrorResponseDecorator extends ClientHttpResponseDecorator {
|
||||
|
||||
private boolean handled = true;
|
||||
|
||||
public HandleErrorResponseDecorator(ClientHttpResponse delegate) {
|
||||
super(delegate);
|
||||
}
|
||||
|
||||
public void setNotHandled() {
|
||||
this.handled = false;
|
||||
}
|
||||
|
||||
public boolean isHandled() {
|
||||
return this.handled;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -52,19 +52,6 @@ public interface ResponseErrorHandler {
|
||||
* @since 5.0
|
||||
*/
|
||||
default void handleError(URI url, HttpMethod method, ClientHttpResponse response) throws IOException {
|
||||
handleError(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the error in the given response.
|
||||
* <p>This method is only called when {@link #hasError(ClientHttpResponse)}
|
||||
* has returned {@code true}.
|
||||
* @param response the response with the error
|
||||
* @throws IOException in case of I/O errors
|
||||
* @deprecated in favor of {@link #handleError(URI, HttpMethod, ClientHttpResponse)}
|
||||
*/
|
||||
@Deprecated(since = "6.2.1", forRemoval = true)
|
||||
default void handleError(ClientHttpResponse response) throws IOException {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,176 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.filter.reactive;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import io.micrometer.observation.Observation;
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
import io.micrometer.observation.contextpropagation.ObservationThreadLocalAccessor;
|
||||
import reactor.core.observability.DefaultSignalListener;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.util.context.Context;
|
||||
|
||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||
import org.springframework.http.server.reactive.observation.DefaultServerRequestObservationConvention;
|
||||
import org.springframework.http.server.reactive.observation.ServerHttpObservationDocumentation;
|
||||
import org.springframework.http.server.reactive.observation.ServerRequestObservationContext;
|
||||
import org.springframework.http.server.reactive.observation.ServerRequestObservationConvention;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.server.WebFilter;
|
||||
import org.springframework.web.server.WebFilterChain;
|
||||
import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.web.server.WebFilter} that creates {@link Observation observations}
|
||||
* for HTTP exchanges. This collects information about the execution time and
|
||||
* information gathered from the {@link ServerRequestObservationContext}.
|
||||
* <p>Web Frameworks can fetch the current {@link ServerRequestObservationContext context}
|
||||
* as a {@link #CURRENT_OBSERVATION_CONTEXT_ATTRIBUTE request attribute} and contribute
|
||||
* additional information to it.
|
||||
* The configured {@link ServerRequestObservationConvention} will use this context to collect
|
||||
* {@link io.micrometer.common.KeyValue metadata} and attach it to the observation.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @since 6.0
|
||||
* @deprecated since 6.1 in favor of {@link WebHttpHandlerBuilder}.
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public class ServerHttpObservationFilter implements WebFilter {
|
||||
|
||||
/**
|
||||
* Name of the request attribute holding the {@link ServerRequestObservationContext context} for the current observation.
|
||||
*/
|
||||
public static final String CURRENT_OBSERVATION_CONTEXT_ATTRIBUTE = ServerHttpObservationFilter.class.getName() + ".context";
|
||||
|
||||
private static final ServerRequestObservationConvention DEFAULT_OBSERVATION_CONVENTION = new DefaultServerRequestObservationConvention();
|
||||
|
||||
private final ObservationRegistry observationRegistry;
|
||||
|
||||
private final ServerRequestObservationConvention observationConvention;
|
||||
|
||||
/**
|
||||
* Create an {@code HttpRequestsObservationWebFilter} that records observations
|
||||
* against the given {@link ObservationRegistry}. The default
|
||||
* {@link DefaultServerRequestObservationConvention convention} will be used.
|
||||
* @param observationRegistry the registry to use for recording observations
|
||||
*/
|
||||
public ServerHttpObservationFilter(ObservationRegistry observationRegistry) {
|
||||
this(observationRegistry, DEFAULT_OBSERVATION_CONVENTION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an {@code HttpRequestsObservationWebFilter} that records observations
|
||||
* against the given {@link ObservationRegistry} with a custom convention.
|
||||
* @param observationRegistry the registry to use for recording observations
|
||||
* @param observationConvention the convention to use for all recorded observations
|
||||
*/
|
||||
public ServerHttpObservationFilter(ObservationRegistry observationRegistry, ServerRequestObservationConvention observationConvention) {
|
||||
this.observationRegistry = observationRegistry;
|
||||
this.observationConvention = observationConvention;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current {@link ServerRequestObservationContext observation context} from the given request, if available.
|
||||
* @param exchange the current exchange
|
||||
* @return the current observation context
|
||||
*/
|
||||
public static Optional<ServerRequestObservationContext> findObservationContext(ServerWebExchange exchange) {
|
||||
return Optional.ofNullable(exchange.getAttribute(CURRENT_OBSERVATION_CONTEXT_ATTRIBUTE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
|
||||
ServerRequestObservationContext observationContext = new ServerRequestObservationContext(exchange.getRequest(),
|
||||
exchange.getResponse(), exchange.getAttributes());
|
||||
exchange.getAttributes().put(CURRENT_OBSERVATION_CONTEXT_ATTRIBUTE, observationContext);
|
||||
return chain.filter(exchange).tap(() -> new ObservationSignalListener(observationContext));
|
||||
}
|
||||
|
||||
private final class ObservationSignalListener extends DefaultSignalListener<Void> {
|
||||
|
||||
private static final Set<String> DISCONNECTED_CLIENT_EXCEPTIONS = Set.of("AbortedException",
|
||||
"ClientAbortException", "EOFException", "EofException");
|
||||
|
||||
private final ServerRequestObservationContext observationContext;
|
||||
|
||||
private final Observation observation;
|
||||
|
||||
private final AtomicBoolean observationRecorded = new AtomicBoolean();
|
||||
|
||||
ObservationSignalListener(ServerRequestObservationContext observationContext) {
|
||||
this.observationContext = observationContext;
|
||||
this.observation = ServerHttpObservationDocumentation.HTTP_REACTIVE_SERVER_REQUESTS.observation(observationConvention,
|
||||
DEFAULT_OBSERVATION_CONVENTION, () -> observationContext, observationRegistry);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Context addToContext(Context originalContext) {
|
||||
return originalContext.put(ObservationThreadLocalAccessor.KEY, this.observation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFirst() throws Throwable {
|
||||
this.observation.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doOnCancel() throws Throwable {
|
||||
if (this.observationRecorded.compareAndSet(false, true)) {
|
||||
this.observationContext.setConnectionAborted(true);
|
||||
this.observation.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doOnComplete() throws Throwable {
|
||||
if (this.observationRecorded.compareAndSet(false, true)) {
|
||||
doOnTerminate(this.observationContext);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doOnError(Throwable error) throws Throwable {
|
||||
if (this.observationRecorded.compareAndSet(false, true)) {
|
||||
if (DISCONNECTED_CLIENT_EXCEPTIONS.contains(error.getClass().getSimpleName())) {
|
||||
this.observationContext.setConnectionAborted(true);
|
||||
}
|
||||
this.observationContext.setError(error);
|
||||
doOnTerminate(this.observationContext);
|
||||
}
|
||||
}
|
||||
|
||||
private void doOnTerminate(ServerRequestObservationContext context) {
|
||||
ServerHttpResponse response = context.getResponse();
|
||||
if (response != null) {
|
||||
if (response.isCommitted()) {
|
||||
this.observation.stop();
|
||||
}
|
||||
else {
|
||||
response.beforeCommit(() -> {
|
||||
this.observation.stop();
|
||||
return Mono.empty();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -88,11 +88,10 @@ public class ResponseStatusExceptionHandler implements WebExceptionHandler {
|
||||
return "Resolved [" + className + ": " + message + "] for HTTP " + request.getMethod() + " " + path;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private boolean updateResponse(ServerHttpResponse response, Throwable ex) {
|
||||
boolean result = false;
|
||||
HttpStatusCode statusCode = determineStatus(ex);
|
||||
int code = (statusCode != null ? statusCode.value() : determineRawStatusCode(ex));
|
||||
int code = (statusCode != null ? statusCode.value() : -1);
|
||||
if (code != -1) {
|
||||
if (response.setStatusCode(statusCode)) {
|
||||
if (ex instanceof ResponseStatusException responseStatusException) {
|
||||
@@ -127,19 +126,4 @@ public class ResponseStatusExceptionHandler implements WebExceptionHandler {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the raw status code for the given exception.
|
||||
* @param ex the exception to check
|
||||
* @return the associated HTTP status code, or -1 if it can't be derived.
|
||||
* @since 5.3
|
||||
* @deprecated in favor of {@link #determineStatus(Throwable)}, for removal in 7.0
|
||||
*/
|
||||
@Deprecated(since = "6.0", forRemoval = true)
|
||||
protected int determineRawStatusCode(Throwable ex) {
|
||||
if (ex instanceof ResponseStatusException responseStatusException) {
|
||||
return responseStatusException.getStatusCode().value();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,9 +18,6 @@ package org.springframework.web.service.invoker;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.core.ReactiveAdapterRegistry;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
@@ -35,9 +32,7 @@ import org.springframework.util.Assert;
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 6.1
|
||||
*/
|
||||
@SuppressWarnings("removal")
|
||||
public abstract class AbstractReactorHttpExchangeAdapter
|
||||
implements ReactorHttpExchangeAdapter, org.springframework.web.service.invoker.HttpClientAdapter {
|
||||
public abstract class AbstractReactorHttpExchangeAdapter implements ReactorHttpExchangeAdapter {
|
||||
|
||||
private ReactiveAdapterRegistry reactiveAdapterRegistry = ReactiveAdapterRegistry.getSharedInstance();
|
||||
|
||||
@@ -126,46 +121,4 @@ public abstract class AbstractReactorHttpExchangeAdapter
|
||||
return entity;
|
||||
}
|
||||
|
||||
|
||||
// HttpClientAdapter implementation
|
||||
|
||||
@Override
|
||||
public Mono<Void> requestToVoid(HttpRequestValues requestValues) {
|
||||
return exchangeForMono(requestValues);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<HttpHeaders> requestToHeaders(HttpRequestValues requestValues) {
|
||||
return exchangeForHeadersMono(requestValues);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Mono<T> requestToBody(HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType) {
|
||||
return exchangeForBodyMono(requestValues, bodyType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Flux<T> requestToBodyFlux(HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType) {
|
||||
return exchangeForBodyFlux(requestValues, bodyType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<ResponseEntity<Void>> requestToBodilessEntity(HttpRequestValues requestValues) {
|
||||
return exchangeForBodilessEntityMono(requestValues);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Mono<ResponseEntity<T>> requestToEntity(
|
||||
HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType) {
|
||||
|
||||
return exchangeForEntityMono(requestValues, bodyType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Mono<ResponseEntity<Flux<T>>> requestToEntityFlux(
|
||||
HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType) {
|
||||
|
||||
return exchangeForEntityFlux(requestValues, bodyType);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,147 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.service.invoker;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
|
||||
/**
|
||||
* Contract to abstract the underlying HTTP client and decouple it from the
|
||||
* {@linkplain HttpServiceProxyFactory#createClient(Class) HTTP service proxy}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Olga Maciaszek-Sharma
|
||||
* @since 6.0
|
||||
* @deprecated in favor of {@link ReactorHttpExchangeAdapter}
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public interface HttpClientAdapter {
|
||||
|
||||
/**
|
||||
* Perform the given request, and release the response content, if any.
|
||||
* @param requestValues the request to perform
|
||||
* @return {@code Mono} that completes when the request is fully executed
|
||||
* and the response content is released.
|
||||
*/
|
||||
Mono<Void> requestToVoid(HttpRequestValues requestValues);
|
||||
|
||||
/**
|
||||
* Perform the given request, release the response content, and return the
|
||||
* response headers.
|
||||
* @param requestValues the request to perform
|
||||
* @return {@code Mono} that returns the response headers the request is
|
||||
* fully executed and the response content released.
|
||||
*/
|
||||
Mono<HttpHeaders> requestToHeaders(HttpRequestValues requestValues);
|
||||
|
||||
/**
|
||||
* Perform the given request and decode the response content to the given type.
|
||||
* @param requestValues the request to perform
|
||||
* @param bodyType the target type to decode to
|
||||
* @return {@code Mono} that returns the decoded response.
|
||||
* @param <T> the type the response is decoded to
|
||||
*/
|
||||
<T> Mono<T> requestToBody(HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType);
|
||||
|
||||
/**
|
||||
* Perform the given request and decode the response content to a stream with
|
||||
* elements of the given type.
|
||||
* @param requestValues the request to perform
|
||||
* @param bodyType the target stream element type to decode to
|
||||
* @return {@code Flux} with decoded stream elements.
|
||||
* @param <T> the type the response is decoded to
|
||||
*/
|
||||
<T> Flux<T> requestToBodyFlux(HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType);
|
||||
|
||||
/**
|
||||
* Variant of {@link #requestToVoid(HttpRequestValues)} with additional
|
||||
* access to the response status and headers.
|
||||
*/
|
||||
Mono<ResponseEntity<Void>> requestToBodilessEntity(HttpRequestValues requestValues);
|
||||
|
||||
/**
|
||||
* Variant of {@link #requestToBody(HttpRequestValues, ParameterizedTypeReference)}
|
||||
* with additional access to the response status and headers.
|
||||
*/
|
||||
<T> Mono<ResponseEntity<T>> requestToEntity(HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType);
|
||||
|
||||
/**
|
||||
* Variant of {@link #requestToBodyFlux(HttpRequestValues, ParameterizedTypeReference)}
|
||||
* with additional access to the response status and headers.
|
||||
*/
|
||||
<T> Mono<ResponseEntity<Flux<T>>> requestToEntityFlux(HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType);
|
||||
|
||||
|
||||
/**
|
||||
* Adapt this instance to {@link ReactorHttpExchangeAdapter}.
|
||||
* @since 6.1
|
||||
*/
|
||||
default ReactorHttpExchangeAdapter asReactorExchangeAdapter() {
|
||||
|
||||
return new AbstractReactorHttpExchangeAdapter() {
|
||||
|
||||
@Override
|
||||
public boolean supportsRequestAttributes() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> exchangeForMono(HttpRequestValues values) {
|
||||
return HttpClientAdapter.this.requestToVoid(values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<HttpHeaders> exchangeForHeadersMono(HttpRequestValues values) {
|
||||
return HttpClientAdapter.this.requestToHeaders(values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Mono<T> exchangeForBodyMono(HttpRequestValues values, ParameterizedTypeReference<T> bodyType) {
|
||||
return HttpClientAdapter.this.requestToBody(values, bodyType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Flux<T> exchangeForBodyFlux(HttpRequestValues values, ParameterizedTypeReference<T> bodyType) {
|
||||
return HttpClientAdapter.this.requestToBodyFlux(values, bodyType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<ResponseEntity<Void>> exchangeForBodilessEntityMono(HttpRequestValues values) {
|
||||
return HttpClientAdapter.this.requestToBodilessEntity(values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Mono<ResponseEntity<T>> exchangeForEntityMono(
|
||||
HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType) {
|
||||
|
||||
return HttpClientAdapter.this.requestToEntity(requestValues, bodyType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Mono<ResponseEntity<Flux<T>>> exchangeForEntityFlux(
|
||||
HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType) {
|
||||
|
||||
return HttpClientAdapter.this.requestToEntityFlux(requestValues, bodyType);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -86,21 +86,6 @@ public class ContentCachingRequestWrapper extends HttpServletRequestWrapper {
|
||||
this.contentCacheLimit = (cacheLimit > 0 ? cacheLimit : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ContentCachingRequestWrapper for the given servlet request.
|
||||
* @param request the original servlet request
|
||||
* @deprecated in favor of {@link #ContentCachingRequestWrapper(HttpServletRequest, int)}
|
||||
* in order to explicitly choose the cache limit
|
||||
*/
|
||||
@Deprecated(since = "6.2.1", forRemoval = true)
|
||||
public ContentCachingRequestWrapper(HttpServletRequest request) {
|
||||
super(request);
|
||||
int contentLength = request.getContentLength();
|
||||
this.cachedContent = (contentLength > 0 ?
|
||||
new FastByteArrayOutputStream(contentLength) : new FastByteArrayOutputStream());
|
||||
this.contentCacheLimit = null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ServletInputStream getInputStream() throws IOException {
|
||||
|
||||
@@ -30,7 +30,6 @@ import java.util.Optional;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.springframework.http.HttpRequest;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
@@ -243,34 +242,6 @@ public class UriComponentsBuilder implements UriBuilder, Cloneable {
|
||||
return fromUriString(httpUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code UriComponents} object from the URI associated with
|
||||
* the given HttpRequest while also overlaying with values from the headers
|
||||
* "Forwarded" (<a href="https://tools.ietf.org/html/rfc7239">RFC 7239</a>),
|
||||
* or "X-Forwarded-Host", "X-Forwarded-Port", and "X-Forwarded-Proto" if
|
||||
* "Forwarded" is not found.
|
||||
* @param request the source request
|
||||
* @return the URI components of the URI
|
||||
* @since 4.1.5
|
||||
* @deprecated in favor of {@link ForwardedHeaderUtils#adaptFromForwardedHeaders};
|
||||
* to be removed in 7.0
|
||||
*/
|
||||
@Deprecated(since = "6.1", forRemoval = true)
|
||||
public static UriComponentsBuilder fromHttpRequest(HttpRequest request) {
|
||||
return ForwardedHeaderUtils.adaptFromForwardedHeaders(request.getURI(), request.getHeaders());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance by parsing the "Origin" header of an HTTP request.
|
||||
* @see <a href="https://tools.ietf.org/html/rfc6454">RFC 6454</a>
|
||||
* @deprecated in favor of {@link UriComponentsBuilder#fromUriString(String)};
|
||||
* to be removed in 7.0
|
||||
*/
|
||||
@Deprecated(since = "6.2", forRemoval = true)
|
||||
public static UriComponentsBuilder fromOriginHeader(String origin) {
|
||||
return fromUriString(origin);
|
||||
}
|
||||
|
||||
|
||||
// Encode methods
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ package org.springframework.http;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
@@ -279,221 +278,6 @@ class MediaTypeTests {
|
||||
assertThat(audioBasic.isLessSpecific(MediaType.TEXT_HTML)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void specificityComparator() {
|
||||
MediaType audioBasic = new MediaType("audio", "basic");
|
||||
MediaType audioWave = new MediaType("audio", "wave");
|
||||
MediaType audio = new MediaType("audio");
|
||||
MediaType audio03 = new MediaType("audio", "*", 0.3);
|
||||
MediaType audio07 = new MediaType("audio", "*", 0.7);
|
||||
MediaType audioBasicLevel = new MediaType("audio", "basic", Collections.singletonMap("level", "1"));
|
||||
MediaType textHtml = new MediaType("text", "html");
|
||||
MediaType allXml = new MediaType("application", "*+xml");
|
||||
MediaType all = MediaType.ALL;
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
Comparator<MediaType> comp = MediaType.SPECIFICITY_COMPARATOR;
|
||||
|
||||
// equal
|
||||
assertThat(comp.compare(audioBasic, audioBasic)).as("Invalid comparison result").isEqualTo(0);
|
||||
assertThat(comp.compare(audio, audio)).as("Invalid comparison result").isEqualTo(0);
|
||||
assertThat(comp.compare(audio07, audio07)).as("Invalid comparison result").isEqualTo(0);
|
||||
assertThat(comp.compare(audio03, audio03)).as("Invalid comparison result").isEqualTo(0);
|
||||
assertThat(comp.compare(audioBasicLevel, audioBasicLevel)).as("Invalid comparison result").isEqualTo(0);
|
||||
|
||||
// specific to unspecific
|
||||
assertThat(comp.compare(audioBasic, audio)).as("Invalid comparison result").isLessThan(0);
|
||||
assertThat(comp.compare(audioBasic, all)).as("Invalid comparison result").isLessThan(0);
|
||||
assertThat(comp.compare(audio, all)).as("Invalid comparison result").isLessThan(0);
|
||||
assertThat(comp.compare(MediaType.APPLICATION_XHTML_XML, allXml)).as("Invalid comparison result").isLessThan(0);
|
||||
|
||||
// unspecific to specific
|
||||
assertThat(comp.compare(audio, audioBasic)).as("Invalid comparison result").isGreaterThan(0);
|
||||
assertThat(comp.compare(allXml, MediaType.APPLICATION_XHTML_XML)).as("Invalid comparison result")
|
||||
.isGreaterThan(0);
|
||||
assertThat(comp.compare(all, audioBasic)).as("Invalid comparison result").isGreaterThan(0);
|
||||
assertThat(comp.compare(all, audio)).as("Invalid comparison result").isGreaterThan(0);
|
||||
|
||||
// qualifiers
|
||||
assertThat(comp.compare(audio, audio07)).as("Invalid comparison result").isLessThan(0);
|
||||
assertThat(comp.compare(audio07, audio)).as("Invalid comparison result").isGreaterThan(0);
|
||||
assertThat(comp.compare(audio07, audio03)).as("Invalid comparison result").isLessThan(0);
|
||||
assertThat(comp.compare(audio03, audio07)).as("Invalid comparison result").isGreaterThan(0);
|
||||
assertThat(comp.compare(audio03, all)).as("Invalid comparison result").isLessThan(0);
|
||||
assertThat(comp.compare(all, audio03)).as("Invalid comparison result").isGreaterThan(0);
|
||||
|
||||
// other parameters
|
||||
assertThat(comp.compare(audioBasic, audioBasicLevel)).as("Invalid comparison result").isGreaterThan(0);
|
||||
assertThat(comp.compare(audioBasicLevel, audioBasic)).as("Invalid comparison result").isLessThan(0);
|
||||
|
||||
// different types
|
||||
assertThat(comp.compare(audioBasic, textHtml)).as("Invalid comparison result").isEqualTo(0);
|
||||
assertThat(comp.compare(textHtml, audioBasic)).as("Invalid comparison result").isEqualTo(0);
|
||||
|
||||
// different subtypes
|
||||
assertThat(comp.compare(audioBasic, audioWave)).as("Invalid comparison result").isEqualTo(0);
|
||||
assertThat(comp.compare(audioWave, audioBasic)).as("Invalid comparison result").isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("removal")
|
||||
public void sortBySpecificityRelated() {
|
||||
MediaType audioBasic = new MediaType("audio", "basic");
|
||||
MediaType audio = new MediaType("audio");
|
||||
MediaType audio03 = new MediaType("audio", "*", 0.3);
|
||||
MediaType audio07 = new MediaType("audio", "*", 0.7);
|
||||
MediaType audioBasicLevel = new MediaType("audio", "basic", Collections.singletonMap("level", "1"));
|
||||
MediaType all = MediaType.ALL;
|
||||
|
||||
List<MediaType> expected = new ArrayList<>();
|
||||
expected.add(audioBasicLevel);
|
||||
expected.add(audioBasic);
|
||||
expected.add(audio);
|
||||
expected.add(audio07);
|
||||
expected.add(audio03);
|
||||
expected.add(all);
|
||||
|
||||
List<MediaType> result = new ArrayList<>(expected);
|
||||
Random rnd = new Random();
|
||||
// shuffle & sort 10 times
|
||||
for (int i = 0; i < 10; i++) {
|
||||
Collections.shuffle(result, rnd);
|
||||
MediaType.sortBySpecificity(result);
|
||||
|
||||
for (int j = 0; j < result.size(); j++) {
|
||||
assertThat(result.get(j)).as("Invalid media type at " + j).isSameAs(expected.get(j));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("removal")
|
||||
public void sortBySpecificityUnrelated() {
|
||||
MediaType audioBasic = new MediaType("audio", "basic");
|
||||
MediaType audioWave = new MediaType("audio", "wave");
|
||||
MediaType textHtml = new MediaType("text", "html");
|
||||
|
||||
List<MediaType> expected = new ArrayList<>();
|
||||
expected.add(textHtml);
|
||||
expected.add(audioBasic);
|
||||
expected.add(audioWave);
|
||||
|
||||
List<MediaType> result = new ArrayList<>(expected);
|
||||
MediaType.sortBySpecificity(result);
|
||||
|
||||
for (int i = 0; i < result.size(); i++) {
|
||||
assertThat(result.get(i)).as("Invalid media type at " + i).isSameAs(expected.get(i));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void qualityComparator() {
|
||||
MediaType audioBasic = new MediaType("audio", "basic");
|
||||
MediaType audioWave = new MediaType("audio", "wave");
|
||||
MediaType audio = new MediaType("audio");
|
||||
MediaType audio03 = new MediaType("audio", "*", 0.3);
|
||||
MediaType audio07 = new MediaType("audio", "*", 0.7);
|
||||
MediaType audioBasicLevel = new MediaType("audio", "basic", Collections.singletonMap("level", "1"));
|
||||
MediaType textHtml = new MediaType("text", "html");
|
||||
MediaType allXml = new MediaType("application", "*+xml");
|
||||
MediaType all = MediaType.ALL;
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
Comparator<MediaType> comp = MediaType.QUALITY_VALUE_COMPARATOR;
|
||||
|
||||
// equal
|
||||
assertThat(comp.compare(audioBasic, audioBasic)).as("Invalid comparison result").isEqualTo(0);
|
||||
assertThat(comp.compare(audio, audio)).as("Invalid comparison result").isEqualTo(0);
|
||||
assertThat(comp.compare(audio07, audio07)).as("Invalid comparison result").isEqualTo(0);
|
||||
assertThat(comp.compare(audio03, audio03)).as("Invalid comparison result").isEqualTo(0);
|
||||
assertThat(comp.compare(audioBasicLevel, audioBasicLevel)).as("Invalid comparison result").isEqualTo(0);
|
||||
|
||||
// specific to unspecific
|
||||
assertThat(comp.compare(audioBasic, audio)).as("Invalid comparison result").isLessThan(0);
|
||||
assertThat(comp.compare(audioBasic, all)).as("Invalid comparison result").isLessThan(0);
|
||||
assertThat(comp.compare(audio, all)).as("Invalid comparison result").isLessThan(0);
|
||||
assertThat(comp.compare(MediaType.APPLICATION_XHTML_XML, allXml)).as("Invalid comparison result").isLessThan(0);
|
||||
|
||||
// unspecific to specific
|
||||
assertThat(comp.compare(audio, audioBasic)).as("Invalid comparison result").isGreaterThan(0);
|
||||
assertThat(comp.compare(all, audioBasic)).as("Invalid comparison result").isGreaterThan(0);
|
||||
assertThat(comp.compare(all, audio)).as("Invalid comparison result").isGreaterThan(0);
|
||||
assertThat(comp.compare(allXml, MediaType.APPLICATION_XHTML_XML)).as("Invalid comparison result")
|
||||
.isGreaterThan(0);
|
||||
|
||||
// qualifiers
|
||||
assertThat(comp.compare(audio, audio07)).as("Invalid comparison result").isLessThan(0);
|
||||
assertThat(comp.compare(audio07, audio)).as("Invalid comparison result").isGreaterThan(0);
|
||||
assertThat(comp.compare(audio07, audio03)).as("Invalid comparison result").isLessThan(0);
|
||||
assertThat(comp.compare(audio03, audio07)).as("Invalid comparison result").isGreaterThan(0);
|
||||
assertThat(comp.compare(audio03, all)).as("Invalid comparison result").isGreaterThan(0);
|
||||
assertThat(comp.compare(all, audio03)).as("Invalid comparison result").isLessThan(0);
|
||||
|
||||
// other parameters
|
||||
assertThat(comp.compare(audioBasic, audioBasicLevel)).as("Invalid comparison result").isGreaterThan(0);
|
||||
assertThat(comp.compare(audioBasicLevel, audioBasic)).as("Invalid comparison result").isLessThan(0);
|
||||
|
||||
// different types
|
||||
assertThat(comp.compare(audioBasic, textHtml)).as("Invalid comparison result").isEqualTo(0);
|
||||
assertThat(comp.compare(textHtml, audioBasic)).as("Invalid comparison result").isEqualTo(0);
|
||||
|
||||
// different subtypes
|
||||
assertThat(comp.compare(audioBasic, audioWave)).as("Invalid comparison result").isEqualTo(0);
|
||||
assertThat(comp.compare(audioWave, audioBasic)).as("Invalid comparison result").isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("removal")
|
||||
public void sortByQualityRelated() {
|
||||
MediaType audioBasic = new MediaType("audio", "basic");
|
||||
MediaType audio = new MediaType("audio");
|
||||
MediaType audio03 = new MediaType("audio", "*", 0.3);
|
||||
MediaType audio07 = new MediaType("audio", "*", 0.7);
|
||||
MediaType audioBasicLevel = new MediaType("audio", "basic", Collections.singletonMap("level", "1"));
|
||||
MediaType all = MediaType.ALL;
|
||||
|
||||
List<MediaType> expected = new ArrayList<>();
|
||||
expected.add(audioBasicLevel);
|
||||
expected.add(audioBasic);
|
||||
expected.add(audio);
|
||||
expected.add(all);
|
||||
expected.add(audio07);
|
||||
expected.add(audio03);
|
||||
|
||||
List<MediaType> result = new ArrayList<>(expected);
|
||||
Random rnd = new Random();
|
||||
// shuffle & sort 10 times
|
||||
for (int i = 0; i < 10; i++) {
|
||||
Collections.shuffle(result, rnd);
|
||||
MediaType.sortByQualityValue(result);
|
||||
|
||||
for (int j = 0; j < result.size(); j++) {
|
||||
assertThat(result.get(j)).as("Invalid media type at " + j).isSameAs(expected.get(j));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("removal")
|
||||
public void sortByQualityUnrelated() {
|
||||
MediaType audioBasic = new MediaType("audio", "basic");
|
||||
MediaType audioWave = new MediaType("audio", "wave");
|
||||
MediaType textHtml = new MediaType("text", "html");
|
||||
|
||||
List<MediaType> expected = new ArrayList<>();
|
||||
expected.add(textHtml);
|
||||
expected.add(audioBasic);
|
||||
expected.add(audioWave);
|
||||
|
||||
List<MediaType> result = new ArrayList<>(expected);
|
||||
MediaType.sortBySpecificity(result);
|
||||
|
||||
for (int i = 0; i < result.size(); i++) {
|
||||
assertThat(result.get(i)).as("Invalid media type at " + i).isSameAs(expected.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testWithConversionService() {
|
||||
ConversionService conversionService = new DefaultConversionService();
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.http.client;
|
||||
|
||||
/**
|
||||
* Tests for {@link BufferingClientHttpRequestWrapper} for clients
|
||||
* not supporting non-null, empty request bodies for GET requests.
|
||||
*/
|
||||
class BufferingClientHttpRequestFactoryWithOkHttpTests extends AbstractHttpRequestFactoryTests {
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("removal")
|
||||
protected ClientHttpRequestFactory createRequestFactory() {
|
||||
return new BufferingClientHttpRequestFactory(new OkHttp3ClientHttpRequestFactory());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.http.client;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.http.HttpMethod;
|
||||
|
||||
/**
|
||||
* @author Roy Clarkson
|
||||
*/
|
||||
class OkHttp3ClientHttpRequestFactoryTests extends AbstractHttpRequestFactoryTests {
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
@Override
|
||||
protected ClientHttpRequestFactory createRequestFactory() {
|
||||
return new OkHttp3ClientHttpRequestFactory();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test
|
||||
void httpMethods() throws Exception {
|
||||
super.httpMethods();
|
||||
assertHttpMethod("patch", HttpMethod.PATCH);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -76,12 +76,10 @@ class RestClientIntegrationTests {
|
||||
@interface ParameterizedRestClientTest {
|
||||
}
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
static Stream<Arguments> clientHttpRequestFactories() {
|
||||
return Stream.of(
|
||||
argumentSet("JDK HttpURLConnection", new SimpleClientHttpRequestFactory()),
|
||||
argumentSet("HttpComponents", new HttpComponentsClientHttpRequestFactory()),
|
||||
argumentSet("OkHttp", new org.springframework.http.client.OkHttp3ClientHttpRequestFactory()),
|
||||
argumentSet("Jetty", new JettyClientHttpRequestFactory()),
|
||||
argumentSet("JDK HttpClient", new JdkClientHttpRequestFactory()),
|
||||
argumentSet("Reactor Netty", new ReactorClientHttpRequestFactory())
|
||||
|
||||
@@ -90,12 +90,10 @@ class RestTemplateIntegrationTests extends AbstractMockWebServerTests {
|
||||
@interface ParameterizedRestTemplateTest {
|
||||
}
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
static Stream<Arguments> clientHttpRequestFactories() {
|
||||
return Stream.of(
|
||||
argumentSet("JDK HttpURLConnection", new SimpleClientHttpRequestFactory()),
|
||||
argumentSet("HttpComponents", new HttpComponentsClientHttpRequestFactory()),
|
||||
argumentSet("OkHttp", new org.springframework.http.client.OkHttp3ClientHttpRequestFactory()),
|
||||
argumentSet("Jetty", new JettyClientHttpRequestFactory()),
|
||||
argumentSet("JDK HttpClient", new JdkClientHttpRequestFactory()),
|
||||
argumentSet("Reactor Netty", new ReactorClientHttpRequestFactory())
|
||||
|
||||
@@ -1,142 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.filter.reactive;
|
||||
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import io.micrometer.observation.Observation;
|
||||
import io.micrometer.observation.contextpropagation.ObservationThreadLocalAccessor;
|
||||
import io.micrometer.observation.tck.TestObservationRegistry;
|
||||
import io.micrometer.observation.tck.TestObservationRegistryAssert;
|
||||
import org.assertj.core.api.ThrowingConsumer;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||
import org.springframework.http.server.reactive.observation.ServerRequestObservationContext;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.server.WebFilterChain;
|
||||
import org.springframework.web.testfixture.http.server.reactive.MockServerHttpRequest;
|
||||
import org.springframework.web.testfixture.server.MockServerWebExchange;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link ServerHttpObservationFilter}.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
*/
|
||||
@SuppressWarnings("removal")
|
||||
class ServerHttpObservationFilterTests {
|
||||
|
||||
private final TestObservationRegistry observationRegistry = TestObservationRegistry.create();
|
||||
|
||||
private final ServerHttpObservationFilter filter = new ServerHttpObservationFilter(this.observationRegistry);
|
||||
|
||||
@Test
|
||||
void filterShouldFillObservationContext() {
|
||||
ServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.post("/test/resource"));
|
||||
exchange.getResponse().setRawStatusCode(200);
|
||||
WebFilterChain filterChain = createFilterChain(filterExchange -> {
|
||||
Optional<ServerRequestObservationContext> observationContext = ServerHttpObservationFilter.findObservationContext(filterExchange);
|
||||
assertThat(observationContext).isPresent();
|
||||
assertThat(observationContext.get().getCarrier()).isEqualTo(exchange.getRequest());
|
||||
assertThat(observationContext.get().getResponse()).isEqualTo(exchange.getResponse());
|
||||
});
|
||||
this.filter.filter(exchange, filterChain).block();
|
||||
assertThatHttpObservation().hasLowCardinalityKeyValue("outcome", "SUCCESS");
|
||||
}
|
||||
|
||||
@Test
|
||||
void filterShouldAddNewObservationToReactorContext() {
|
||||
ServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.post("/test/resource"));
|
||||
exchange.getResponse().setRawStatusCode(200);
|
||||
WebFilterChain filterChain = webExchange -> Mono.deferContextual(contextView -> {
|
||||
Observation observation = contextView.get(ObservationThreadLocalAccessor.KEY);
|
||||
assertThat(observation).isNotNull();
|
||||
// check that the observation was started
|
||||
assertThat(observation.getContext().getLowCardinalityKeyValue("outcome")).isNotNull();
|
||||
return Mono.empty();
|
||||
});
|
||||
this.filter.filter(exchange, filterChain).block();
|
||||
assertThatHttpObservation().hasLowCardinalityKeyValue("outcome", "SUCCESS");
|
||||
}
|
||||
|
||||
@Test
|
||||
void filterShouldUseThrownException() {
|
||||
ServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.post("/test/resource"));
|
||||
exchange.getResponse().setRawStatusCode(500);
|
||||
WebFilterChain filterChain = createFilterChain(filterExchange -> {
|
||||
throw new IllegalArgumentException("server error");
|
||||
});
|
||||
StepVerifier.create(this.filter.filter(exchange, filterChain))
|
||||
.expectError(IllegalArgumentException.class)
|
||||
.verify();
|
||||
Optional<ServerRequestObservationContext> observationContext = ServerHttpObservationFilter.findObservationContext(exchange);
|
||||
assertThat(observationContext.get().getError()).isInstanceOf(IllegalArgumentException.class);
|
||||
assertThatHttpObservation().hasLowCardinalityKeyValue("outcome", "SERVER_ERROR");
|
||||
}
|
||||
|
||||
@Test
|
||||
void filterShouldRecordObservationWhenCancelled() {
|
||||
ServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.post("/test/resource"));
|
||||
exchange.getResponse().setRawStatusCode(200);
|
||||
WebFilterChain filterChain = createFilterChain(filterExchange -> {
|
||||
});
|
||||
StepVerifier.create(this.filter.filter(exchange, filterChain))
|
||||
.thenCancel()
|
||||
.verify();
|
||||
assertThatHttpObservation().hasLowCardinalityKeyValue("outcome", "UNKNOWN");
|
||||
}
|
||||
|
||||
@Test
|
||||
void filterShouldStopObservationOnResponseCommit() {
|
||||
ServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.post("/test/resource"));
|
||||
WebFilterChain filterChain = createFilterChain(filterExchange -> {
|
||||
throw new IllegalArgumentException("server error");
|
||||
});
|
||||
StepVerifier.create(this.filter.filter(exchange, filterChain).doOnError(throwable -> {
|
||||
ServerHttpResponse response = exchange.getResponse();
|
||||
response.setRawStatusCode(500);
|
||||
response.setComplete().block();
|
||||
}))
|
||||
.expectError(IllegalArgumentException.class)
|
||||
.verify();
|
||||
Optional<ServerRequestObservationContext> observationContext = ServerHttpObservationFilter.findObservationContext(exchange);
|
||||
assertThat(observationContext.get().getError()).isInstanceOf(IllegalArgumentException.class);
|
||||
assertThatHttpObservation().hasLowCardinalityKeyValue("outcome", "SERVER_ERROR");
|
||||
}
|
||||
|
||||
|
||||
private WebFilterChain createFilterChain(ThrowingConsumer<ServerWebExchange> exchangeConsumer) {
|
||||
return filterExchange -> {
|
||||
try {
|
||||
exchangeConsumer.accept(filterExchange);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
return Mono.error(ex);
|
||||
}
|
||||
return Mono.empty();
|
||||
};
|
||||
}
|
||||
|
||||
private TestObservationRegistryAssert.TestObservationRegistryAssertReturningObservationContextAssert assertThatHttpObservation() {
|
||||
return assertThat(this.observationRegistry).hasObservationWithNameEqualTo("http.server.requests").that();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user