Use HttpStatusCode interface

This commit contains changes made because of the introduction of
HttpStatusCode. In general, methods that used to return a HttpStatus
now return HttpStatusCode instead, and methods that returned raw status
codes are now deprecated.

See gh-28214
This commit is contained in:
Arjen Poutsma
2022-03-17 14:21:04 +01:00
parent ca4b6e86a4
commit 28ac0d3883
143 changed files with 1064 additions and 950 deletions

View File

@@ -20,6 +20,7 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.client.ClientHttpResponse; import org.springframework.http.client.ClientHttpResponse;
import org.springframework.mock.http.MockHttpInputMessage; import org.springframework.mock.http.MockHttpInputMessage;
import org.springframework.util.Assert; import org.springframework.util.Assert;
@@ -32,62 +33,65 @@ import org.springframework.util.Assert;
*/ */
public class MockClientHttpResponse extends MockHttpInputMessage implements ClientHttpResponse { public class MockClientHttpResponse extends MockHttpInputMessage implements ClientHttpResponse {
private final int statusCode; private final HttpStatusCode statusCode;
/** /**
* Constructor with response body as a byte array. * Constructor with response body as a byte array.
*/ */
public MockClientHttpResponse(byte[] body, HttpStatus statusCode) { public MockClientHttpResponse(byte[] body, HttpStatusCode statusCode) {
super(body); super(body);
Assert.notNull(statusCode, "HttpStatus is required"); Assert.notNull(statusCode, "HttpStatusCode is required");
this.statusCode = statusCode.value(); this.statusCode = statusCode;
} }
/** /**
* Variant of {@link #MockClientHttpResponse(byte[], HttpStatus)} with a * Variant of {@link #MockClientHttpResponse(byte[], HttpStatusCode)} with a
* custom HTTP status code. * custom HTTP status code.
* @since 5.3.17 * @since 5.3.17
*/ */
public MockClientHttpResponse(byte[] body, int statusCode) { public MockClientHttpResponse(byte[] body, int statusCode) {
super(body); this(body, HttpStatusCode.valueOf(statusCode));
this.statusCode = statusCode;
} }
/** /**
* Constructor with response body as InputStream. * Constructor with response body as InputStream.
*/ */
public MockClientHttpResponse(InputStream body, HttpStatus statusCode) { public MockClientHttpResponse(InputStream body, HttpStatusCode statusCode) {
super(body); super(body);
Assert.notNull(statusCode, "HttpStatus is required"); Assert.notNull(statusCode, "HttpStatus is required");
this.statusCode = statusCode.value(); this.statusCode = statusCode;
} }
/** /**
* Variant of {@link #MockClientHttpResponse(InputStream, HttpStatus)} with a * Variant of {@link #MockClientHttpResponse(InputStream, HttpStatusCode)} with a
* custom HTTP status code. * custom HTTP status code.
* @since 5.3.17 * @since 5.3.17
*/ */
public MockClientHttpResponse(InputStream body, int statusCode) { public MockClientHttpResponse(InputStream body, int statusCode) {
super(body); this(body, HttpStatusCode.valueOf(statusCode));
this.statusCode = statusCode;
} }
@Override @Override
public HttpStatus getStatusCode() { public HttpStatusCode getStatusCode() {
return HttpStatus.valueOf(this.statusCode);
}
@Override
public int getRawStatusCode() {
return this.statusCode; return this.statusCode;
} }
@Override
@Deprecated
public int getRawStatusCode() {
return this.statusCode.value();
}
@Override @Override
public String getStatusText() { public String getStatusText() {
HttpStatus status = HttpStatus.resolve(this.statusCode); if (this.statusCode instanceof HttpStatus status) {
return (status != null ? status.getReasonPhrase() : ""); return status.getReasonPhrase();
}
else {
return "";
}
} }
@Override @Override

View File

@@ -30,6 +30,7 @@ import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.core.io.buffer.DefaultDataBufferFactory; import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.ResponseCookie; import org.springframework.http.ResponseCookie;
import org.springframework.http.client.reactive.ClientHttpResponse; import org.springframework.http.client.reactive.ClientHttpResponse;
@@ -46,7 +47,7 @@ import org.springframework.util.MultiValueMap;
*/ */
public class MockClientHttpResponse implements ClientHttpResponse { public class MockClientHttpResponse implements ClientHttpResponse {
private final int status; private final HttpStatusCode statusCode;
private final HttpHeaders headers = new HttpHeaders(); private final HttpHeaders headers = new HttpHeaders();
@@ -55,25 +56,25 @@ public class MockClientHttpResponse implements ClientHttpResponse {
private Flux<DataBuffer> body = Flux.empty(); private Flux<DataBuffer> body = Flux.empty();
public MockClientHttpResponse(HttpStatus status) {
Assert.notNull(status, "HttpStatus is required");
this.status = status.value();
}
public MockClientHttpResponse(int status) { public MockClientHttpResponse(int status) {
Assert.isTrue(status > 99 && status < 1000, "Status must be between 100 and 999"); this(HttpStatusCode.valueOf(status));
this.status = status; }
public MockClientHttpResponse(HttpStatusCode status) {
Assert.notNull(status, "HttpStatusCode is required");
this.statusCode = status;
} }
@Override @Override
public HttpStatus getStatusCode() { public HttpStatusCode getStatusCode() {
return HttpStatus.valueOf(this.status); return this.statusCode;
} }
@Override @Override
@Deprecated
public int getRawStatusCode() { public int getRawStatusCode() {
return this.status; return this.statusCode.value();
} }
@Override @Override
@@ -140,7 +141,11 @@ public class MockClientHttpResponse implements ClientHttpResponse {
@Override @Override
public String toString() { public String toString() {
HttpStatus code = HttpStatus.resolve(this.status); if (this.statusCode instanceof HttpStatus status) {
return (code != null ? code.name() + "(" + this.status + ")" : "Status (" + this.status + ")") + this.headers; return status.name() + "(" + this.statusCode + ")" + this.headers;
}
else {
return "Status (" + this.statusCode + ")" + this.headers;
}
} }
} }

View File

@@ -23,6 +23,7 @@ import java.util.List;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.client.ClientHttpRequest; import org.springframework.http.client.ClientHttpRequest;
import org.springframework.http.client.ClientHttpRequestFactory; import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.ClientHttpResponse; import org.springframework.http.client.ClientHttpResponse;
@@ -71,7 +72,7 @@ public class MockMvcClientHttpRequestFactory implements ClientHttpRequestFactory
.andReturn() .andReturn()
.getResponse(); .getResponse();
HttpStatus status = HttpStatus.valueOf(servletResponse.getStatus()); HttpStatusCode status = HttpStatusCode.valueOf(servletResponse.getStatus());
byte[] body = servletResponse.getContentAsByteArray(); byte[] body = servletResponse.getContentAsByteArray();
MockClientHttpResponse clientResponse = new MockClientHttpResponse(body, status); MockClientHttpResponse clientResponse = new MockClientHttpResponse(body, status);
clientResponse.getHeaders().putAll(getResponseHeaders(servletResponse)); clientResponse.getHeaders().putAll(getResponseHeaders(servletResponse));

View File

@@ -22,7 +22,7 @@ import java.nio.charset.StandardCharsets;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpRequest; import org.springframework.http.client.ClientHttpRequest;
import org.springframework.http.client.ClientHttpResponse; import org.springframework.http.client.ClientHttpResponse;
@@ -39,7 +39,7 @@ import org.springframework.util.Assert;
*/ */
public class DefaultResponseCreator implements ResponseCreator { public class DefaultResponseCreator implements ResponseCreator {
private final int statusCode; private final HttpStatusCode statusCode;
private byte[] content = new byte[0]; private byte[] content = new byte[0];
@@ -52,18 +52,18 @@ public class DefaultResponseCreator implements ResponseCreator {
/** /**
* Protected constructor. * Protected constructor.
* Use static factory methods in {@link MockRestResponseCreators}. * Use static factory methods in {@link MockRestResponseCreators}.
* @since 5.3.17
*/ */
protected DefaultResponseCreator(HttpStatus statusCode) { protected DefaultResponseCreator(int statusCode) {
Assert.notNull(statusCode, "HttpStatus must not be null"); this(HttpStatusCode.valueOf(statusCode));
this.statusCode = statusCode.value();
} }
/** /**
* Protected constructor. * Protected constructor.
* Use static factory methods in {@link MockRestResponseCreators}. * Use static factory methods in {@link MockRestResponseCreators}.
* @since 5.3.17
*/ */
protected DefaultResponseCreator(int statusCode) { protected DefaultResponseCreator(HttpStatusCode statusCode) {
Assert.notNull(statusCode, "HttpStatusCode must not be null");
this.statusCode = statusCode; this.statusCode = statusCode;
} }

View File

@@ -21,6 +21,7 @@ import java.net.URI;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.test.web.client.ResponseCreator; import org.springframework.test.web.client.ResponseCreator;
@@ -113,12 +114,12 @@ public abstract class MockRestResponseCreators {
* {@code ResponseCreator} with a specific HTTP status. * {@code ResponseCreator} with a specific HTTP status.
* @param status the response status * @param status the response status
*/ */
public static DefaultResponseCreator withStatus(HttpStatus status) { public static DefaultResponseCreator withStatus(HttpStatusCode status) {
return new DefaultResponseCreator(status); return new DefaultResponseCreator(status);
} }
/** /**
* Variant of {@link #withStatus(HttpStatus)} for a custom HTTP status code. * Variant of {@link #withStatus(HttpStatusCode)} with an integer.
* @param status the response status * @param status the response status
* @since 5.3.17 * @since 5.3.17
*/ */

View File

@@ -31,6 +31,7 @@ import reactor.core.publisher.Mono;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.ResponseCookie; import org.springframework.http.ResponseCookie;
import org.springframework.http.client.reactive.ClientHttpRequest; import org.springframework.http.client.reactive.ClientHttpRequest;
@@ -170,17 +171,18 @@ public class ExchangeResult {
/** /**
* Return the HTTP status code as an {@link HttpStatus} enum value. * Return the HTTP status code as an {@link HttpStatusCode} value.
*/ */
public HttpStatus getStatus() { public HttpStatusCode getStatus() {
return this.response.getStatusCode(); return this.response.getStatusCode();
} }
/** /**
* Return the HTTP status code (potentially non-standard and not resolvable * Return the HTTP status code as an integer.
* through the {@link HttpStatus} enum) as an integer.
* @since 5.1.10 * @since 5.1.10
* @deprecated as of 6.0, in favor of {@link #getStatus()}
*/ */
@Deprecated
public int getRawStatusCode() { public int getRawStatusCode() {
return this.response.getRawStatusCode(); return this.response.getRawStatusCode();
} }
@@ -248,13 +250,22 @@ public class ExchangeResult {
"\n" + "\n" +
formatBody(getRequestHeaders().getContentType(), this.requestBody) + "\n" + formatBody(getRequestHeaders().getContentType(), this.requestBody) + "\n" +
"\n" + "\n" +
"< " + getStatus() + " " + getStatus().getReasonPhrase() + "\n" + "< " + getStatus() + " " + getReasonPhrase(getStatus()) + "\n" +
"< " + formatHeaders(getResponseHeaders(), "\n< ") + "\n" + "< " + formatHeaders(getResponseHeaders(), "\n< ") + "\n" +
"\n" + "\n" +
formatBody(getResponseHeaders().getContentType(), this.responseBody) +"\n" + formatBody(getResponseHeaders().getContentType(), this.responseBody) +"\n" +
formatMockServerResult(); formatMockServerResult();
} }
private static String getReasonPhrase(HttpStatusCode statusCode) {
if (statusCode instanceof HttpStatus status) {
return status.getReasonPhrase();
}
else {
return "";
}
}
private String formatHeaders(HttpHeaders headers, String delimiter) { private String formatHeaders(HttpHeaders headers, String delimiter) {
return headers.entrySet().stream() return headers.entrySet().stream()
.map(entry -> entry.getKey() + ": " + entry.getValue()) .map(entry -> entry.getKey() + ": " + entry.getValue())

View File

@@ -31,6 +31,8 @@ import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpCookie; import org.springframework.http.HttpCookie;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.client.reactive.ClientHttpConnector; import org.springframework.http.client.reactive.ClientHttpConnector;
import org.springframework.http.client.reactive.ClientHttpRequest; import org.springframework.http.client.reactive.ClientHttpRequest;
import org.springframework.http.client.reactive.ClientHttpResponse; import org.springframework.http.client.reactive.ClientHttpResponse;
@@ -142,8 +144,8 @@ public class HttpHandlerConnector implements ClientHttpConnector {
} }
private ClientHttpResponse adaptResponse(MockServerHttpResponse response, Flux<DataBuffer> body) { private ClientHttpResponse adaptResponse(MockServerHttpResponse response, Flux<DataBuffer> body) {
Integer status = response.getRawStatusCode(); HttpStatusCode status = response.getStatusCode();
MockClientHttpResponse clientResponse = new MockClientHttpResponse((status != null) ? status : 200); MockClientHttpResponse clientResponse = new MockClientHttpResponse((status != null) ? status : HttpStatus.OK);
clientResponse.getHeaders().putAll(response.getHeaders()); clientResponse.getHeaders().putAll(response.getHeaders());
clientResponse.getCookies().putAll(response.getCookies()); clientResponse.getCookies().putAll(response.getCookies());
clientResponse.setBody(body); clientResponse.setBody(body);

View File

@@ -22,6 +22,7 @@ import org.hamcrest.Matcher;
import org.hamcrest.MatcherAssert; import org.hamcrest.MatcherAssert;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.test.util.AssertionErrors; import org.springframework.test.util.AssertionErrors;
/** /**
@@ -45,19 +46,19 @@ public class StatusAssertions {
/** /**
* Assert the response status as an {@link HttpStatus}. * Assert the response status as an {@link HttpStatusCode}.
*/ */
public WebTestClient.ResponseSpec isEqualTo(HttpStatus status) { public WebTestClient.ResponseSpec isEqualTo(HttpStatusCode status) {
return isEqualTo(status.value()); HttpStatusCode actual = this.exchangeResult.getStatus();
this.exchangeResult.assertWithDiagnostics(() -> AssertionErrors.assertEquals("Status", status, actual));
return this.responseSpec;
} }
/** /**
* Assert the response status as an integer. * Assert the response status as an integer.
*/ */
public WebTestClient.ResponseSpec isEqualTo(int status) { public WebTestClient.ResponseSpec isEqualTo(int status) {
int actual = this.exchangeResult.getRawStatusCode(); return isEqualTo(HttpStatusCode.valueOf(status));
this.exchangeResult.assertWithDiagnostics(() -> AssertionErrors.assertEquals("Status", status, actual));
return this.responseSpec;
} }
/** /**
@@ -156,12 +157,22 @@ public class StatusAssertions {
* Assert the response error message. * Assert the response error message.
*/ */
public WebTestClient.ResponseSpec reasonEquals(String reason) { public WebTestClient.ResponseSpec reasonEquals(String reason) {
String actual = this.exchangeResult.getStatus().getReasonPhrase(); String actual = getReasonPhrase(this.exchangeResult.getStatus());
this.exchangeResult.assertWithDiagnostics(() -> this.exchangeResult.assertWithDiagnostics(() ->
AssertionErrors.assertEquals("Response status reason", reason, actual)); AssertionErrors.assertEquals("Response status reason", reason, actual));
return this.responseSpec; return this.responseSpec;
} }
private static String getReasonPhrase(HttpStatusCode statusCode) {
if (statusCode instanceof HttpStatus status) {
return status.getReasonPhrase();
}
else {
return "";
}
}
/** /**
* Assert the response status code is in the 1xx range. * Assert the response status code is in the 1xx range.
*/ */
@@ -203,7 +214,7 @@ public class StatusAssertions {
* @since 5.1 * @since 5.1
*/ */
public WebTestClient.ResponseSpec value(Matcher<? super Integer> matcher) { public WebTestClient.ResponseSpec value(Matcher<? super Integer> matcher) {
int actual = this.exchangeResult.getRawStatusCode(); int actual = this.exchangeResult.getStatus().value();
this.exchangeResult.assertWithDiagnostics(() -> MatcherAssert.assertThat("Response status", actual, matcher)); this.exchangeResult.assertWithDiagnostics(() -> MatcherAssert.assertThat("Response status", actual, matcher));
return this.responseSpec; return this.responseSpec;
} }
@@ -214,22 +225,23 @@ public class StatusAssertions {
* @since 5.1 * @since 5.1
*/ */
public WebTestClient.ResponseSpec value(Consumer<Integer> consumer) { public WebTestClient.ResponseSpec value(Consumer<Integer> consumer) {
int actual = this.exchangeResult.getRawStatusCode(); int actual = this.exchangeResult.getStatus().value();
this.exchangeResult.assertWithDiagnostics(() -> consumer.accept(actual)); this.exchangeResult.assertWithDiagnostics(() -> consumer.accept(actual));
return this.responseSpec; return this.responseSpec;
} }
private WebTestClient.ResponseSpec assertStatusAndReturn(HttpStatus expected) { private WebTestClient.ResponseSpec assertStatusAndReturn(HttpStatusCode expected) {
HttpStatus actual = this.exchangeResult.getStatus(); HttpStatusCode actual = this.exchangeResult.getStatus();
this.exchangeResult.assertWithDiagnostics(() -> AssertionErrors.assertEquals("Status", expected, actual)); this.exchangeResult.assertWithDiagnostics(() -> AssertionErrors.assertEquals("Status", expected, actual));
return this.responseSpec; return this.responseSpec;
} }
private WebTestClient.ResponseSpec assertSeriesAndReturn(HttpStatus.Series expected) { private WebTestClient.ResponseSpec assertSeriesAndReturn(HttpStatus.Series expected) {
HttpStatus status = this.exchangeResult.getStatus(); HttpStatusCode status = this.exchangeResult.getStatus();
HttpStatus.Series series = HttpStatus.Series.resolve(status.value());
this.exchangeResult.assertWithDiagnostics(() -> this.exchangeResult.assertWithDiagnostics(() ->
AssertionErrors.assertEquals("Range for response status value " + status, expected, status.series())); AssertionErrors.assertEquals("Range for response status value " + status, expected, series));
return this.responseSpec; return this.responseSpec;
} }

View File

@@ -19,6 +19,7 @@ package org.springframework.test.web.servlet.result;
import org.hamcrest.Matcher; import org.hamcrest.Matcher;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.ResultMatcher; import org.springframework.test.web.servlet.ResultMatcher;
@@ -104,9 +105,7 @@ public class StatusResultMatchers {
} }
private HttpStatus.Series getHttpStatusSeries(MvcResult result) { private HttpStatus.Series getHttpStatusSeries(MvcResult result) {
int statusValue = result.getResponse().getStatus(); return HttpStatus.Series.resolve(result.getResponse().getStatus());
HttpStatus status = HttpStatus.valueOf(statusValue);
return status.series();
} }
/** /**
@@ -623,7 +622,7 @@ public class StatusResultMatchers {
/** /**
* Match the expected response status to that of the HttpServletResponse. * Match the expected response status to that of the HttpServletResponse.
*/ */
private ResultMatcher matcher(HttpStatus status) { private ResultMatcher matcher(HttpStatusCode status) {
return result -> assertEquals("Status", status.value(), result.getResponse().getStatus()); return result -> assertEquals("Status", status.value(), result.getResponse().getStatus());
} }

View File

@@ -22,6 +22,7 @@ import java.net.URI;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.mock.http.client.MockClientHttpResponse; import org.springframework.mock.http.client.MockClientHttpResponse;
import org.springframework.test.web.client.ResponseCreator; import org.springframework.test.web.client.ResponseCreator;
@@ -133,7 +134,7 @@ class ResponseCreatorsTests {
DefaultResponseCreator responseCreator = MockRestResponseCreators.withRawStatus(454); DefaultResponseCreator responseCreator = MockRestResponseCreators.withRawStatus(454);
MockClientHttpResponse response = (MockClientHttpResponse) responseCreator.createResponse(null); MockClientHttpResponse response = (MockClientHttpResponse) responseCreator.createResponse(null);
assertThat(response.getRawStatusCode()).isEqualTo(454); assertThat(response.getStatusCode()).isEqualTo(HttpStatusCode.valueOf(454));
assertThat(response.getStatusText()).isEmpty(); assertThat(response.getStatusText()).isEmpty();
} }

View File

@@ -55,7 +55,7 @@ public class ProblemDetail {
/** /**
* Protected constructor for subclasses. * Protected constructor for subclasses.
* <p>To create a {@link ProblemDetail} instance, use static factory methods, * <p>To create a {@link ProblemDetail} instance, use static factory methods,
* {@link #forStatus(HttpStatus)} or {@link #forRawStatusCode(int)}. * {@link #forStatus(HttpStatusCode)} or {@link #forStatus(int)}.
* @param rawStatusCode the response status to use * @param rawStatusCode the response status to use
*/ */
protected ProblemDetail(int rawStatusCode) { protected ProblemDetail(int rawStatusCode) {
@@ -97,12 +97,12 @@ public class ProblemDetail {
/** /**
* Variant of {@link #setStatus(int)} for chained initialization. * Variant of {@link #setStatus(int)} for chained initialization.
* @param status the response status for the problem * @param statusCode the response status for the problem
* @return the same instance * @return the same instance
*/ */
public ProblemDetail withStatus(HttpStatus status) { public ProblemDetail withStatus(HttpStatusCode statusCode) {
Assert.notNull(status, "HttpStatus is required"); Assert.notNull(statusCode, "HttpStatus is required");
setStatus(status.value()); setStatus(statusCode.value());
return this; return this;
} }
@@ -111,7 +111,7 @@ public class ProblemDetail {
* @param status the response status value for the problem * @param status the response status value for the problem
* @return the same instance * @return the same instance
*/ */
public ProblemDetail withRawStatusCode(int status) { public ProblemDetail withStatus(int status) {
setStatus(status); setStatus(status);
return this; return this;
} }
@@ -164,8 +164,8 @@ public class ProblemDetail {
/** /**
* Setter for the {@link #getStatus() problem status}. * Setter for the {@link #getStatus() problem status}.
* @param status the problem status * @param status the problem status
* @see #withStatus(HttpStatus) * @see #withStatus(HttpStatusCode)
* @see #withRawStatusCode(int) * @see #withStatus(int)
*/ */
public void setStatus(int status) { public void setStatus(int status) {
this.status = status; this.status = status;
@@ -264,15 +264,15 @@ public class ProblemDetail {
/** /**
* Create a {@code ProblemDetail} instance with the given status code. * Create a {@code ProblemDetail} instance with the given status code.
*/ */
public static ProblemDetail forStatus(HttpStatus status) { public static ProblemDetail forStatus(HttpStatusCode status) {
Assert.notNull(status, "HttpStatus is required"); Assert.notNull(status, "HttpStatusCode is required");
return forRawStatusCode(status.value()); return forStatus(status.value());
} }
/** /**
* Create a {@code ProblemDetail} instance with the given status value. * Create a {@code ProblemDetail} instance with the given status value.
*/ */
public static ProblemDetail forRawStatusCode(int status) { public static ProblemDetail forStatus(int status) {
return new ProblemDetail(status); return new ProblemDetail(status);
} }

View File

@@ -31,7 +31,7 @@ import org.springframework.util.MultiValueMap;
import org.springframework.util.ObjectUtils; import org.springframework.util.ObjectUtils;
/** /**
* Extension of {@link HttpEntity} that adds an {@link HttpStatus} status code. * Extension of {@link HttpEntity} that adds an {@link HttpStatusCode} status code.
* Used in {@code RestTemplate} as well as in {@code @Controller} methods. * Used in {@code RestTemplate} as well as in {@code @Controller} methods.
* *
* <p>In {@code RestTemplate}, this class is returned by * <p>In {@code RestTemplate}, this class is returned by
@@ -85,7 +85,7 @@ public class ResponseEntity<T> extends HttpEntity<T> {
* Create a {@code ResponseEntity} with a status code only. * Create a {@code ResponseEntity} with a status code only.
* @param status the status code * @param status the status code
*/ */
public ResponseEntity(HttpStatus status) { public ResponseEntity(HttpStatusCode status) {
this(null, null, status); this(null, null, status);
} }
@@ -94,7 +94,7 @@ public class ResponseEntity<T> extends HttpEntity<T> {
* @param body the entity body * @param body the entity body
* @param status the status code * @param status the status code
*/ */
public ResponseEntity(@Nullable T body, HttpStatus status) { public ResponseEntity(@Nullable T body, HttpStatusCode status) {
this(body, null, status); this(body, null, status);
} }
@@ -103,7 +103,7 @@ public class ResponseEntity<T> extends HttpEntity<T> {
* @param headers the entity headers * @param headers the entity headers
* @param status the status code * @param status the status code
*/ */
public ResponseEntity(MultiValueMap<String, String> headers, HttpStatus status) { public ResponseEntity(MultiValueMap<String, String> headers, HttpStatusCode status) {
this(null, headers, status); this(null, headers, status);
} }
@@ -113,7 +113,7 @@ public class ResponseEntity<T> extends HttpEntity<T> {
* @param headers the entity headers * @param headers the entity headers
* @param status the status code * @param status the status code
*/ */
public ResponseEntity(@Nullable T body, @Nullable MultiValueMap<String, String> headers, HttpStatus status) { public ResponseEntity(@Nullable T body, @Nullable MultiValueMap<String, String> headers, HttpStatusCode status) {
this(body, headers, (Object) status); this(body, headers, (Object) status);
} }
@@ -133,7 +133,7 @@ public class ResponseEntity<T> extends HttpEntity<T> {
*/ */
private ResponseEntity(@Nullable T body, @Nullable MultiValueMap<String, String> headers, Object status) { private ResponseEntity(@Nullable T body, @Nullable MultiValueMap<String, String> headers, Object status) {
super(body, headers); super(body, headers);
Assert.notNull(status, "HttpStatus must not be null"); Assert.notNull(status, "HttpStatusCode must not be null");
this.status = status; this.status = status;
} }
@@ -142,12 +142,12 @@ public class ResponseEntity<T> extends HttpEntity<T> {
* Return the HTTP status code of the response. * Return the HTTP status code of the response.
* @return the HTTP status as an HttpStatus enum entry * @return the HTTP status as an HttpStatus enum entry
*/ */
public HttpStatus getStatusCode() { public HttpStatusCode getStatusCode() {
if (this.status instanceof HttpStatus) { if (this.status instanceof HttpStatusCode statusCode) {
return (HttpStatus) this.status; return statusCode;
} }
else { else {
return HttpStatus.valueOf((Integer) this.status); return HttpStatusCode.valueOf((Integer) this.status);
} }
} }
@@ -155,10 +155,12 @@ public class ResponseEntity<T> extends HttpEntity<T> {
* Return the HTTP status code of the response. * Return the HTTP status code of the response.
* @return the HTTP status as an int value * @return the HTTP status as an int value
* @since 4.3 * @since 4.3
* @deprecated as of 6.0, in favor of {@link #getStatusCode()}
*/ */
@Deprecated
public int getStatusCodeValue() { public int getStatusCodeValue() {
if (this.status instanceof HttpStatus) { if (this.status instanceof HttpStatusCode statusCode) {
return ((HttpStatus) this.status).value(); return statusCode.value();
} }
else { else {
return (Integer) this.status; return (Integer) this.status;
@@ -187,9 +189,9 @@ public class ResponseEntity<T> extends HttpEntity<T> {
public String toString() { public String toString() {
StringBuilder builder = new StringBuilder("<"); StringBuilder builder = new StringBuilder("<");
builder.append(this.status); builder.append(this.status);
if (this.status instanceof HttpStatus) { if (this.status instanceof HttpStatus httpStatus) {
builder.append(' '); builder.append(' ');
builder.append(((HttpStatus) this.status).getReasonPhrase()); builder.append(httpStatus.getReasonPhrase());
} }
builder.append(','); builder.append(',');
T body = getBody(); T body = getBody();
@@ -212,8 +214,8 @@ public class ResponseEntity<T> extends HttpEntity<T> {
* @return the created builder * @return the created builder
* @since 4.1 * @since 4.1
*/ */
public static BodyBuilder status(HttpStatus status) { public static BodyBuilder status(HttpStatusCode status) {
Assert.notNull(status, "HttpStatus must not be null"); Assert.notNull(status, "HttpStatusCode must not be null");
return new DefaultBuilder(status); return new DefaultBuilder(status);
} }

View File

@@ -18,19 +18,21 @@ package org.springframework.http.client;
import java.io.IOException; import java.io.IOException;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode;
/** /**
* Abstract base for {@link ClientHttpResponse}. * Abstract base for {@link ClientHttpResponse}.
* *
* @author Arjen Poutsma * @author Arjen Poutsma
* @since 3.1.1 * @since 3.1.1
* @deprecated with no direct replacement
*/ */
@Deprecated
public abstract class AbstractClientHttpResponse implements ClientHttpResponse { public abstract class AbstractClientHttpResponse implements ClientHttpResponse {
@Override @Override
public HttpStatus getStatusCode() throws IOException { public HttpStatusCode getStatusCode() throws IOException {
return HttpStatus.valueOf(getRawStatusCode()); return HttpStatusCode.valueOf(getRawStatusCode());
} }
} }

View File

@@ -21,7 +21,7 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.util.StreamUtils; import org.springframework.util.StreamUtils;
@@ -46,11 +46,12 @@ final class BufferingClientHttpResponseWrapper implements ClientHttpResponse {
@Override @Override
public HttpStatus getStatusCode() throws IOException { public HttpStatusCode getStatusCode() throws IOException {
return this.response.getStatusCode(); return this.response.getStatusCode();
} }
@Override @Override
@Deprecated
public int getRawStatusCode() throws IOException { public int getRawStatusCode() throws IOException {
return this.response.getRawStatusCode(); return this.response.getRawStatusCode();
} }

View File

@@ -20,7 +20,7 @@ import java.io.Closeable;
import java.io.IOException; import java.io.IOException;
import org.springframework.http.HttpInputMessage; import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode;
/** /**
* Represents a client-side HTTP response. * Represents a client-side HTTP response.
@@ -36,26 +36,21 @@ import org.springframework.http.HttpStatus;
public interface ClientHttpResponse extends HttpInputMessage, Closeable { public interface ClientHttpResponse extends HttpInputMessage, Closeable {
/** /**
* Get the HTTP status code as an {@link HttpStatus} enum value. * Get the HTTP status code as an {@link HttpStatusCode}.
* <p>For status codes not supported by {@code HttpStatus}, use * @return the HTTP status as {@code HttpStatusCode} value (never {@code null})
* {@link #getRawStatusCode()} instead.
* @return the HTTP status as an HttpStatus enum value (never {@code null})
* @throws IOException in case of I/O errors * @throws IOException in case of I/O errors
* @throws IllegalArgumentException in case of an unknown HTTP status code
* @since #getRawStatusCode()
* @see HttpStatus#valueOf(int)
*/ */
HttpStatus getStatusCode() throws IOException; HttpStatusCode getStatusCode() throws IOException;
/** /**
* Get the HTTP status code (potentially non-standard and not * Get the HTTP status code as an integer.
* resolvable through the {@link HttpStatus} enum) as an integer.
* @return the HTTP status as an integer value * @return the HTTP status as an integer value
* @throws IOException in case of I/O errors * @throws IOException in case of I/O errors
* @since 3.1.1 * @since 3.1.1
* @see #getStatusCode() * @see #getStatusCode()
* @see HttpStatus#resolve(int) * @deprecated as of 6.0, in favor of {@link #getStatusCode()}
*/ */
@Deprecated
int getRawStatusCode() throws IOException; int getRawStatusCode() throws IOException;
/** /**

View File

@@ -26,6 +26,7 @@ import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils; import org.apache.http.util.EntityUtils;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatusCode;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.util.StreamUtils; import org.springframework.util.StreamUtils;
@@ -40,7 +41,7 @@ import org.springframework.util.StreamUtils;
* @since 3.1 * @since 3.1
* @see HttpComponentsClientHttpRequest#execute() * @see HttpComponentsClientHttpRequest#execute()
*/ */
final class HttpComponentsClientHttpResponse extends AbstractClientHttpResponse { final class HttpComponentsClientHttpResponse implements ClientHttpResponse {
private final HttpResponse httpResponse; private final HttpResponse httpResponse;
@@ -54,6 +55,12 @@ final class HttpComponentsClientHttpResponse extends AbstractClientHttpResponse
@Override @Override
public HttpStatusCode getStatusCode() throws IOException {
return HttpStatusCode.valueOf(this.httpResponse.getStatusLine().getStatusCode());
}
@Override
@Deprecated
public int getRawStatusCode() throws IOException { public int getRawStatusCode() throws IOException {
return this.httpResponse.getStatusLine().getStatusCode(); return this.httpResponse.getStatusLine().getStatusCode();
} }

View File

@@ -23,6 +23,7 @@ import okhttp3.Response;
import okhttp3.ResponseBody; import okhttp3.ResponseBody;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatusCode;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.StreamUtils; import org.springframework.util.StreamUtils;
@@ -35,7 +36,7 @@ import org.springframework.util.StreamUtils;
* @author Roy Clarkson * @author Roy Clarkson
* @since 4.3 * @since 4.3
*/ */
class OkHttp3ClientHttpResponse extends AbstractClientHttpResponse { class OkHttp3ClientHttpResponse implements ClientHttpResponse {
private final Response response; private final Response response;
@@ -50,6 +51,12 @@ class OkHttp3ClientHttpResponse extends AbstractClientHttpResponse {
@Override @Override
public HttpStatusCode getStatusCode() throws IOException {
return HttpStatusCode.valueOf(this.response.code());
}
@Override
@Deprecated
public int getRawStatusCode() { public int getRawStatusCode() {
return this.response.code(); return this.response.code();
} }

View File

@@ -21,6 +21,7 @@ import java.io.InputStream;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatusCode;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.util.StreamUtils; import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
@@ -34,7 +35,7 @@ import org.springframework.util.StringUtils;
* @author Brian Clozel * @author Brian Clozel
* @since 3.0 * @since 3.0
*/ */
final class SimpleClientHttpResponse extends AbstractClientHttpResponse { final class SimpleClientHttpResponse implements ClientHttpResponse {
private final HttpURLConnection connection; private final HttpURLConnection connection;
@@ -51,6 +52,12 @@ final class SimpleClientHttpResponse extends AbstractClientHttpResponse {
@Override @Override
public HttpStatusCode getStatusCode() throws IOException {
return HttpStatusCode.valueOf(this.connection.getResponseCode());
}
@Override
@Deprecated
public int getRawStatusCode() throws IOException { public int getRawStatusCode() throws IOException {
return this.connection.getResponseCode(); return this.connection.getResponseCode();
} }

View File

@@ -16,7 +16,7 @@
package org.springframework.http.client.reactive; package org.springframework.http.client.reactive;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode;
import org.springframework.http.ReactiveHttpInputMessage; import org.springframework.http.ReactiveHttpInputMessage;
import org.springframework.http.ResponseCookie; import org.springframework.http.ResponseCookie;
import org.springframework.util.MultiValueMap; import org.springframework.util.MultiValueMap;
@@ -41,22 +41,19 @@ public interface ClientHttpResponse extends ReactiveHttpInputMessage {
} }
/** /**
* Return the HTTP status code as an {@link HttpStatus} enum value. * Return the HTTP status code as an {@link HttpStatusCode}.
* @return the HTTP status as an HttpStatus enum value (never {@code null}) * @return the HTTP status as {@code HttpStatusCode} value (never {@code null})
* @throws IllegalArgumentException in case of an unknown HTTP status code
* @since #getRawStatusCode()
* @see HttpStatus#valueOf(int)
*/ */
HttpStatus getStatusCode(); HttpStatusCode getStatusCode();
/** /**
* Return the HTTP status code (potentially non-standard and not * Return the HTTP status code as an integer.
* resolvable through the {@link HttpStatus} enum) as an integer.
* @return the HTTP status as an integer value * @return the HTTP status as an integer value
* @since 5.0.6 * @since 5.0.6
* @see #getStatusCode() * @see #getStatusCode()
* @see HttpStatus#resolve(int) * @deprecated as of 6.0, in favor of {@link #getStatusCode()}
*/ */
@Deprecated
int getRawStatusCode(); int getRawStatusCode();
/** /**

View File

@@ -20,7 +20,7 @@ import reactor.core.publisher.Flux;
import org.springframework.core.io.buffer.DataBuffer; import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode;
import org.springframework.http.ResponseCookie; import org.springframework.http.ResponseCookie;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.MultiValueMap; import org.springframework.util.MultiValueMap;
@@ -56,11 +56,12 @@ public class ClientHttpResponseDecorator implements ClientHttpResponse {
} }
@Override @Override
public HttpStatus getStatusCode() { public HttpStatusCode getStatusCode() {
return this.delegate.getStatusCode(); return this.delegate.getStatusCode();
} }
@Override @Override
@Deprecated
public int getRawStatusCode() { public int getRawStatusCode() {
return this.delegate.getRawStatusCode(); return this.delegate.getRawStatusCode();
} }

View File

@@ -29,7 +29,7 @@ import reactor.core.publisher.Flux;
import org.springframework.core.io.buffer.DataBuffer; import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory; import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode;
import org.springframework.http.ResponseCookie; import org.springframework.http.ResponseCookie;
import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap; import org.springframework.util.MultiValueMap;
@@ -68,11 +68,12 @@ class HttpComponentsClientHttpResponse implements ClientHttpResponse {
@Override @Override
public HttpStatus getStatusCode() { public HttpStatusCode getStatusCode() {
return HttpStatus.valueOf(this.message.getHead().getCode()); return HttpStatusCode.valueOf(this.message.getHead().getCode());
} }
@Override @Override
@Deprecated
public int getRawStatusCode() { public int getRawStatusCode() {
return this.message.getHead().getCode(); return this.message.getHead().getCode();
} }

View File

@@ -35,7 +35,7 @@ import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory; import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils; import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode;
import org.springframework.http.ResponseCookie; import org.springframework.http.ResponseCookie;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
@@ -80,11 +80,12 @@ class JdkClientHttpResponse implements ClientHttpResponse {
@Override @Override
public HttpStatus getStatusCode() { public HttpStatusCode getStatusCode() {
return HttpStatus.valueOf(this.response.statusCode()); return HttpStatusCode.valueOf(this.response.statusCode());
} }
@Override @Override
@Deprecated
public int getRawStatusCode() { public int getRawStatusCode() {
return this.response.statusCode(); return this.response.statusCode();
} }

View File

@@ -27,7 +27,7 @@ import reactor.core.publisher.Flux;
import org.springframework.core.io.buffer.DataBuffer; import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode;
import org.springframework.http.ResponseCookie; import org.springframework.http.ResponseCookie;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
@@ -64,11 +64,12 @@ class JettyClientHttpResponse implements ClientHttpResponse {
@Override @Override
public HttpStatus getStatusCode() { public HttpStatusCode getStatusCode() {
return HttpStatus.valueOf(getRawStatusCode()); return HttpStatusCode.valueOf(this.reactiveResponse.getStatus());
} }
@Override @Override
@Deprecated
public int getRawStatusCode() { public int getRawStatusCode() {
return this.reactiveResponse.getStatus(); return this.reactiveResponse.getStatus();
} }

View File

@@ -34,7 +34,7 @@ import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.NettyDataBufferFactory; import org.springframework.core.io.buffer.NettyDataBufferFactory;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode;
import org.springframework.http.ResponseCookie; import org.springframework.http.ResponseCookie;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils; import org.springframework.util.ClassUtils;
@@ -135,11 +135,12 @@ class ReactorClientHttpResponse implements ClientHttpResponse {
} }
@Override @Override
public HttpStatus getStatusCode() { public HttpStatusCode getStatusCode() {
return HttpStatus.valueOf(getRawStatusCode()); return HttpStatusCode.valueOf(this.response.status().code());
} }
@Override @Override
@Deprecated
public int getRawStatusCode() { public int getRawStatusCode() {
return this.response.status().code(); return this.response.status().code();
} }

View File

@@ -20,7 +20,7 @@ import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**
@@ -52,7 +52,7 @@ public class DelegatingServerHttpResponse implements ServerHttpResponse {
} }
@Override @Override
public void setStatusCode(HttpStatus status) { public void setStatusCode(HttpStatusCode status) {
this.delegate.setStatusCode(status); this.delegate.setStatusCode(status);
} }

View File

@@ -21,7 +21,7 @@ import java.io.Flushable;
import java.io.IOException; import java.io.IOException;
import org.springframework.http.HttpOutputMessage; import org.springframework.http.HttpOutputMessage;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode;
/** /**
* Represents a server-side HTTP response. * Represents a server-side HTTP response.
@@ -35,7 +35,7 @@ public interface ServerHttpResponse extends HttpOutputMessage, Flushable, Closea
* Set the HTTP status code of the response. * Set the HTTP status code of the response.
* @param status the HTTP status as an HttpStatus enum value * @param status the HTTP status as an HttpStatus enum value
*/ */
void setStatusCode(HttpStatus status); void setStatusCode(HttpStatusCode status);
/** /**
* Ensure that the headers and the content of the response are written out. * Ensure that the headers and the content of the response are written out.

View File

@@ -26,7 +26,7 @@ import java.util.List;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
@@ -71,7 +71,7 @@ public class ServletServerHttpResponse implements ServerHttpResponse {
} }
@Override @Override
public void setStatusCode(HttpStatus status) { public void setStatusCode(HttpStatusCode status) {
Assert.notNull(status, "HttpStatus must not be null"); Assert.notNull(status, "HttpStatus must not be null");
this.servletResponse.setStatus(status.value()); this.servletResponse.setStatus(status.value());
} }

View File

@@ -31,7 +31,7 @@ import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils; import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.core.io.buffer.PooledDataBuffer; import org.springframework.core.io.buffer.PooledDataBuffer;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode;
import org.springframework.http.ResponseCookie; import org.springframework.http.ResponseCookie;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.util.Assert; import org.springframework.util.Assert;
@@ -62,7 +62,7 @@ public abstract class AbstractServerHttpResponse implements ServerHttpResponse {
private final DataBufferFactory dataBufferFactory; private final DataBufferFactory dataBufferFactory;
@Nullable @Nullable
private Integer statusCode; private HttpStatusCode statusCode;
private final HttpHeaders headers; private final HttpHeaders headers;
@@ -95,37 +95,32 @@ public abstract class AbstractServerHttpResponse implements ServerHttpResponse {
} }
@Override @Override
public boolean setStatusCode(@Nullable HttpStatus status) { public boolean setStatusCode(@Nullable HttpStatusCode status) {
if (this.state.get() == State.COMMITTED) { if (this.state.get() == State.COMMITTED) {
return false; return false;
} }
else { else {
this.statusCode = (status != null ? status.value() : null); this.statusCode = status;
return true; return true;
} }
} }
@Override @Override
@Nullable @Nullable
public HttpStatus getStatusCode() { public HttpStatusCode getStatusCode() {
return (this.statusCode != null ? HttpStatus.resolve(this.statusCode) : null); return this.statusCode;
} }
@Override @Override
public boolean setRawStatusCode(@Nullable Integer statusCode) { public boolean setRawStatusCode(@Nullable Integer statusCode) {
if (this.state.get() == State.COMMITTED) { return setStatusCode(statusCode != null ? HttpStatusCode.valueOf(statusCode) : null);
return false;
}
else {
this.statusCode = statusCode;
return true;
}
} }
@Override @Override
@Nullable @Nullable
@Deprecated
public Integer getRawStatusCode() { public Integer getRawStatusCode() {
return this.statusCode; return this.statusCode != null ? this.statusCode.value() : null;
} }
@Override @Override

View File

@@ -34,7 +34,7 @@ import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils; import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.core.io.buffer.NettyDataBufferFactory; import org.springframework.core.io.buffer.NettyDataBufferFactory;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode;
import org.springframework.http.ResponseCookie; import org.springframework.http.ResponseCookie;
import org.springframework.http.ZeroCopyHttpOutputMessage; import org.springframework.http.ZeroCopyHttpOutputMessage;
import org.springframework.util.Assert; import org.springframework.util.Assert;
@@ -68,12 +68,13 @@ class ReactorServerHttpResponse extends AbstractServerHttpResponse implements Ze
} }
@Override @Override
public HttpStatus getStatusCode() { public HttpStatusCode getStatusCode() {
HttpStatus status = super.getStatusCode(); HttpStatusCode status = super.getStatusCode();
return (status != null ? status : HttpStatus.resolve(this.response.status().code())); return (status != null ? status : HttpStatusCode.valueOf(this.response.status().code()));
} }
@Override @Override
@Deprecated
public Integer getRawStatusCode() { public Integer getRawStatusCode() {
Integer status = super.getRawStatusCode(); Integer status = super.getRawStatusCode();
return (status != null ? status : this.response.status().code()); return (status != null ? status : this.response.status().code());
@@ -81,9 +82,9 @@ class ReactorServerHttpResponse extends AbstractServerHttpResponse implements Ze
@Override @Override
protected void applyStatusCode() { protected void applyStatusCode() {
Integer status = super.getRawStatusCode(); HttpStatusCode status = super.getStatusCode();
if (status != null) { if (status != null) {
this.response.status(status); this.response.status(status.value());
} }
} }

View File

@@ -16,7 +16,7 @@
package org.springframework.http.server.reactive; package org.springframework.http.server.reactive;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode;
import org.springframework.http.ReactiveHttpOutputMessage; import org.springframework.http.ReactiveHttpOutputMessage;
import org.springframework.http.ResponseCookie; import org.springframework.http.ResponseCookie;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
@@ -34,42 +34,30 @@ public interface ServerHttpResponse extends ReactiveHttpOutputMessage {
/** /**
* Set the HTTP status code of the response. * Set the HTTP status code of the response.
* @param status the HTTP status as an {@link HttpStatus} enum value * @param status the HTTP status as an {@link HttpStatusCode} value
* @return {@code false} if the status code change wasn't processed because * @return {@code false} if the status code change wasn't processed because
* the HTTP response is committed, {@code true} if successfully set. * the HTTP response is committed, {@code true} if successfully set.
*/ */
boolean setStatusCode(@Nullable HttpStatus status); boolean setStatusCode(@Nullable HttpStatusCode status);
/** /**
* Return the status code that has been set, or otherwise fall back on the * 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 * status of the response from the underlying server. The return value may
* be {@code null} if the status code value is outside the * be {@code null} if there is no default value from the
* {@link HttpStatus} enum range, or if there is no default value from the
* underlying server. * underlying server.
*/ */
@Nullable @Nullable
HttpStatus getStatusCode(); HttpStatusCode getStatusCode();
/** /**
* Set the HTTP status code to the given value (potentially non-standard and * Set the HTTP status code to the given value as an integer.
* not resolvable through the {@link HttpStatus} enum) as an integer.
* @param value the status code value * @param value the status code value
* @return {@code false} if the status code change wasn't processed because * @return {@code false} if the status code change wasn't processed because
* the HTTP response is committed, {@code true} if successfully set. * the HTTP response is committed, {@code true} if successfully set.
* @since 5.2.4 * @since 5.2.4
*/ */
default boolean setRawStatusCode(@Nullable Integer value) { default boolean setRawStatusCode(@Nullable Integer value) {
if (value == null) { return setStatusCode(value != null ? HttpStatusCode.valueOf(value) : null);
return setStatusCode(null);
}
else {
HttpStatus httpStatus = HttpStatus.resolve(value);
if (httpStatus == null) {
throw new IllegalStateException(
"Unresolvable HttpStatus for general ServerHttpResponse: " + value);
}
return setStatusCode(httpStatus);
}
} }
/** /**
@@ -77,10 +65,12 @@ public interface ServerHttpResponse extends ReactiveHttpOutputMessage {
* status of the response from the underlying server. The return value may * 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. * be {@code null} if there is no default value from the underlying server.
* @since 5.2.4 * @since 5.2.4
* @deprecated as of 6.0, in favor of {@link #getStatusCode()}
*/ */
@Nullable @Nullable
@Deprecated
default Integer getRawStatusCode() { default Integer getRawStatusCode() {
HttpStatus httpStatus = getStatusCode(); HttpStatusCode httpStatus = getStatusCode();
return (httpStatus != null ? httpStatus.value() : null); return (httpStatus != null ? httpStatus.value() : null);
} }

View File

@@ -24,7 +24,7 @@ import reactor.core.publisher.Mono;
import org.springframework.core.io.buffer.DataBuffer; import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory; import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode;
import org.springframework.http.ResponseCookie; import org.springframework.http.ResponseCookie;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.util.Assert; import org.springframework.util.Assert;
@@ -56,12 +56,12 @@ public class ServerHttpResponseDecorator implements ServerHttpResponse {
// ServerHttpResponse delegation methods... // ServerHttpResponse delegation methods...
@Override @Override
public boolean setStatusCode(@Nullable HttpStatus status) { public boolean setStatusCode(@Nullable HttpStatusCode status) {
return getDelegate().setStatusCode(status); return getDelegate().setStatusCode(status);
} }
@Override @Override
public HttpStatus getStatusCode() { public HttpStatusCode getStatusCode() {
return getDelegate().getStatusCode(); return getDelegate().getStatusCode();
} }
@@ -71,6 +71,7 @@ public class ServerHttpResponseDecorator implements ServerHttpResponse {
} }
@Override @Override
@Deprecated
public Integer getRawStatusCode() { public Integer getRawStatusCode() {
return getDelegate().getRawStatusCode(); return getDelegate().getRawStatusCode();
} }

View File

@@ -34,7 +34,7 @@ import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory; import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils; import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.ResponseCookie; import org.springframework.http.ResponseCookie;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
@@ -101,12 +101,13 @@ class ServletServerHttpResponse extends AbstractListenerServerHttpResponse {
} }
@Override @Override
public HttpStatus getStatusCode() { public HttpStatusCode getStatusCode() {
HttpStatus status = super.getStatusCode(); HttpStatusCode status = super.getStatusCode();
return (status != null ? status : HttpStatus.resolve(this.response.getStatus())); return (status != null ? status : HttpStatusCode.valueOf(this.response.getStatus()));
} }
@Override @Override
@Deprecated
public Integer getRawStatusCode() { public Integer getRawStatusCode() {
Integer status = super.getRawStatusCode(); Integer status = super.getRawStatusCode();
return (status != null ? status : this.response.getStatus()); return (status != null ? status : this.response.getStatus());
@@ -114,9 +115,9 @@ class ServletServerHttpResponse extends AbstractListenerServerHttpResponse {
@Override @Override
protected void applyStatusCode() { protected void applyStatusCode() {
Integer status = super.getRawStatusCode(); HttpStatusCode status = super.getStatusCode();
if (status != null) { if (status != null) {
this.response.setStatus(status); this.response.setStatus(status.value());
} }
} }

View File

@@ -35,7 +35,7 @@ import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory; import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils; import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode;
import org.springframework.http.ResponseCookie; import org.springframework.http.ResponseCookie;
import org.springframework.http.ZeroCopyHttpOutputMessage; import org.springframework.http.ZeroCopyHttpOutputMessage;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
@@ -81,12 +81,13 @@ class UndertowServerHttpResponse extends AbstractListenerServerHttpResponse impl
} }
@Override @Override
public HttpStatus getStatusCode() { public HttpStatusCode getStatusCode() {
HttpStatus status = super.getStatusCode(); HttpStatusCode status = super.getStatusCode();
return (status != null ? status : HttpStatus.resolve(this.exchange.getStatusCode())); return (status != null ? status : HttpStatusCode.valueOf(this.exchange.getStatusCode()));
} }
@Override @Override
@Deprecated
public Integer getRawStatusCode() { public Integer getRawStatusCode() {
Integer status = super.getRawStatusCode(); Integer status = super.getRawStatusCode();
return (status != null ? status : this.exchange.getStatusCode()); return (status != null ? status : this.exchange.getStatusCode());
@@ -94,9 +95,9 @@ class UndertowServerHttpResponse extends AbstractListenerServerHttpResponse impl
@Override @Override
protected void applyStatusCode() { protected void applyStatusCode() {
Integer status = super.getRawStatusCode(); HttpStatusCode status = super.getStatusCode();
if (status != null) { if (status != null) {
this.exchange.setStatusCode(status); this.exchange.setStatusCode(status.value());
} }
} }

View File

@@ -17,7 +17,7 @@
package org.springframework.web; package org.springframework.web;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode;
import org.springframework.http.ProblemDetail; import org.springframework.http.ProblemDetail;
@@ -41,18 +41,9 @@ import org.springframework.http.ProblemDetail;
public interface ErrorResponse { public interface ErrorResponse {
/** /**
* Return the HTTP status to use for the response. * Return the HTTP status code to use for the response.
* @throws IllegalArgumentException for an unknown HTTP status code
*/ */
default HttpStatus getStatus() { HttpStatusCode getStatusCode();
return HttpStatus.valueOf(getRawStatusCode());
}
/**
* Return the HTTP status value for the response, potentially non-standard
* and not resolvable via {@link HttpStatus}.
*/
int getRawStatusCode();
/** /**
* Return headers to use for the response. * Return headers to use for the response.

View File

@@ -16,13 +16,12 @@
package org.springframework.web; package org.springframework.web;
import java.net.URI; import java.net.URI;
import org.springframework.core.NestedExceptionUtils; import org.springframework.core.NestedExceptionUtils;
import org.springframework.core.NestedRuntimeException; import org.springframework.core.NestedRuntimeException;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode;
import org.springframework.http.ProblemDetail; import org.springframework.http.ProblemDetail;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
@@ -43,7 +42,7 @@ import org.springframework.lang.Nullable;
@SuppressWarnings("serial") @SuppressWarnings("serial")
public class ErrorResponseException extends NestedRuntimeException implements ErrorResponse { public class ErrorResponseException extends NestedRuntimeException implements ErrorResponse {
private final int status; private final HttpStatusCode status;
private final HttpHeaders headers = new HttpHeaders(); private final HttpHeaders headers = new HttpHeaders();
@@ -51,40 +50,31 @@ public class ErrorResponseException extends NestedRuntimeException implements Er
/** /**
* Constructor with a well-known {@link HttpStatus}. * Constructor with a {@link HttpStatusCode}.
*/ */
public ErrorResponseException(HttpStatus status) { public ErrorResponseException(HttpStatusCode status) {
this(status, null); this(status, null);
} }
/** /**
* Constructor with a well-known {@link HttpStatus} and an optional cause. * Constructor with a {@link HttpStatusCode} and an optional cause.
*/ */
public ErrorResponseException(HttpStatus status, @Nullable Throwable cause) { public ErrorResponseException(HttpStatusCode status, @Nullable Throwable cause) {
this(status.value(), cause); this(status, ProblemDetail.forStatus(status), cause);
}
/**
* Constructor that accepts any status value, possibly not resolvable as an
* {@link HttpStatus} enum, and an optional cause.
*/
public ErrorResponseException(int status, @Nullable Throwable cause) {
this(status, ProblemDetail.forRawStatusCode(status), cause);
} }
/** /**
* Constructor with a given {@link ProblemDetail} instance, possibly a * Constructor with a given {@link ProblemDetail} instance, possibly a
* subclass of {@code ProblemDetail} with extended fields. * subclass of {@code ProblemDetail} with extended fields.
*/ */
public ErrorResponseException(int status, ProblemDetail body, @Nullable Throwable cause) { public ErrorResponseException(HttpStatusCode status, ProblemDetail body, @Nullable Throwable cause) {
super(null, cause); super(null, cause);
this.status = status; this.status = status;
this.body = body; this.body = body;
} }
@Override @Override
public int getRawStatusCode() { public HttpStatusCode getStatusCode() {
return this.status; return this.status;
} }
@@ -147,9 +137,7 @@ public class ErrorResponseException extends NestedRuntimeException implements Er
@Override @Override
public String getMessage() { public String getMessage() {
HttpStatus httpStatus = HttpStatus.resolve(this.status); String message = this.status + (!this.headers.isEmpty() ? ", headers=" + this.headers : "") + ", " + this.body;
String message = (httpStatus != null ? httpStatus : String.valueOf(this.status)) +
(!this.headers.isEmpty() ? ", headers=" + this.headers : "") + ", " + this.body;
return NestedExceptionUtils.buildMessage(message, getCause()); return NestedExceptionUtils.buildMessage(message, getCause());
} }

View File

@@ -35,7 +35,7 @@ public abstract class HttpMediaTypeException extends ServletException implements
private final List<MediaType> supportedMediaTypes; private final List<MediaType> supportedMediaTypes;
private final ProblemDetail body = ProblemDetail.forRawStatusCode(getRawStatusCode()); private final ProblemDetail body = ProblemDetail.forStatus(getStatusCode());
/** /**

View File

@@ -21,6 +21,7 @@ import java.util.stream.Collectors;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
@@ -55,8 +56,8 @@ public class HttpMediaTypeNotAcceptableException extends HttpMediaTypeException
@Override @Override
public int getRawStatusCode() { public HttpStatusCode getStatusCode() {
return HttpStatus.NOT_ACCEPTABLE.value(); return HttpStatus.NOT_ACCEPTABLE;
} }
@Override @Override

View File

@@ -21,6 +21,7 @@ import java.util.List;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
@@ -104,8 +105,8 @@ public class HttpMediaTypeNotSupportedException extends HttpMediaTypeException {
} }
@Override @Override
public int getRawStatusCode() { public HttpStatusCode getStatusCode() {
return HttpStatus.UNSUPPORTED_MEDIA_TYPE.value(); return HttpStatus.UNSUPPORTED_MEDIA_TYPE;
} }
@Override @Override

View File

@@ -25,6 +25,7 @@ import jakarta.servlet.ServletException;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.ProblemDetail; import org.springframework.http.ProblemDetail;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils; import org.springframework.util.ObjectUtils;
@@ -95,7 +96,7 @@ public class HttpRequestMethodNotSupportedException extends ServletException imp
this.supportedMethods = supportedMethods; this.supportedMethods = supportedMethods;
String detail = "Method '" + method + "' is not supported."; String detail = "Method '" + method + "' is not supported.";
this.body = ProblemDetail.forRawStatusCode(getRawStatusCode()).withDetail(detail); this.body = ProblemDetail.forStatus(getStatusCode()).withDetail(detail);
} }
@@ -133,8 +134,8 @@ public class HttpRequestMethodNotSupportedException extends ServletException imp
} }
@Override @Override
public int getRawStatusCode() { public HttpStatusCode getStatusCode() {
return HttpStatus.METHOD_NOT_ALLOWED.value(); return HttpStatus.METHOD_NOT_ALLOWED;
} }
@Override @Override

View File

@@ -18,6 +18,7 @@ package org.springframework.web.bind;
import org.springframework.core.MethodParameter; import org.springframework.core.MethodParameter;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.ProblemDetail; import org.springframework.http.ProblemDetail;
import org.springframework.validation.BindException; import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult; import org.springframework.validation.BindingResult;
@@ -48,13 +49,12 @@ public class MethodArgumentNotValidException extends BindException implements Er
public MethodArgumentNotValidException(MethodParameter parameter, BindingResult bindingResult) { public MethodArgumentNotValidException(MethodParameter parameter, BindingResult bindingResult) {
super(bindingResult); super(bindingResult);
this.parameter = parameter; this.parameter = parameter;
this.body = ProblemDetail.forRawStatusCode(getRawStatusCode()).withDetail("Invalid request content."); this.body = ProblemDetail.forStatus(getStatusCode()).withDetail("Invalid request content.");
} }
@Override @Override
public int getRawStatusCode() { public HttpStatusCode getStatusCode() {
return HttpStatus.BAD_REQUEST.value(); return HttpStatus.BAD_REQUEST;
} }
@Override @Override

View File

@@ -18,6 +18,7 @@ package org.springframework.web.bind;
import org.springframework.core.MethodParameter; import org.springframework.core.MethodParameter;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
/** /**
* {@link ServletRequestBindingException} subclass that indicates that a path * {@link ServletRequestBindingException} subclass that indicates that a path
@@ -85,10 +86,9 @@ public class MissingPathVariableException extends MissingRequestValueException {
return this.parameter; return this.parameter;
} }
@Override @Override
public int getRawStatusCode() { public HttpStatusCode getStatusCode() {
return HttpStatus.INTERNAL_SERVER_ERROR.value(); return HttpStatus.INTERNAL_SERVER_ERROR;
} }
} }

View File

@@ -17,6 +17,7 @@
package org.springframework.web.bind; package org.springframework.web.bind;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.ProblemDetail; import org.springframework.http.ProblemDetail;
import org.springframework.web.ErrorResponse; import org.springframework.web.ErrorResponse;
import org.springframework.web.util.NestedServletException; import org.springframework.web.util.NestedServletException;
@@ -35,7 +36,7 @@ import org.springframework.web.util.NestedServletException;
@SuppressWarnings("serial") @SuppressWarnings("serial")
public class ServletRequestBindingException extends NestedServletException implements ErrorResponse { public class ServletRequestBindingException extends NestedServletException implements ErrorResponse {
private final ProblemDetail body = ProblemDetail.forRawStatusCode(getRawStatusCode()); private final ProblemDetail body = ProblemDetail.forStatus(getStatusCode());
/** /**
@@ -55,10 +56,9 @@ public class ServletRequestBindingException extends NestedServletException imple
super(msg, cause); super(msg, cause);
} }
@Override @Override
public int getRawStatusCode() { public HttpStatusCode getStatusCode() {
return HttpStatus.BAD_REQUEST.value(); return HttpStatus.BAD_REQUEST;
} }
@Override @Override

View File

@@ -23,6 +23,7 @@ import java.nio.charset.StandardCharsets;
import org.springframework.core.log.LogFormatUtils; import org.springframework.core.log.LogFormatUtils;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpResponse; import org.springframework.http.client.ClientHttpResponse;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
@@ -35,7 +36,7 @@ import org.springframework.util.ObjectUtils;
* <p>This error handler checks for the status code on the * <p>This error handler checks for the status code on the
* {@link ClientHttpResponse}. Any code in the 4xx or 5xx series is considered * {@link ClientHttpResponse}. Any code in the 4xx or 5xx series is considered
* to be an error. This behavior can be changed by overriding * to be an error. This behavior can be changed by overriding
* {@link #hasError(HttpStatus)}. Unknown status codes will be ignored by * {@link #hasError(HttpStatusCode)}. Unknown status codes will be ignored by
* {@link #hasError(ClientHttpResponse)}. * {@link #hasError(ClientHttpResponse)}.
* *
* <p>See {@link #handleError(ClientHttpResponse)} for more details on specific * <p>See {@link #handleError(ClientHttpResponse)} for more details on specific
@@ -50,28 +51,25 @@ import org.springframework.util.ObjectUtils;
public class DefaultResponseErrorHandler implements ResponseErrorHandler { public class DefaultResponseErrorHandler implements ResponseErrorHandler {
/** /**
* Delegates to {@link #hasError(HttpStatus)} (for a standard status enum value) or * Delegates to {@link #hasError(HttpStatusCode)} with the response status code.
* {@link #hasError(int)} (for an unknown status code) with the response status code. * @see ClientHttpResponse#getStatusCode()
* @see ClientHttpResponse#getRawStatusCode() * @see #hasError(HttpStatusCode)
* @see #hasError(HttpStatus)
* @see #hasError(int)
*/ */
@Override @Override
public boolean hasError(ClientHttpResponse response) throws IOException { public boolean hasError(ClientHttpResponse response) throws IOException {
int rawStatusCode = response.getRawStatusCode(); HttpStatusCode statusCode = response.getStatusCode();
HttpStatus statusCode = HttpStatus.resolve(rawStatusCode); return hasError(statusCode);
return (statusCode != null ? hasError(statusCode) : hasError(rawStatusCode));
} }
/** /**
* Template method called from {@link #hasError(ClientHttpResponse)}. * Template method called from {@link #hasError(ClientHttpResponse)}.
* <p>The default implementation checks {@link HttpStatus#isError()}. * <p>The default implementation checks {@link HttpStatusCode#isError()}.
* Can be overridden in subclasses. * Can be overridden in subclasses.
* @param statusCode the HTTP status code as enum value * @param statusCode the HTTP status code
* @return {@code true} if the response indicates an error; {@code false} otherwise * @return {@code true} if the response indicates an error; {@code false} otherwise
* @see HttpStatus#isError() * @see HttpStatusCode#isError()
*/ */
protected boolean hasError(HttpStatus statusCode) { protected boolean hasError(HttpStatusCode statusCode) {
return statusCode.isError(); return statusCode.isError();
} }
@@ -81,14 +79,16 @@ public class DefaultResponseErrorHandler implements ResponseErrorHandler {
* {@link org.springframework.http.HttpStatus.Series#CLIENT_ERROR CLIENT_ERROR} or * {@link org.springframework.http.HttpStatus.Series#CLIENT_ERROR CLIENT_ERROR} or
* {@link org.springframework.http.HttpStatus.Series#SERVER_ERROR SERVER_ERROR}. * {@link org.springframework.http.HttpStatus.Series#SERVER_ERROR SERVER_ERROR}.
* Can be overridden in subclasses. * Can be overridden in subclasses.
* @param unknownStatusCode the HTTP status code as raw value * @param statusCode the HTTP status code as raw value
* @return {@code true} if the response indicates an error; {@code false} otherwise * @return {@code true} if the response indicates an error; {@code false} otherwise
* @since 4.3.21 * @since 4.3.21
* @see org.springframework.http.HttpStatus.Series#CLIENT_ERROR * @see org.springframework.http.HttpStatus.Series#CLIENT_ERROR
* @see org.springframework.http.HttpStatus.Series#SERVER_ERROR * @see org.springframework.http.HttpStatus.Series#SERVER_ERROR
* @deprecated in favor of {@link #hasError(HttpStatusCode)}
*/ */
protected boolean hasError(int unknownStatusCode) { @Deprecated
HttpStatus.Series series = HttpStatus.Series.resolve(unknownStatusCode); protected boolean hasError(int statusCode) {
HttpStatus.Series series = HttpStatus.Series.resolve(statusCode);
return (series == HttpStatus.Series.CLIENT_ERROR || series == HttpStatus.Series.SERVER_ERROR); return (series == HttpStatus.Series.CLIENT_ERROR || series == HttpStatus.Series.SERVER_ERROR);
} }
@@ -106,19 +106,11 @@ public class DefaultResponseErrorHandler implements ResponseErrorHandler {
* {@link HttpStatus} enum range. * {@link HttpStatus} enum range.
* </ul> * </ul>
* @throws UnknownHttpStatusCodeException in case of an unresolvable status code * @throws UnknownHttpStatusCodeException in case of an unresolvable status code
* @see #handleError(ClientHttpResponse, HttpStatus) * @see #handleError(ClientHttpResponse, HttpStatusCode)
*/ */
@Override @Override
public void handleError(ClientHttpResponse response) throws IOException { public void handleError(ClientHttpResponse response) throws IOException {
HttpStatus statusCode = HttpStatus.resolve(response.getRawStatusCode()); HttpStatusCode statusCode = response.getStatusCode();
if (statusCode == null) {
byte[] body = getResponseBody(response);
String message = getErrorMessage(response.getRawStatusCode(),
response.getStatusText(), body, getCharset(response));
throw new UnknownHttpStatusCodeException(message,
response.getRawStatusCode(), response.getStatusText(),
response.getHeaders(), body, getCharset(response));
}
handleError(response, statusCode); handleError(response, statusCode);
} }
@@ -156,20 +148,21 @@ public class DefaultResponseErrorHandler implements ResponseErrorHandler {
* @see HttpClientErrorException#create * @see HttpClientErrorException#create
* @see HttpServerErrorException#create * @see HttpServerErrorException#create
*/ */
protected void handleError(ClientHttpResponse response, HttpStatus statusCode) throws IOException { protected void handleError(ClientHttpResponse response, HttpStatusCode statusCode) throws IOException {
String statusText = response.getStatusText(); String statusText = response.getStatusText();
HttpHeaders headers = response.getHeaders(); HttpHeaders headers = response.getHeaders();
byte[] body = getResponseBody(response); byte[] body = getResponseBody(response);
Charset charset = getCharset(response); Charset charset = getCharset(response);
String message = getErrorMessage(statusCode.value(), statusText, body, charset); String message = getErrorMessage(statusCode.value(), statusText, body, charset);
switch (statusCode.series()) { if (statusCode.is4xxClientError()) {
case CLIENT_ERROR -> throw HttpClientErrorException.create(message, statusCode, statusText, headers, body, charset);
throw HttpClientErrorException.create(message, statusCode, statusText, headers, body, charset); }
case SERVER_ERROR -> else if (statusCode.is5xxServerError()) {
throw HttpServerErrorException.create(message, statusCode, statusText, headers, body, charset); throw HttpServerErrorException.create(message, statusCode, statusText, headers, body, charset);
default -> }
throw new UnknownHttpStatusCodeException(message, statusCode.value(), statusText, headers, body, charset); else {
throw new UnknownHttpStatusCodeException(message, statusCode.value(), statusText, headers, body, charset);
} }
} }

View File

@@ -23,6 +23,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.client.ClientHttpResponse; import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
@@ -59,7 +60,7 @@ public class ExtractingResponseErrorHandler extends DefaultResponseErrorHandler
private List<HttpMessageConverter<?>> messageConverters = Collections.emptyList(); private List<HttpMessageConverter<?>> messageConverters = Collections.emptyList();
private final Map<HttpStatus, Class<? extends RestClientException>> statusMapping = new LinkedHashMap<>(); private final Map<HttpStatusCode, Class<? extends RestClientException>> statusMapping = new LinkedHashMap<>();
private final Map<HttpStatus.Series, Class<? extends RestClientException>> seriesMapping = new LinkedHashMap<>(); private final Map<HttpStatus.Series, Class<? extends RestClientException>> seriesMapping = new LinkedHashMap<>();
@@ -97,7 +98,7 @@ public class ExtractingResponseErrorHandler extends DefaultResponseErrorHandler
* {@linkplain #setMessageConverters(List) configured message converters} to convert the * {@linkplain #setMessageConverters(List) configured message converters} to convert the
* response into the mapped subclass of {@link RestClientException}. * response into the mapped subclass of {@link RestClientException}.
*/ */
public void setStatusMapping(Map<HttpStatus, Class<? extends RestClientException>> statusMapping) { public void setStatusMapping(Map<HttpStatusCode, Class<? extends RestClientException>> statusMapping) {
if (!CollectionUtils.isEmpty(statusMapping)) { if (!CollectionUtils.isEmpty(statusMapping)) {
this.statusMapping.putAll(statusMapping); this.statusMapping.putAll(statusMapping);
} }
@@ -120,12 +121,13 @@ public class ExtractingResponseErrorHandler extends DefaultResponseErrorHandler
@Override @Override
protected boolean hasError(HttpStatus statusCode) { protected boolean hasError(HttpStatusCode statusCode) {
if (this.statusMapping.containsKey(statusCode)) { if (this.statusMapping.containsKey(statusCode)) {
return this.statusMapping.get(statusCode) != null; return this.statusMapping.get(statusCode) != null;
} }
else if (this.seriesMapping.containsKey(statusCode.series())) { HttpStatus.Series series = HttpStatus.Series.resolve(statusCode.value());
return this.seriesMapping.get(statusCode.series()) != null; if (this.seriesMapping.containsKey(series)) {
return this.seriesMapping.get(series) != null;
} }
else { else {
return super.hasError(statusCode); return super.hasError(statusCode);
@@ -133,12 +135,13 @@ public class ExtractingResponseErrorHandler extends DefaultResponseErrorHandler
} }
@Override @Override
public void handleError(ClientHttpResponse response, HttpStatus statusCode) throws IOException { public void handleError(ClientHttpResponse response, HttpStatusCode statusCode) throws IOException {
if (this.statusMapping.containsKey(statusCode)) { if (this.statusMapping.containsKey(statusCode)) {
extract(this.statusMapping.get(statusCode), response); extract(this.statusMapping.get(statusCode), response);
} }
else if (this.seriesMapping.containsKey(statusCode.series())) { HttpStatus.Series series = HttpStatus.Series.resolve(statusCode.value());
extract(this.seriesMapping.get(statusCode.series()), response); if (this.seriesMapping.containsKey(series)) {
extract(this.seriesMapping.get(series), response);
} }
else { else {
super.handleError(response, statusCode); super.handleError(response, statusCode);

View File

@@ -20,6 +20,7 @@ import java.nio.charset.Charset;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
/** /**
@@ -37,14 +38,14 @@ public class HttpClientErrorException extends HttpStatusCodeException {
/** /**
* Constructor with a status code only. * Constructor with a status code only.
*/ */
public HttpClientErrorException(HttpStatus statusCode) { public HttpClientErrorException(HttpStatusCode statusCode) {
super(statusCode); super(statusCode);
} }
/** /**
* Constructor with a status code and status text. * Constructor with a status code and status text.
*/ */
public HttpClientErrorException(HttpStatus statusCode, String statusText) { public HttpClientErrorException(HttpStatusCode statusCode, String statusText) {
super(statusCode, statusText); super(statusCode, statusText);
} }
@@ -52,7 +53,7 @@ public class HttpClientErrorException extends HttpStatusCodeException {
* Constructor with a status code and status text, and content. * Constructor with a status code and status text, and content.
*/ */
public HttpClientErrorException( public HttpClientErrorException(
HttpStatus statusCode, String statusText, @Nullable byte[] body, @Nullable Charset responseCharset) { HttpStatusCode statusCode, String statusText, @Nullable byte[] body, @Nullable Charset responseCharset) {
super(statusCode, statusText, body, responseCharset); super(statusCode, statusText, body, responseCharset);
} }
@@ -60,7 +61,7 @@ public class HttpClientErrorException extends HttpStatusCodeException {
/** /**
* Constructor with a status code and status text, headers, and content. * Constructor with a status code and status text, headers, and content.
*/ */
public HttpClientErrorException(HttpStatus statusCode, String statusText, public HttpClientErrorException(HttpStatusCode statusCode, String statusText,
@Nullable HttpHeaders headers, @Nullable byte[] body, @Nullable Charset responseCharset) { @Nullable HttpHeaders headers, @Nullable byte[] body, @Nullable Charset responseCharset) {
super(statusCode, statusText, headers, body, responseCharset); super(statusCode, statusText, headers, body, responseCharset);
@@ -71,7 +72,7 @@ public class HttpClientErrorException extends HttpStatusCodeException {
* and an prepared message. * and an prepared message.
* @since 5.2.2 * @since 5.2.2
*/ */
public HttpClientErrorException(String message, HttpStatus statusCode, String statusText, public HttpClientErrorException(String message, HttpStatusCode statusCode, String statusText,
@Nullable HttpHeaders headers, @Nullable byte[] body, @Nullable Charset responseCharset) { @Nullable HttpHeaders headers, @Nullable byte[] body, @Nullable Charset responseCharset) {
super(message, statusCode, statusText, headers, body, responseCharset); super(message, statusCode, statusText, headers, body, responseCharset);
@@ -83,68 +84,64 @@ public class HttpClientErrorException extends HttpStatusCodeException {
* @since 5.1 * @since 5.1
*/ */
public static HttpClientErrorException create( public static HttpClientErrorException create(
HttpStatus statusCode, String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) { HttpStatusCode statusCode, String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
return create(null, statusCode, statusText, headers, body, charset); return create(null, statusCode, statusText, headers, body, charset);
} }
/** /**
* Variant of {@link #create(HttpStatus, String, HttpHeaders, byte[], Charset)} * Variant of {@link #create(HttpStatusCode, String, HttpHeaders, byte[], Charset)}
* with an optional prepared message. * with an optional prepared message.
* @since 5.2.2 * @since 5.2.2
*/ */
public static HttpClientErrorException create(@Nullable String message, HttpStatus statusCode, public static HttpClientErrorException create(@Nullable String message, HttpStatusCode statusCode,
String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) { String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
switch (statusCode) { if (statusCode instanceof HttpStatus status) {
case BAD_REQUEST: return switch (status) {
return message != null ? case BAD_REQUEST -> message != null ?
new HttpClientErrorException.BadRequest(message, statusText, headers, body, charset) : new BadRequest(message, statusText, headers, body, charset) :
new HttpClientErrorException.BadRequest(statusText, headers, body, charset); new BadRequest(statusText, headers, body, charset);
case UNAUTHORIZED: case UNAUTHORIZED -> message != null ?
return message != null ? new Unauthorized(message, statusText, headers, body, charset) :
new HttpClientErrorException.Unauthorized(message, statusText, headers, body, charset) : new Unauthorized(statusText, headers, body, charset);
new HttpClientErrorException.Unauthorized(statusText, headers, body, charset); case FORBIDDEN -> message != null ?
case FORBIDDEN: new Forbidden(message, statusText, headers, body, charset) :
return message != null ? new Forbidden(statusText, headers, body, charset);
new HttpClientErrorException.Forbidden(message, statusText, headers, body, charset) : case NOT_FOUND -> message != null ?
new HttpClientErrorException.Forbidden(statusText, headers, body, charset); new NotFound(message, statusText, headers, body, charset) :
case NOT_FOUND: new NotFound(statusText, headers, body, charset);
return message != null ? case METHOD_NOT_ALLOWED -> message != null ?
new HttpClientErrorException.NotFound(message, statusText, headers, body, charset) : new MethodNotAllowed(message, statusText, headers, body, charset) :
new HttpClientErrorException.NotFound(statusText, headers, body, charset); new MethodNotAllowed(statusText, headers, body, charset);
case METHOD_NOT_ALLOWED: case NOT_ACCEPTABLE -> message != null ?
return message != null ? new NotAcceptable(message, statusText, headers, body, charset) :
new HttpClientErrorException.MethodNotAllowed(message, statusText, headers, body, charset) : new NotAcceptable(statusText, headers, body, charset);
new HttpClientErrorException.MethodNotAllowed(statusText, headers, body, charset); case CONFLICT -> message != null ?
case NOT_ACCEPTABLE: new Conflict(message, statusText, headers, body, charset) :
return message != null ? new Conflict(statusText, headers, body, charset);
new HttpClientErrorException.NotAcceptable(message, statusText, headers, body, charset) : case GONE -> message != null ?
new HttpClientErrorException.NotAcceptable(statusText, headers, body, charset); new Gone(message, statusText, headers, body, charset) :
case CONFLICT: new Gone(statusText, headers, body, charset);
return message != null ? case UNSUPPORTED_MEDIA_TYPE -> message != null ?
new HttpClientErrorException.Conflict(message, statusText, headers, body, charset) : new UnsupportedMediaType(message, statusText, headers, body, charset) :
new HttpClientErrorException.Conflict(statusText, headers, body, charset); new UnsupportedMediaType(statusText, headers, body, charset);
case GONE: case TOO_MANY_REQUESTS -> message != null ?
return message != null ? new TooManyRequests(message, statusText, headers, body, charset) :
new HttpClientErrorException.Gone(message, statusText, headers, body, charset) : new TooManyRequests(statusText, headers, body, charset);
new HttpClientErrorException.Gone(statusText, headers, body, charset); case UNPROCESSABLE_ENTITY -> message != null ?
case UNSUPPORTED_MEDIA_TYPE: new UnprocessableEntity(message, statusText, headers, body, charset) :
return message != null ? new UnprocessableEntity(statusText, headers, body, charset);
new HttpClientErrorException.UnsupportedMediaType(message, statusText, headers, body, charset) : default -> message != null ?
new HttpClientErrorException.UnsupportedMediaType(statusText, headers, body, charset);
case TOO_MANY_REQUESTS:
return message != null ?
new HttpClientErrorException.TooManyRequests(message, statusText, headers, body, charset) :
new HttpClientErrorException.TooManyRequests(statusText, headers, body, charset);
case UNPROCESSABLE_ENTITY:
return message != null ?
new HttpClientErrorException.UnprocessableEntity(message, statusText, headers, body, charset) :
new HttpClientErrorException.UnprocessableEntity(statusText, headers, body, charset);
default:
return message != null ?
new HttpClientErrorException(message, statusCode, statusText, headers, body, charset) : new HttpClientErrorException(message, statusCode, statusText, headers, body, charset) :
new HttpClientErrorException(statusCode, statusText, headers, body, charset); new HttpClientErrorException(statusCode, statusText, headers, body, charset);
};
}
if (message != null) {
return new HttpClientErrorException(message, statusCode, statusText, headers, body, charset);
}
else {
return new HttpClientErrorException(statusCode, statusText, headers, body, charset);
} }
} }

View File

@@ -122,7 +122,7 @@ public class HttpMessageConverterExtractor<T> implements ResponseExtractor<T> {
} }
throw new UnknownContentTypeException(this.responseType, contentType, throw new UnknownContentTypeException(this.responseType, contentType,
responseWrapper.getRawStatusCode(), responseWrapper.getStatusText(), responseWrapper.getStatusCode(), responseWrapper.getStatusText(),
responseWrapper.getHeaders(), getResponseBody(responseWrapper)); responseWrapper.getHeaders(), getResponseBody(responseWrapper));
} }

View File

@@ -20,6 +20,7 @@ import java.nio.charset.Charset;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
/** /**
@@ -37,14 +38,14 @@ public class HttpServerErrorException extends HttpStatusCodeException {
/** /**
* Constructor with a status code only. * Constructor with a status code only.
*/ */
public HttpServerErrorException(HttpStatus statusCode) { public HttpServerErrorException(HttpStatusCode statusCode) {
super(statusCode); super(statusCode);
} }
/** /**
* Constructor with a status code and status text. * Constructor with a status code and status text.
*/ */
public HttpServerErrorException(HttpStatus statusCode, String statusText) { public HttpServerErrorException(HttpStatusCode statusCode, String statusText) {
super(statusCode, statusText); super(statusCode, statusText);
} }
@@ -52,7 +53,7 @@ public class HttpServerErrorException extends HttpStatusCodeException {
* Constructor with a status code and status text, and content. * Constructor with a status code and status text, and content.
*/ */
public HttpServerErrorException( public HttpServerErrorException(
HttpStatus statusCode, String statusText, @Nullable byte[] body, @Nullable Charset charset) { HttpStatusCode statusCode, String statusText, @Nullable byte[] body, @Nullable Charset charset) {
super(statusCode, statusText, body, charset); super(statusCode, statusText, body, charset);
} }
@@ -60,7 +61,7 @@ public class HttpServerErrorException extends HttpStatusCodeException {
/** /**
* Constructor with a status code and status text, headers, and content. * Constructor with a status code and status text, headers, and content.
*/ */
public HttpServerErrorException(HttpStatus statusCode, String statusText, public HttpServerErrorException(HttpStatusCode statusCode, String statusText,
@Nullable HttpHeaders headers, @Nullable byte[] body, @Nullable Charset charset) { @Nullable HttpHeaders headers, @Nullable byte[] body, @Nullable Charset charset) {
super(statusCode, statusText, headers, body, charset); super(statusCode, statusText, headers, body, charset);
@@ -71,7 +72,7 @@ public class HttpServerErrorException extends HttpStatusCodeException {
* prepared message. * prepared message.
* @since 5.2.2 * @since 5.2.2
*/ */
public HttpServerErrorException(String message, HttpStatus statusCode, String statusText, public HttpServerErrorException(String message, HttpStatusCode statusCode, String statusText,
@Nullable HttpHeaders headers, @Nullable byte[] body, @Nullable Charset charset) { @Nullable HttpHeaders headers, @Nullable byte[] body, @Nullable Charset charset) {
super(message, statusCode, statusText, headers, body, charset); super(message, statusCode, statusText, headers, body, charset);
@@ -81,46 +82,55 @@ public class HttpServerErrorException extends HttpStatusCodeException {
* Create an {@code HttpServerErrorException} or an HTTP status specific sub-class. * Create an {@code HttpServerErrorException} or an HTTP status specific sub-class.
* @since 5.1 * @since 5.1
*/ */
public static HttpServerErrorException create(HttpStatus statusCode, public static HttpServerErrorException create(HttpStatusCode statusCode,
String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) { String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
return create(null, statusCode, statusText, headers, body, charset); return create(null, statusCode, statusText, headers, body, charset);
} }
/** /**
* Variant of {@link #create(String, HttpStatus, String, HttpHeaders, byte[], Charset)} * Variant of {@link #create(String, HttpStatusCode, String, HttpHeaders, byte[], Charset)}
* with an optional prepared message. * with an optional prepared message.
* @since 5.2.2. * @since 5.2.2.
*/ */
public static HttpServerErrorException create(@Nullable String message, HttpStatus statusCode, public static HttpServerErrorException create(@Nullable String message, HttpStatusCode statusCode,
String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) { String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
switch (statusCode) { if (statusCode instanceof HttpStatus status) {
case INTERNAL_SERVER_ERROR: switch (status) {
return message != null ? case INTERNAL_SERVER_ERROR:
return message != null ?
new HttpServerErrorException.InternalServerError(message, statusText, headers, body, charset) : new HttpServerErrorException.InternalServerError(message, statusText, headers, body, charset) :
new HttpServerErrorException.InternalServerError(statusText, headers, body, charset); new HttpServerErrorException.InternalServerError(statusText, headers, body, charset);
case NOT_IMPLEMENTED: case NOT_IMPLEMENTED:
return message != null ? return message != null ?
new HttpServerErrorException.NotImplemented(message, statusText, headers, body, charset) : new HttpServerErrorException.NotImplemented(message, statusText, headers, body, charset) :
new HttpServerErrorException.NotImplemented(statusText, headers, body, charset); new HttpServerErrorException.NotImplemented(statusText, headers, body, charset);
case BAD_GATEWAY: case BAD_GATEWAY:
return message != null ? return message != null ?
new HttpServerErrorException.BadGateway(message, statusText, headers, body, charset) : new HttpServerErrorException.BadGateway(message, statusText, headers, body, charset) :
new HttpServerErrorException.BadGateway(statusText, headers, body, charset); new HttpServerErrorException.BadGateway(statusText, headers, body, charset);
case SERVICE_UNAVAILABLE: case SERVICE_UNAVAILABLE:
return message != null ? return message != null ?
new HttpServerErrorException.ServiceUnavailable(message, statusText, headers, body, charset) : new HttpServerErrorException.ServiceUnavailable(message, statusText, headers, body, charset) :
new HttpServerErrorException.ServiceUnavailable(statusText, headers, body, charset); new HttpServerErrorException.ServiceUnavailable(statusText, headers, body, charset);
case GATEWAY_TIMEOUT: case GATEWAY_TIMEOUT:
return message != null ? return message != null ?
new HttpServerErrorException.GatewayTimeout(message, statusText, headers, body, charset) : new HttpServerErrorException.GatewayTimeout(message, statusText, headers, body, charset) :
new HttpServerErrorException.GatewayTimeout(statusText, headers, body, charset); new HttpServerErrorException.GatewayTimeout(statusText, headers, body, charset);
default: default:
return message != null ? return message != null ?
new HttpServerErrorException(message, statusCode, statusText, headers, body, charset) : new HttpServerErrorException(message, statusCode, statusText, headers, body, charset) :
new HttpServerErrorException(statusCode, statusText, headers, body, charset); new HttpServerErrorException(statusCode, statusText, headers, body, charset);
}
} }
if (message != null) {
return new HttpServerErrorException(message, statusCode, statusText, headers, body, charset);
}
else {
return new HttpServerErrorException(statusCode, statusText, headers, body, charset);
}
} }

View File

@@ -20,11 +20,12 @@ import java.nio.charset.Charset;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
/** /**
* Abstract base class for exceptions based on an {@link HttpStatus}. * Abstract base class for exceptions based on an {@link HttpStatusCode}.
* *
* @author Arjen Poutsma * @author Arjen Poutsma
* @author Chris Beams * @author Chris Beams
@@ -36,42 +37,48 @@ public abstract class HttpStatusCodeException extends RestClientResponseExceptio
private static final long serialVersionUID = 5696801857651587810L; private static final long serialVersionUID = 5696801857651587810L;
private final HttpStatus statusCode;
/** /**
* Construct a new instance with an {@link HttpStatus}. * Construct a new instance with an {@link HttpStatusCode}.
* @param statusCode the status code * @param statusCode the status code
*/ */
protected HttpStatusCodeException(HttpStatus statusCode) { protected HttpStatusCodeException(HttpStatusCode statusCode) {
this(statusCode, statusCode.name(), null, null, null); this(statusCode, name(statusCode), null, null, null);
}
private static String name(HttpStatusCode statusCode) {
if (statusCode instanceof HttpStatus status) {
return status.name();
}
else {
return "";
}
} }
/** /**
* Construct a new instance with an {@link HttpStatus} and status text. * Construct a new instance with an {@link HttpStatusCode} and status text.
* @param statusCode the status code * @param statusCode the status code
* @param statusText the status text * @param statusText the status text
*/ */
protected HttpStatusCodeException(HttpStatus statusCode, String statusText) { protected HttpStatusCodeException(HttpStatusCode statusCode, String statusText) {
this(statusCode, statusText, null, null, null); this(statusCode, statusText, null, null, null);
} }
/** /**
* Construct instance with an {@link HttpStatus}, status text, and content. * Construct instance with an {@link HttpStatusCode}, status text, and content.
* @param statusCode the status code * @param statusCode the status code
* @param statusText the status text * @param statusText the status text
* @param responseBody the response body content, may be {@code null} * @param responseBody the response body content, may be {@code null}
* @param responseCharset the response body charset, may be {@code null} * @param responseCharset the response body charset, may be {@code null}
* @since 3.0.5 * @since 3.0.5
*/ */
protected HttpStatusCodeException(HttpStatus statusCode, String statusText, protected HttpStatusCodeException(HttpStatusCode statusCode, String statusText,
@Nullable byte[] responseBody, @Nullable Charset responseCharset) { @Nullable byte[] responseBody, @Nullable Charset responseCharset) {
this(statusCode, statusText, null, responseBody, responseCharset); this(statusCode, statusText, null, responseBody, responseCharset);
} }
/** /**
* Construct instance with an {@link HttpStatus}, status text, content, and * Construct instance with an {@link HttpStatusCode}, status text, content, and
* a response charset. * a response charset.
* @param statusCode the status code * @param statusCode the status code
* @param statusText the status text * @param statusText the status text
@@ -80,7 +87,7 @@ public abstract class HttpStatusCodeException extends RestClientResponseExceptio
* @param responseCharset the response body charset, may be {@code null} * @param responseCharset the response body charset, may be {@code null}
* @since 3.1.2 * @since 3.1.2
*/ */
protected HttpStatusCodeException(HttpStatus statusCode, String statusText, protected HttpStatusCodeException(HttpStatusCode statusCode, String statusText,
@Nullable HttpHeaders responseHeaders, @Nullable byte[] responseBody, @Nullable Charset responseCharset) { @Nullable HttpHeaders responseHeaders, @Nullable byte[] responseBody, @Nullable Charset responseCharset) {
this(getMessage(statusCode, statusText), this(getMessage(statusCode, statusText),
@@ -88,7 +95,7 @@ public abstract class HttpStatusCodeException extends RestClientResponseExceptio
} }
/** /**
* Construct instance with an {@link HttpStatus}, status text, content, and * Construct instance with an {@link HttpStatusCode}, status text, content, and
* a response charset. * a response charset.
* @param message the exception message * @param message the exception message
* @param statusCode the status code * @param statusCode the status code
@@ -98,25 +105,17 @@ public abstract class HttpStatusCodeException extends RestClientResponseExceptio
* @param responseCharset the response body charset, may be {@code null} * @param responseCharset the response body charset, may be {@code null}
* @since 5.2.2 * @since 5.2.2
*/ */
protected HttpStatusCodeException(String message, HttpStatus statusCode, String statusText, protected HttpStatusCodeException(String message, HttpStatusCode statusCode, String statusText,
@Nullable HttpHeaders responseHeaders, @Nullable byte[] responseBody, @Nullable Charset responseCharset) { @Nullable HttpHeaders responseHeaders, @Nullable byte[] responseBody, @Nullable Charset responseCharset) {
super(message, statusCode.value(), statusText, responseHeaders, responseBody, responseCharset); super(message, statusCode, statusText, responseHeaders, responseBody, responseCharset);
this.statusCode = statusCode;
} }
private static String getMessage(HttpStatus statusCode, String statusText) { private static String getMessage(HttpStatusCode statusCode, String statusText) {
if (!StringUtils.hasLength(statusText)) { if (!StringUtils.hasLength(statusText) && statusCode instanceof HttpStatus status) {
statusText = statusCode.getReasonPhrase(); statusText = status.getReasonPhrase();
} }
return statusCode.value() + " " + statusText; return statusCode.value() + " " + statusText;
} }
/**
* Return the HTTP status code.
*/
public HttpStatus getStatusCode() {
return this.statusCode;
}
} }

View File

@@ -22,6 +22,7 @@ import java.io.PushbackInputStream;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.client.ClientHttpResponse; import org.springframework.http.client.ClientHttpResponse;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
@@ -58,9 +59,9 @@ class MessageBodyClientHttpResponseWrapper implements ClientHttpResponse {
* @throws IOException in case of I/O errors * @throws IOException in case of I/O errors
*/ */
public boolean hasMessageBody() throws IOException { public boolean hasMessageBody() throws IOException {
HttpStatus status = HttpStatus.resolve(getRawStatusCode()); HttpStatusCode statusCode = getStatusCode();
if (status != null && (status.is1xxInformational() || status == HttpStatus.NO_CONTENT || if (statusCode.is1xxInformational() || statusCode == HttpStatus.NO_CONTENT ||
status == HttpStatus.NOT_MODIFIED)) { statusCode == HttpStatus.NOT_MODIFIED) {
return false; return false;
} }
if (getHeaders().getContentLength() == 0) { if (getHeaders().getContentLength() == 0) {
@@ -121,11 +122,12 @@ class MessageBodyClientHttpResponseWrapper implements ClientHttpResponse {
} }
@Override @Override
public HttpStatus getStatusCode() throws IOException { public HttpStatusCode getStatusCode() throws IOException {
return this.response.getStatusCode(); return this.response.getStatusCode();
} }
@Override @Override
@Deprecated
public int getRawStatusCode() throws IOException { public int getRawStatusCode() throws IOException {
return this.response.getRawStatusCode(); return this.response.getRawStatusCode();
} }

View File

@@ -21,6 +21,7 @@ import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatusCode;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
/** /**
@@ -36,7 +37,7 @@ public class RestClientResponseException extends RestClientException {
private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8; private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
private final int rawStatusCode; private final HttpStatusCode statusCode;
private final String statusText; private final String statusText;
@@ -59,9 +60,22 @@ public class RestClientResponseException extends RestClientException {
*/ */
public RestClientResponseException(String message, int statusCode, String statusText, public RestClientResponseException(String message, int statusCode, String statusText,
@Nullable HttpHeaders responseHeaders, @Nullable byte[] responseBody, @Nullable Charset responseCharset) { @Nullable HttpHeaders responseHeaders, @Nullable byte[] responseBody, @Nullable Charset responseCharset) {
this(message, HttpStatusCode.valueOf(statusCode), statusText, responseHeaders, responseBody, responseCharset);
}
/**
* Construct a new instance of with the given response data.
* @param statusCode the raw status code value
* @param statusText the status text
* @param responseHeaders the response headers (may be {@code null})
* @param responseBody the response body content (may be {@code null})
* @param responseCharset the response body charset (may be {@code null})
* @since 6.0
*/
public RestClientResponseException(String message, HttpStatusCode statusCode, String statusText,
@Nullable HttpHeaders responseHeaders, @Nullable byte[] responseBody, @Nullable Charset responseCharset) {
super(message); super(message);
this.rawStatusCode = statusCode; this.statusCode = statusCode;
this.statusText = statusText; this.statusText = statusText;
this.responseHeaders = responseHeaders; this.responseHeaders = responseHeaders;
this.responseBody = (responseBody != null ? responseBody : new byte[0]); this.responseBody = (responseBody != null ? responseBody : new byte[0]);
@@ -70,10 +84,20 @@ public class RestClientResponseException extends RestClientException {
/** /**
* Return the raw HTTP status code value. * Return the HTTP status code.
* @since 6.0
*/ */
public HttpStatusCode getStatusCode() {
return this.statusCode;
}
/**
* Return the raw HTTP status code value.
* @deprecated as of 6.0, in favor of {@link #getStatusCode()}
*/
@Deprecated
public int getRawStatusCode() { public int getRawStatusCode() {
return this.rawStatusCode; return this.statusCode.value();
} }
/** /**

View File

@@ -33,7 +33,7 @@ import org.springframework.core.SpringProperties;
import org.springframework.http.HttpEntity; import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.RequestEntity; import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
@@ -798,9 +798,8 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
boolean hasError = errorHandler.hasError(response); boolean hasError = errorHandler.hasError(response);
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
try { try {
int code = response.getRawStatusCode(); HttpStatusCode statusCode = response.getStatusCode();
HttpStatus status = HttpStatus.resolve(code); logger.debug("Response " + statusCode);
logger.debug("Response " + (status != null ? status : code));
} }
catch (IOException ex) { catch (IOException ex) {
// ignore // ignore
@@ -1026,10 +1025,10 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
public ResponseEntity<T> extractData(ClientHttpResponse response) throws IOException { public ResponseEntity<T> extractData(ClientHttpResponse response) throws IOException {
if (this.delegate != null) { if (this.delegate != null) {
T body = this.delegate.extractData(response); T body = this.delegate.extractData(response);
return ResponseEntity.status(response.getRawStatusCode()).headers(response.getHeaders()).body(body); return ResponseEntity.status(response.getStatusCode()).headers(response.getHeaders()).body(body);
} }
else { else {
return ResponseEntity.status(response.getRawStatusCode()).headers(response.getHeaders()).build(); return ResponseEntity.status(response.getStatusCode()).headers(response.getHeaders()).build();
} }
} }
} }

View File

@@ -20,6 +20,7 @@ import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
@@ -40,7 +41,7 @@ public class UnknownContentTypeException extends RestClientException {
private final MediaType contentType; private final MediaType contentType;
private final int rawStatusCode; private final HttpStatusCode statusCode;
private final String statusText; private final String statusText;
@@ -61,12 +62,28 @@ public class UnknownContentTypeException extends RestClientException {
public UnknownContentTypeException(Type targetType, MediaType contentType, public UnknownContentTypeException(Type targetType, MediaType contentType,
int statusCode, String statusText, HttpHeaders responseHeaders, byte[] responseBody) { int statusCode, String statusText, HttpHeaders responseHeaders, byte[] responseBody) {
this(targetType, contentType, HttpStatusCode.valueOf(statusCode), statusText, responseHeaders, responseBody);
}
/**
* Construct a new instance of with the given response data.
* @param targetType the expected target type
* @param contentType the content type of the response
* @param statusCode the raw status code value
* @param statusText the status text
* @param responseHeaders the response headers (may be {@code null})
* @param responseBody the response body content (may be {@code null})
* @since 6.0
*/
public UnknownContentTypeException(Type targetType, MediaType contentType,
HttpStatusCode statusCode, String statusText, HttpHeaders responseHeaders, byte[] responseBody) {
super("Could not extract response: no suitable HttpMessageConverter found " + super("Could not extract response: no suitable HttpMessageConverter found " +
"for response type [" + targetType + "] and content type [" + contentType + "]"); "for response type [" + targetType + "] and content type [" + contentType + "]");
this.targetType = targetType; this.targetType = targetType;
this.contentType = contentType; this.contentType = contentType;
this.rawStatusCode = statusCode; this.statusCode = statusCode;
this.statusText = statusText; this.statusText = statusText;
this.responseHeaders = responseHeaders; this.responseHeaders = responseHeaders;
this.responseBody = responseBody; this.responseBody = responseBody;
@@ -88,10 +105,19 @@ public class UnknownContentTypeException extends RestClientException {
} }
/** /**
* Return the raw HTTP status code value. * Return the HTTP status code value.
*/ */
public HttpStatusCode getStatusCode() {
return this.statusCode;
}
/**
* Return the raw HTTP status code value.
* @deprecated as of 6.0, in favor of {@link #getStatusCode()}
*/
@Deprecated
public int getRawStatusCode() { public int getRawStatusCode() {
return this.rawStatusCode; return this.statusCode.value();
} }
/** /**

View File

@@ -19,7 +19,6 @@ package org.springframework.web.client;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
/** /**
@@ -34,8 +33,8 @@ public class UnknownHttpStatusCodeException extends RestClientResponseException
/** /**
* Construct a new instance of {@code HttpStatusCodeException} based on an * Construct a new instance of {@code HttpStatusCodeException} based on a
* {@link HttpStatus}, status text, and response body content. * status code, status text, and response body content.
* @param rawStatusCode the raw status code value * @param rawStatusCode the raw status code value
* @param statusText the status text * @param statusText the status text
* @param responseHeaders the response headers (may be {@code null}) * @param responseHeaders the response headers (may be {@code null})
@@ -50,8 +49,8 @@ public class UnknownHttpStatusCodeException extends RestClientResponseException
} }
/** /**
* Construct a new instance of {@code HttpStatusCodeException} based on an * Construct a new instance of {@code HttpStatusCodeException} based on a
* {@link HttpStatus}, status text, and response body content. * status code, status text, and response body content.
* @param rawStatusCode the raw status code value * @param rawStatusCode the raw status code value
* @param statusText the status text * @param statusText the status text
* @param responseHeaders the response headers (may be {@code null}) * @param responseHeaders the response headers (may be {@code null})

View File

@@ -17,6 +17,7 @@
package org.springframework.web.context.request.async; package org.springframework.web.context.request.async;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.ProblemDetail; import org.springframework.http.ProblemDetail;
import org.springframework.web.ErrorResponse; import org.springframework.web.ErrorResponse;
@@ -37,13 +38,13 @@ import org.springframework.web.ErrorResponse;
public class AsyncRequestTimeoutException extends RuntimeException implements ErrorResponse { public class AsyncRequestTimeoutException extends RuntimeException implements ErrorResponse {
@Override @Override
public int getRawStatusCode() { public HttpStatusCode getStatusCode() {
return HttpStatus.SERVICE_UNAVAILABLE.value(); return HttpStatus.SERVICE_UNAVAILABLE;
} }
@Override @Override
public ProblemDetail getBody() { public ProblemDetail getBody() {
return ProblemDetail.forRawStatusCode(getRawStatusCode()); return ProblemDetail.forStatus(getStatusCode());
} }
} }

View File

@@ -24,6 +24,7 @@ import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**
@@ -43,7 +44,7 @@ import org.springframework.util.Assert;
*/ */
public class RelativeRedirectFilter extends OncePerRequestFilter { public class RelativeRedirectFilter extends OncePerRequestFilter {
private HttpStatus redirectStatus = HttpStatus.SEE_OTHER; private HttpStatusCode redirectStatus = HttpStatus.SEE_OTHER;
/** /**
@@ -51,7 +52,7 @@ public class RelativeRedirectFilter extends OncePerRequestFilter {
* <p>By default this is {@link HttpStatus#SEE_OTHER}. * <p>By default this is {@link HttpStatus#SEE_OTHER}.
* @param status the 3xx redirect status to use * @param status the 3xx redirect status to use
*/ */
public void setRedirectStatus(HttpStatus status) { public void setRedirectStatus(HttpStatusCode status) {
Assert.notNull(status, "Property 'redirectStatus' is required"); Assert.notNull(status, "Property 'redirectStatus' is required");
Assert.isTrue(status.is3xxRedirection(), "Not a redirect status code"); Assert.isTrue(status.is3xxRedirection(), "Not a redirect status code");
this.redirectStatus = status; this.redirectStatus = status;
@@ -60,7 +61,7 @@ public class RelativeRedirectFilter extends OncePerRequestFilter {
/** /**
* Return the configured redirect status. * Return the configured redirect status.
*/ */
public HttpStatus getRedirectStatus() { public HttpStatusCode getRedirectStatus() {
return this.redirectStatus; return this.redirectStatus;
} }

View File

@@ -20,7 +20,7 @@ import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpServletResponseWrapper; import jakarta.servlet.http.HttpServletResponseWrapper;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.web.util.WebUtils; import org.springframework.web.util.WebUtils;
@@ -33,10 +33,10 @@ import org.springframework.web.util.WebUtils;
*/ */
final class RelativeRedirectResponseWrapper extends HttpServletResponseWrapper { final class RelativeRedirectResponseWrapper extends HttpServletResponseWrapper {
private final HttpStatus redirectStatus; private final HttpStatusCode redirectStatus;
private RelativeRedirectResponseWrapper(HttpServletResponse response, HttpStatus redirectStatus) { private RelativeRedirectResponseWrapper(HttpServletResponse response, HttpStatusCode redirectStatus) {
super(response); super(response);
Assert.notNull(redirectStatus, "'redirectStatus' is required"); Assert.notNull(redirectStatus, "'redirectStatus' is required");
this.redirectStatus = redirectStatus; this.redirectStatus = redirectStatus;
@@ -51,7 +51,7 @@ final class RelativeRedirectResponseWrapper extends HttpServletResponseWrapper {
public static HttpServletResponse wrapIfNecessary(HttpServletResponse response, public static HttpServletResponse wrapIfNecessary(HttpServletResponse response,
HttpStatus redirectStatus) { HttpStatusCode redirectStatus) {
RelativeRedirectResponseWrapper wrapper = RelativeRedirectResponseWrapper wrapper =
WebUtils.getNativeResponse(response, RelativeRedirectResponseWrapper.class); WebUtils.getNativeResponse(response, RelativeRedirectResponseWrapper.class);

View File

@@ -36,7 +36,7 @@ import org.springframework.core.MethodParameter;
import org.springframework.core.ResolvableType; import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.AnnotatedElementUtils; import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.SynthesizingMethodParameter; import org.springframework.core.annotation.SynthesizingMethodParameter;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode;
import org.springframework.lang.NonNull; import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.util.Assert; import org.springframework.util.Assert;
@@ -85,7 +85,7 @@ public class HandlerMethod {
private final MethodParameter[] parameters; private final MethodParameter[] parameters;
@Nullable @Nullable
private HttpStatus responseStatus; private HttpStatusCode responseStatus;
@Nullable @Nullable
private String responseStatusReason; private String responseStatusReason;
@@ -296,7 +296,7 @@ public class HandlerMethod {
* @see ResponseStatus#code() * @see ResponseStatus#code()
*/ */
@Nullable @Nullable
protected HttpStatus getResponseStatus() { protected HttpStatusCode getResponseStatus() {
return this.responseStatus; return this.responseStatus;
} }

View File

@@ -20,7 +20,7 @@ import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.ui.Model; import org.springframework.ui.Model;
import org.springframework.ui.ModelMap; import org.springframework.ui.ModelMap;
@@ -62,7 +62,7 @@ public class ModelAndViewContainer {
private boolean redirectModelScenario = false; private boolean redirectModelScenario = false;
@Nullable @Nullable
private HttpStatus status; private HttpStatusCode status;
private final Set<String> noBinding = new HashSet<>(4); private final Set<String> noBinding = new HashSet<>(4);
@@ -193,7 +193,7 @@ public class ModelAndViewContainer {
* {@code ModelAndView} used for view rendering purposes. * {@code ModelAndView} used for view rendering purposes.
* @since 4.3 * @since 4.3
*/ */
public void setStatus(@Nullable HttpStatus status) { public void setStatus(@Nullable HttpStatusCode status) {
this.status = status; this.status = status;
} }
@@ -202,7 +202,7 @@ public class ModelAndViewContainer {
* @since 4.3 * @since 4.3
*/ */
@Nullable @Nullable
public HttpStatus getStatus() { public HttpStatusCode getStatus() {
return this.status; return this.status;
} }

View File

@@ -18,7 +18,7 @@ package org.springframework.web.server;
import org.springframework.core.NestedExceptionUtils; import org.springframework.core.NestedExceptionUtils;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.web.ErrorResponseException; import org.springframework.web.ErrorResponseException;
@@ -41,7 +41,7 @@ public class ResponseStatusException extends ErrorResponseException {
* Constructor with a response status. * Constructor with a response status.
* @param status the HTTP status (required) * @param status the HTTP status (required)
*/ */
public ResponseStatusException(HttpStatus status) { public ResponseStatusException(HttpStatusCode status) {
this(status, null); this(status, null);
} }
@@ -51,21 +51,10 @@ public class ResponseStatusException extends ErrorResponseException {
* @param status the HTTP status (required) * @param status the HTTP status (required)
* @param reason the associated reason (optional) * @param reason the associated reason (optional)
*/ */
public ResponseStatusException(HttpStatus status, @Nullable String reason) { public ResponseStatusException(HttpStatusCode status, @Nullable String reason) {
this(status, reason, null); this(status, reason, null);
} }
/**
* Constructor with a response status and a reason to add to the exception
* message as explanation, as well as a nested exception.
* @param status the HTTP status (required)
* @param reason the associated reason (optional)
* @param cause a nested exception (optional)
*/
public ResponseStatusException(HttpStatus status, @Nullable String reason, @Nullable Throwable cause) {
this(status.value(), reason, cause);
}
/** /**
* Constructor with a response status and a reason to add to the exception * Constructor with a response status and a reason to add to the exception
* message as explanation, as well as a nested exception. * message as explanation, as well as a nested exception.
@@ -75,7 +64,18 @@ public class ResponseStatusException extends ErrorResponseException {
* @since 5.3 * @since 5.3
*/ */
public ResponseStatusException(int rawStatusCode, @Nullable String reason, @Nullable Throwable cause) { public ResponseStatusException(int rawStatusCode, @Nullable String reason, @Nullable Throwable cause) {
super(rawStatusCode, cause); this(HttpStatusCode.valueOf(rawStatusCode), reason, cause);
}
/**
* Constructor with a response status and a reason to add to the exception
* message as explanation, as well as a nested exception.
* @param status the HTTP status (required)
* @param reason the associated reason (optional)
* @param cause a nested exception (optional)
*/
public ResponseStatusException(HttpStatusCode status, @Nullable String reason, @Nullable Throwable cause) {
super(status, cause);
this.reason = reason; this.reason = reason;
} }
@@ -112,8 +112,7 @@ public class ResponseStatusException extends ErrorResponseException {
@Override @Override
public String getMessage() { public String getMessage() {
HttpStatus code = HttpStatus.resolve(getRawStatusCode()); String msg = getStatusCode() + (this.reason != null ? " \"" + this.reason + "\"" : "");
String msg = (code != null ? code : getRawStatusCode()) + (this.reason != null ? " \"" + this.reason + "\"" : "");
return NestedExceptionUtils.buildMessage(msg, getCause()); return NestedExceptionUtils.buildMessage(msg, getCause());
} }

View File

@@ -34,6 +34,7 @@ import org.springframework.core.codec.Hints;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.InvalidMediaTypeException; import org.springframework.http.InvalidMediaTypeException;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.codec.HttpMessageReader; import org.springframework.http.codec.HttpMessageReader;
@@ -249,7 +250,7 @@ public class DefaultServerWebExchange implements ServerWebExchange {
@Override @Override
public boolean checkNotModified(@Nullable String etag, Instant lastModified) { public boolean checkNotModified(@Nullable String etag, Instant lastModified) {
HttpStatus status = getResponse().getStatusCode(); HttpStatusCode status = getResponse().getStatusCode();
if (this.notModified || (status != null && !HttpStatus.OK.equals(status))) { if (this.notModified || (status != null && !HttpStatus.OK.equals(status))) {
return this.notModified; return this.notModified;
} }

View File

@@ -29,6 +29,7 @@ import org.springframework.core.NestedExceptionUtils;
import org.springframework.core.log.LogFormatUtils; import org.springframework.core.log.LogFormatUtils;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.codec.LoggingCodecSupport; import org.springframework.http.codec.LoggingCodecSupport;
import org.springframework.http.codec.ServerCodecConfigurer; import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.http.server.reactive.HttpHandler; import org.springframework.http.server.reactive.HttpHandler;
@@ -270,7 +271,7 @@ public class HttpWebHandlerAdapter extends WebHandlerDecorator implements HttpHa
private void logResponse(ServerWebExchange exchange) { private void logResponse(ServerWebExchange exchange) {
LogFormatUtils.traceDebug(logger, traceOn -> { LogFormatUtils.traceDebug(logger, traceOn -> {
HttpStatus status = exchange.getResponse().getStatusCode(); HttpStatusCode status = exchange.getResponse().getStatusCode();
return exchange.getLogPrefix() + "Completed " + (status != null ? status : "200 OK") + return exchange.getLogPrefix() + "Completed " + (status != null ? status : "200 OK") +
(traceOn ? ", headers=" + formatHeaders(exchange.getResponse().getHeaders()) : ""); (traceOn ? ", headers=" + formatHeaders(exchange.getResponse().getHeaders()) : "");
}); });

View File

@@ -21,7 +21,7 @@ import org.apache.commons.logging.LogFactory;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import org.springframework.core.log.LogFormatUtils; import org.springframework.core.log.LogFormatUtils;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode;
import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
@@ -88,12 +88,13 @@ public class ResponseStatusExceptionHandler implements WebExceptionHandler {
return "Resolved [" + className + ": " + message + "] for HTTP " + request.getMethod() + " " + path; return "Resolved [" + className + ": " + message + "] for HTTP " + request.getMethod() + " " + path;
} }
@SuppressWarnings("deprecation")
private boolean updateResponse(ServerHttpResponse response, Throwable ex) { private boolean updateResponse(ServerHttpResponse response, Throwable ex) {
boolean result = false; boolean result = false;
HttpStatus httpStatus = determineStatus(ex); HttpStatusCode statusCode = determineStatus(ex);
int code = (httpStatus != null ? httpStatus.value() : determineRawStatusCode(ex)); int code = (statusCode != null ? statusCode.value() : determineRawStatusCode(ex));
if (code != -1) { if (code != -1) {
if (response.setRawStatusCode(code)) { if (response.setStatusCode(statusCode)) {
if (ex instanceof ResponseStatusException) { if (ex instanceof ResponseStatusException) {
((ResponseStatusException) ex).getHeaders().forEach((name, values) -> ((ResponseStatusException) ex).getHeaders().forEach((name, values) ->
values.forEach(value -> response.getHeaders().add(name, value))); values.forEach(value -> response.getHeaders().add(name, value)));
@@ -112,16 +113,18 @@ public class ResponseStatusExceptionHandler implements WebExceptionHandler {
/** /**
* Determine the HTTP status for the given exception. * Determine the HTTP status for the given exception.
* <p>As of 5.3 this method always returns {@code null} in which case
* {@link #determineRawStatusCode(Throwable)} is used instead.
* @param ex the exception to check * @param ex the exception to check
* @return the associated HTTP status, if any * @return the associated HTTP status code, or {@code null} if it can't be
* @deprecated as of 5.3 in favor of {@link #determineRawStatusCode(Throwable)}. * derived
*/ */
@Nullable @Nullable
@Deprecated protected HttpStatusCode determineStatus(Throwable ex) {
protected HttpStatus determineStatus(Throwable ex) { if (ex instanceof ResponseStatusException responseStatusException) {
return null; return responseStatusException.getStatusCode();
}
else {
return null;
}
} }
/** /**
@@ -129,10 +132,12 @@ public class ResponseStatusExceptionHandler implements WebExceptionHandler {
* @param ex the exception to check * @param ex the exception to check
* @return the associated HTTP status code, or -1 if it can't be derived. * @return the associated HTTP status code, or -1 if it can't be derived.
* @since 5.3 * @since 5.3
* @deprecated as of 6.0, in favor of {@link #determineStatus(Throwable)}
*/ */
@Deprecated
protected int determineRawStatusCode(Throwable ex) { protected int determineRawStatusCode(Throwable ex) {
if (ex instanceof ResponseStatusException) { if (ex instanceof ResponseStatusException responseStatusException) {
return ((ResponseStatusException) ex).getRawStatusCode(); return responseStatusException.getStatusCode().value();
} }
return -1; return -1;
} }

View File

@@ -328,7 +328,7 @@ public class ErrorResponseExceptionTests {
private void assertStatus(ErrorResponse ex, HttpStatus status) { private void assertStatus(ErrorResponse ex, HttpStatus status) {
ProblemDetail body = ex.getBody(); ProblemDetail body = ex.getBody();
assertThat(ex.getStatus()).isEqualTo(status); assertThat(ex.getStatusCode()).isEqualTo(status);
assertThat(body.getStatus()).isEqualTo(status.value()); assertThat(body.getStatus()).isEqualTo(status.value());
assertThat(body.getTitle()).isEqualTo(status.getReasonPhrase()); assertThat(body.getTitle()).isEqualTo(status.getReasonPhrase());
} }

View File

@@ -66,7 +66,7 @@ class DefaultResponseErrorHandlerHttpStatusTests {
@DisplayName("hasError() returns true") @DisplayName("hasError() returns true")
@MethodSource("errorCodes") @MethodSource("errorCodes")
void hasErrorTrue(HttpStatus httpStatus) throws Exception { void hasErrorTrue(HttpStatus httpStatus) throws Exception {
given(this.response.getRawStatusCode()).willReturn(httpStatus.value()); given(this.response.getStatusCode()).willReturn(httpStatus);
assertThat(this.handler.hasError(this.response)).isTrue(); assertThat(this.handler.hasError(this.response)).isTrue();
} }
@@ -77,7 +77,7 @@ class DefaultResponseErrorHandlerHttpStatusTests {
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.TEXT_PLAIN); headers.setContentType(MediaType.TEXT_PLAIN);
given(this.response.getRawStatusCode()).willReturn(httpStatus.value()); given(this.response.getStatusCode()).willReturn(httpStatus);
given(this.response.getHeaders()).willReturn(headers); given(this.response.getHeaders()).willReturn(headers);
assertThatExceptionOfType(expectedExceptionClass).isThrownBy(() -> this.handler.handleError(this.response)); assertThatExceptionOfType(expectedExceptionClass).isThrownBy(() -> this.handler.handleError(this.response));

View File

@@ -24,6 +24,7 @@ import org.junit.jupiter.api.Test;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpResponse; import org.springframework.http.client.ClientHttpResponse;
import org.springframework.util.StreamUtils; import org.springframework.util.StreamUtils;
@@ -50,13 +51,13 @@ public class DefaultResponseErrorHandlerTests {
@Test @Test
public void hasErrorTrue() throws Exception { public void hasErrorTrue() throws Exception {
given(response.getRawStatusCode()).willReturn(HttpStatus.NOT_FOUND.value()); given(response.getStatusCode()).willReturn(HttpStatus.NOT_FOUND);
assertThat(handler.hasError(response)).isTrue(); assertThat(handler.hasError(response)).isTrue();
} }
@Test @Test
public void hasErrorFalse() throws Exception { public void hasErrorFalse() throws Exception {
given(response.getRawStatusCode()).willReturn(HttpStatus.OK.value()); given(response.getStatusCode()).willReturn(HttpStatus.OK);
assertThat(handler.hasError(response)).isFalse(); assertThat(handler.hasError(response)).isFalse();
} }
@@ -65,7 +66,7 @@ public class DefaultResponseErrorHandlerTests {
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.TEXT_PLAIN); headers.setContentType(MediaType.TEXT_PLAIN);
given(response.getRawStatusCode()).willReturn(HttpStatus.NOT_FOUND.value()); given(response.getStatusCode()).willReturn(HttpStatus.NOT_FOUND);
given(response.getStatusText()).willReturn("Not Found"); given(response.getStatusText()).willReturn("Not Found");
given(response.getHeaders()).willReturn(headers); given(response.getHeaders()).willReturn(headers);
given(response.getBody()).willReturn(new ByteArrayInputStream("Hello World".getBytes(StandardCharsets.UTF_8))); given(response.getBody()).willReturn(new ByteArrayInputStream("Hello World".getBytes(StandardCharsets.UTF_8)));
@@ -81,7 +82,7 @@ public class DefaultResponseErrorHandlerTests {
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.TEXT_PLAIN); headers.setContentType(MediaType.TEXT_PLAIN);
given(response.getRawStatusCode()).willReturn(HttpStatus.NOT_FOUND.value()); given(response.getStatusCode()).willReturn(HttpStatus.NOT_FOUND);
given(response.getStatusText()).willReturn("Not Found"); given(response.getStatusText()).willReturn("Not Found");
given(response.getHeaders()).willReturn(headers); given(response.getHeaders()).willReturn(headers);
given(response.getBody()).willThrow(new IOException()); given(response.getBody()).willThrow(new IOException());
@@ -94,7 +95,7 @@ public class DefaultResponseErrorHandlerTests {
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.TEXT_PLAIN); headers.setContentType(MediaType.TEXT_PLAIN);
given(response.getRawStatusCode()).willReturn(HttpStatus.NOT_FOUND.value()); given(response.getStatusCode()).willReturn(HttpStatus.NOT_FOUND);
given(response.getStatusText()).willReturn("Not Found"); given(response.getStatusText()).willReturn("Not Found");
given(response.getHeaders()).willReturn(headers); given(response.getHeaders()).willReturn(headers);
@@ -107,7 +108,7 @@ public class DefaultResponseErrorHandlerTests {
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.TEXT_PLAIN); headers.setContentType(MediaType.TEXT_PLAIN);
given(response.getRawStatusCode()).willReturn(999); given(response.getStatusCode()).willReturn(HttpStatusCode.valueOf(999));
given(response.getStatusText()).willReturn("Custom status code"); given(response.getStatusText()).willReturn("Custom status code");
given(response.getHeaders()).willReturn(headers); given(response.getHeaders()).willReturn(headers);
@@ -119,7 +120,7 @@ public class DefaultResponseErrorHandlerTests {
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.TEXT_PLAIN); headers.setContentType(MediaType.TEXT_PLAIN);
given(response.getRawStatusCode()).willReturn(999); given(response.getStatusCode()).willReturn(HttpStatusCode.valueOf(999));
given(response.getStatusText()).willReturn("Custom status code"); given(response.getStatusText()).willReturn("Custom status code");
given(response.getHeaders()).willReturn(headers); given(response.getHeaders()).willReturn(headers);
@@ -132,7 +133,7 @@ public class DefaultResponseErrorHandlerTests {
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.TEXT_PLAIN); headers.setContentType(MediaType.TEXT_PLAIN);
given(response.getRawStatusCode()).willReturn(499); given(response.getStatusCode()).willReturn(HttpStatusCode.valueOf(499));
given(response.getStatusText()).willReturn("Custom status code"); given(response.getStatusText()).willReturn("Custom status code");
given(response.getHeaders()).willReturn(headers); given(response.getHeaders()).willReturn(headers);
@@ -141,7 +142,7 @@ public class DefaultResponseErrorHandlerTests {
@Test @Test
public void handleErrorForCustomClientError() throws Exception { public void handleErrorForCustomClientError() throws Exception {
int statusCode = 499; HttpStatusCode statusCode = HttpStatusCode.valueOf(499);
String statusText = "Custom status code"; String statusText = "Custom status code";
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
@@ -150,7 +151,7 @@ public class DefaultResponseErrorHandlerTests {
String responseBody = "Hello World"; String responseBody = "Hello World";
TestByteArrayInputStream body = new TestByteArrayInputStream(responseBody.getBytes(StandardCharsets.UTF_8)); TestByteArrayInputStream body = new TestByteArrayInputStream(responseBody.getBytes(StandardCharsets.UTF_8));
given(response.getRawStatusCode()).willReturn(statusCode); given(response.getStatusCode()).willReturn(statusCode);
given(response.getStatusText()).willReturn(statusText); given(response.getStatusText()).willReturn(statusText);
given(response.getHeaders()).willReturn(headers); given(response.getHeaders()).willReturn(headers);
given(response.getBody()).willReturn(body); given(response.getBody()).willReturn(body);
@@ -158,13 +159,13 @@ public class DefaultResponseErrorHandlerTests {
Throwable throwable = catchThrowable(() -> handler.handleError(response)); Throwable throwable = catchThrowable(() -> handler.handleError(response));
// validate exception // validate exception
assertThat(throwable).isInstanceOf(UnknownHttpStatusCodeException.class); assertThat(throwable).isInstanceOf(HttpClientErrorException.class);
UnknownHttpStatusCodeException actualUnknownHttpStatusCodeException = (UnknownHttpStatusCodeException) throwable; HttpClientErrorException actualHttpClientErrorException = (HttpClientErrorException) throwable;
assertThat(actualUnknownHttpStatusCodeException.getRawStatusCode()).isEqualTo(statusCode); assertThat(actualHttpClientErrorException.getStatusCode()).isEqualTo(statusCode);
assertThat(actualUnknownHttpStatusCodeException.getStatusText()).isEqualTo(statusText); assertThat(actualHttpClientErrorException.getStatusText()).isEqualTo(statusText);
assertThat(actualUnknownHttpStatusCodeException.getResponseHeaders()).isEqualTo(headers); assertThat(actualHttpClientErrorException.getResponseHeaders()).isEqualTo(headers);
assertThat(actualUnknownHttpStatusCodeException.getMessage()).contains(responseBody); assertThat(actualHttpClientErrorException.getMessage()).contains(responseBody);
assertThat(actualUnknownHttpStatusCodeException.getResponseBodyAsString()).isEqualTo(responseBody); assertThat(actualHttpClientErrorException.getResponseBodyAsString()).isEqualTo(responseBody);
} }
@Test // SPR-17461 @Test // SPR-17461
@@ -172,7 +173,7 @@ public class DefaultResponseErrorHandlerTests {
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.TEXT_PLAIN); headers.setContentType(MediaType.TEXT_PLAIN);
given(response.getRawStatusCode()).willReturn(599); given(response.getStatusCode()).willReturn(HttpStatusCode.valueOf(599));
given(response.getStatusText()).willReturn("Custom status code"); given(response.getStatusText()).willReturn("Custom status code");
given(response.getHeaders()).willReturn(headers); given(response.getHeaders()).willReturn(headers);
@@ -181,7 +182,7 @@ public class DefaultResponseErrorHandlerTests {
@Test @Test
public void handleErrorForCustomServerError() throws Exception { public void handleErrorForCustomServerError() throws Exception {
int statusCode = 599; HttpStatusCode statusCode = HttpStatusCode.valueOf(599);
String statusText = "Custom status code"; String statusText = "Custom status code";
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
@@ -190,7 +191,7 @@ public class DefaultResponseErrorHandlerTests {
String responseBody = "Hello World"; String responseBody = "Hello World";
TestByteArrayInputStream body = new TestByteArrayInputStream(responseBody.getBytes(StandardCharsets.UTF_8)); TestByteArrayInputStream body = new TestByteArrayInputStream(responseBody.getBytes(StandardCharsets.UTF_8));
given(response.getRawStatusCode()).willReturn(statusCode); given(response.getStatusCode()).willReturn(statusCode);
given(response.getStatusText()).willReturn(statusText); given(response.getStatusText()).willReturn(statusText);
given(response.getHeaders()).willReturn(headers); given(response.getHeaders()).willReturn(headers);
given(response.getBody()).willReturn(body); given(response.getBody()).willReturn(body);
@@ -198,13 +199,13 @@ public class DefaultResponseErrorHandlerTests {
Throwable throwable = catchThrowable(() -> handler.handleError(response)); Throwable throwable = catchThrowable(() -> handler.handleError(response));
// validate exception // validate exception
assertThat(throwable).isInstanceOf(UnknownHttpStatusCodeException.class); assertThat(throwable).isInstanceOf(HttpServerErrorException.class);
UnknownHttpStatusCodeException actualUnknownHttpStatusCodeException = (UnknownHttpStatusCodeException) throwable; HttpServerErrorException actualHttpServerErrorException = (HttpServerErrorException) throwable;
assertThat(actualUnknownHttpStatusCodeException.getRawStatusCode()).isEqualTo(statusCode); assertThat(actualHttpServerErrorException.getStatusCode()).isEqualTo(statusCode);
assertThat(actualUnknownHttpStatusCodeException.getStatusText()).isEqualTo(statusText); assertThat(actualHttpServerErrorException.getStatusText()).isEqualTo(statusText);
assertThat(actualUnknownHttpStatusCodeException.getResponseHeaders()).isEqualTo(headers); assertThat(actualHttpServerErrorException.getResponseHeaders()).isEqualTo(headers);
assertThat(actualUnknownHttpStatusCodeException.getMessage()).contains(responseBody); assertThat(actualHttpServerErrorException.getMessage()).contains(responseBody);
assertThat(actualUnknownHttpStatusCodeException.getResponseBodyAsString()).isEqualTo(responseBody); assertThat(actualHttpServerErrorException.getResponseBodyAsString()).isEqualTo(responseBody);
} }
@Test // SPR-16604 @Test // SPR-16604
@@ -213,7 +214,7 @@ public class DefaultResponseErrorHandlerTests {
headers.setContentType(MediaType.TEXT_PLAIN); headers.setContentType(MediaType.TEXT_PLAIN);
TestByteArrayInputStream body = new TestByteArrayInputStream("Hello World".getBytes(StandardCharsets.UTF_8)); TestByteArrayInputStream body = new TestByteArrayInputStream("Hello World".getBytes(StandardCharsets.UTF_8));
given(response.getRawStatusCode()).willReturn(999); given(response.getStatusCode()).willReturn(HttpStatusCode.valueOf(999));
given(response.getStatusText()).willReturn("Custom status code"); given(response.getStatusText()).willReturn("Custom status code");
given(response.getHeaders()).willReturn(headers); given(response.getHeaders()).willReturn(headers);
given(response.getBody()).willReturn(body); given(response.getBody()).willReturn(body);

View File

@@ -60,13 +60,13 @@ public class ExtractingResponseErrorHandlerTests {
@Test @Test
public void hasError() throws Exception { public void hasError() throws Exception {
given(this.response.getRawStatusCode()).willReturn(HttpStatus.I_AM_A_TEAPOT.value()); given(this.response.getStatusCode()).willReturn(HttpStatus.I_AM_A_TEAPOT);
assertThat(this.errorHandler.hasError(this.response)).isTrue(); assertThat(this.errorHandler.hasError(this.response)).isTrue();
given(this.response.getRawStatusCode()).willReturn(HttpStatus.INTERNAL_SERVER_ERROR.value()); given(this.response.getStatusCode()).willReturn(HttpStatus.INTERNAL_SERVER_ERROR);
assertThat(this.errorHandler.hasError(this.response)).isTrue(); assertThat(this.errorHandler.hasError(this.response)).isTrue();
given(this.response.getRawStatusCode()).willReturn(HttpStatus.OK.value()); given(this.response.getStatusCode()).willReturn(HttpStatus.OK);
assertThat(this.errorHandler.hasError(this.response)).isFalse(); assertThat(this.errorHandler.hasError(this.response)).isFalse();
} }
@@ -75,19 +75,19 @@ public class ExtractingResponseErrorHandlerTests {
this.errorHandler.setSeriesMapping(Collections this.errorHandler.setSeriesMapping(Collections
.singletonMap(HttpStatus.Series.CLIENT_ERROR, null)); .singletonMap(HttpStatus.Series.CLIENT_ERROR, null));
given(this.response.getRawStatusCode()).willReturn(HttpStatus.I_AM_A_TEAPOT.value()); given(this.response.getStatusCode()).willReturn(HttpStatus.I_AM_A_TEAPOT);
assertThat(this.errorHandler.hasError(this.response)).isTrue(); assertThat(this.errorHandler.hasError(this.response)).isTrue();
given(this.response.getRawStatusCode()).willReturn(HttpStatus.NOT_FOUND.value()); given(this.response.getStatusCode()).willReturn(HttpStatus.NOT_FOUND);
assertThat(this.errorHandler.hasError(this.response)).isFalse(); assertThat(this.errorHandler.hasError(this.response)).isFalse();
given(this.response.getRawStatusCode()).willReturn(HttpStatus.OK.value()); given(this.response.getStatusCode()).willReturn(HttpStatus.OK);
assertThat(this.errorHandler.hasError(this.response)).isFalse(); assertThat(this.errorHandler.hasError(this.response)).isFalse();
} }
@Test @Test
public void handleErrorStatusMatch() throws Exception { public void handleErrorStatusMatch() throws Exception {
given(this.response.getRawStatusCode()).willReturn(HttpStatus.I_AM_A_TEAPOT.value()); given(this.response.getStatusCode()).willReturn(HttpStatus.I_AM_A_TEAPOT);
HttpHeaders responseHeaders = new HttpHeaders(); HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.setContentType(MediaType.APPLICATION_JSON); responseHeaders.setContentType(MediaType.APPLICATION_JSON);
given(this.response.getHeaders()).willReturn(responseHeaders); given(this.response.getHeaders()).willReturn(responseHeaders);
@@ -103,7 +103,7 @@ public class ExtractingResponseErrorHandlerTests {
@Test @Test
public void handleErrorSeriesMatch() throws Exception { public void handleErrorSeriesMatch() throws Exception {
given(this.response.getRawStatusCode()).willReturn(HttpStatus.INTERNAL_SERVER_ERROR.value()); given(this.response.getStatusCode()).willReturn(HttpStatus.INTERNAL_SERVER_ERROR);
HttpHeaders responseHeaders = new HttpHeaders(); HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.setContentType(MediaType.APPLICATION_JSON); responseHeaders.setContentType(MediaType.APPLICATION_JSON);
given(this.response.getHeaders()).willReturn(responseHeaders); given(this.response.getHeaders()).willReturn(responseHeaders);
@@ -119,7 +119,7 @@ public class ExtractingResponseErrorHandlerTests {
@Test @Test
public void handleNoMatch() throws Exception { public void handleNoMatch() throws Exception {
given(this.response.getRawStatusCode()).willReturn(HttpStatus.NOT_FOUND.value()); given(this.response.getStatusCode()).willReturn(HttpStatus.NOT_FOUND);
HttpHeaders responseHeaders = new HttpHeaders(); HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.setContentType(MediaType.APPLICATION_JSON); responseHeaders.setContentType(MediaType.APPLICATION_JSON);
given(this.response.getHeaders()).willReturn(responseHeaders); given(this.response.getHeaders()).willReturn(responseHeaders);
@@ -141,7 +141,7 @@ public class ExtractingResponseErrorHandlerTests {
this.errorHandler.setSeriesMapping(Collections this.errorHandler.setSeriesMapping(Collections
.singletonMap(HttpStatus.Series.CLIENT_ERROR, null)); .singletonMap(HttpStatus.Series.CLIENT_ERROR, null));
given(this.response.getRawStatusCode()).willReturn(HttpStatus.NOT_FOUND.value()); given(this.response.getStatusCode()).willReturn(HttpStatus.NOT_FOUND);
HttpHeaders responseHeaders = new HttpHeaders(); HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.setContentType(MediaType.APPLICATION_JSON); responseHeaders.setContentType(MediaType.APPLICATION_JSON);
given(this.response.getHeaders()).willReturn(responseHeaders); given(this.response.getHeaders()).willReturn(responseHeaders);

View File

@@ -72,7 +72,7 @@ class HttpMessageConverterExtractorTests {
@Test @Test
void noContent() throws IOException { void noContent() throws IOException {
given(response.getRawStatusCode()).willReturn(HttpStatus.NO_CONTENT.value()); given(response.getStatusCode()).willReturn(HttpStatus.NO_CONTENT);
Object result = extractor.extractData(response); Object result = extractor.extractData(response);
assertThat(result).isNull(); assertThat(result).isNull();
@@ -80,7 +80,7 @@ class HttpMessageConverterExtractorTests {
@Test @Test
void notModified() throws IOException { void notModified() throws IOException {
given(response.getRawStatusCode()).willReturn(HttpStatus.NOT_MODIFIED.value()); given(response.getStatusCode()).willReturn(HttpStatus.NOT_MODIFIED);
Object result = extractor.extractData(response); Object result = extractor.extractData(response);
assertThat(result).isNull(); assertThat(result).isNull();
@@ -88,7 +88,7 @@ class HttpMessageConverterExtractorTests {
@Test @Test
void informational() throws IOException { void informational() throws IOException {
given(response.getRawStatusCode()).willReturn(HttpStatus.CONTINUE.value()); given(response.getStatusCode()).willReturn(HttpStatus.CONTINUE);
Object result = extractor.extractData(response); Object result = extractor.extractData(response);
assertThat(result).isNull(); assertThat(result).isNull();
@@ -97,7 +97,7 @@ class HttpMessageConverterExtractorTests {
@Test @Test
void zeroContentLength() throws IOException { void zeroContentLength() throws IOException {
responseHeaders.setContentLength(0); responseHeaders.setContentLength(0);
given(response.getRawStatusCode()).willReturn(HttpStatus.OK.value()); given(response.getStatusCode()).willReturn(HttpStatus.OK);
given(response.getHeaders()).willReturn(responseHeaders); given(response.getHeaders()).willReturn(responseHeaders);
Object result = extractor.extractData(response); Object result = extractor.extractData(response);
@@ -106,7 +106,7 @@ class HttpMessageConverterExtractorTests {
@Test @Test
void emptyMessageBody() throws IOException { void emptyMessageBody() throws IOException {
given(response.getRawStatusCode()).willReturn(HttpStatus.OK.value()); given(response.getStatusCode()).willReturn(HttpStatus.OK);
given(response.getHeaders()).willReturn(responseHeaders); given(response.getHeaders()).willReturn(responseHeaders);
given(response.getBody()).willReturn(new ByteArrayInputStream("".getBytes())); given(response.getBody()).willReturn(new ByteArrayInputStream("".getBytes()));
@@ -116,7 +116,7 @@ class HttpMessageConverterExtractorTests {
@Test // gh-22265 @Test // gh-22265
void nullMessageBody() throws IOException { void nullMessageBody() throws IOException {
given(response.getRawStatusCode()).willReturn(HttpStatus.OK.value()); given(response.getStatusCode()).willReturn(HttpStatus.OK);
given(response.getHeaders()).willReturn(responseHeaders); given(response.getHeaders()).willReturn(responseHeaders);
given(response.getBody()).willReturn(null); given(response.getBody()).willReturn(null);
@@ -128,7 +128,7 @@ class HttpMessageConverterExtractorTests {
void normal() throws IOException { void normal() throws IOException {
responseHeaders.setContentType(contentType); responseHeaders.setContentType(contentType);
String expected = "Foo"; String expected = "Foo";
given(response.getRawStatusCode()).willReturn(HttpStatus.OK.value()); given(response.getStatusCode()).willReturn(HttpStatus.OK);
given(response.getHeaders()).willReturn(responseHeaders); given(response.getHeaders()).willReturn(responseHeaders);
given(response.getBody()).willReturn(new ByteArrayInputStream(expected.getBytes())); given(response.getBody()).willReturn(new ByteArrayInputStream(expected.getBytes()));
given(converter.canRead(String.class, contentType)).willReturn(true); given(converter.canRead(String.class, contentType)).willReturn(true);
@@ -141,7 +141,7 @@ class HttpMessageConverterExtractorTests {
@Test @Test
void cannotRead() throws IOException { void cannotRead() throws IOException {
responseHeaders.setContentType(contentType); responseHeaders.setContentType(contentType);
given(response.getRawStatusCode()).willReturn(HttpStatus.OK.value()); given(response.getStatusCode()).willReturn(HttpStatus.OK);
given(response.getHeaders()).willReturn(responseHeaders); given(response.getHeaders()).willReturn(responseHeaders);
given(response.getBody()).willReturn(new ByteArrayInputStream("Foobar".getBytes())); given(response.getBody()).willReturn(new ByteArrayInputStream("Foobar".getBytes()));
given(converter.canRead(String.class, contentType)).willReturn(false); given(converter.canRead(String.class, contentType)).willReturn(false);
@@ -159,7 +159,7 @@ class HttpMessageConverterExtractorTests {
GenericHttpMessageConverter<String> converter = mock(GenericHttpMessageConverter.class); GenericHttpMessageConverter<String> converter = mock(GenericHttpMessageConverter.class);
HttpMessageConverterExtractor<?> extractor = new HttpMessageConverterExtractor<List<String>>(type, asList(converter)); HttpMessageConverterExtractor<?> extractor = new HttpMessageConverterExtractor<List<String>>(type, asList(converter));
given(response.getRawStatusCode()).willReturn(HttpStatus.OK.value()); given(response.getStatusCode()).willReturn(HttpStatus.OK);
given(response.getHeaders()).willReturn(responseHeaders); given(response.getHeaders()).willReturn(responseHeaders);
given(response.getBody()).willReturn(new ByteArrayInputStream(expected.getBytes())); given(response.getBody()).willReturn(new ByteArrayInputStream(expected.getBytes()));
given(converter.canRead(type, null, contentType)).willReturn(true); given(converter.canRead(type, null, contentType)).willReturn(true);
@@ -172,7 +172,7 @@ class HttpMessageConverterExtractorTests {
@Test // SPR-13592 @Test // SPR-13592
void converterThrowsIOException() throws IOException { void converterThrowsIOException() throws IOException {
responseHeaders.setContentType(contentType); responseHeaders.setContentType(contentType);
given(response.getRawStatusCode()).willReturn(HttpStatus.OK.value()); given(response.getStatusCode()).willReturn(HttpStatus.OK);
given(response.getHeaders()).willReturn(responseHeaders); given(response.getHeaders()).willReturn(responseHeaders);
given(response.getBody()).willReturn(new ByteArrayInputStream("Foobar".getBytes())); given(response.getBody()).willReturn(new ByteArrayInputStream("Foobar".getBytes()));
given(converter.canRead(String.class, contentType)).willReturn(true); given(converter.canRead(String.class, contentType)).willReturn(true);
@@ -185,7 +185,7 @@ class HttpMessageConverterExtractorTests {
@Test // SPR-13592 @Test // SPR-13592
void converterThrowsHttpMessageNotReadableException() throws IOException { void converterThrowsHttpMessageNotReadableException() throws IOException {
responseHeaders.setContentType(contentType); responseHeaders.setContentType(contentType);
given(response.getRawStatusCode()).willReturn(HttpStatus.OK.value()); given(response.getStatusCode()).willReturn(HttpStatus.OK);
given(response.getHeaders()).willReturn(responseHeaders); given(response.getHeaders()).willReturn(responseHeaders);
given(response.getBody()).willReturn(new ByteArrayInputStream("Foobar".getBytes())); given(response.getBody()).willReturn(new ByteArrayInputStream("Foobar".getBytes()));
given(converter.canRead(String.class, contentType)).willThrow(HttpMessageNotReadableException.class); given(converter.canRead(String.class, contentType)).willThrow(HttpMessageNotReadableException.class);
@@ -197,7 +197,7 @@ class HttpMessageConverterExtractorTests {
@Test @Test
void unknownContentTypeExceptionContainsCorrectResponseBody() throws IOException { void unknownContentTypeExceptionContainsCorrectResponseBody() throws IOException {
responseHeaders.setContentType(contentType); responseHeaders.setContentType(contentType);
given(response.getRawStatusCode()).willReturn(HttpStatus.OK.value()); given(response.getStatusCode()).willReturn(HttpStatus.OK);
given(response.getHeaders()).willReturn(responseHeaders); given(response.getHeaders()).willReturn(responseHeaders);
given(response.getBody()).willReturn(new ByteArrayInputStream("Foobar".getBytes()) { given(response.getBody()).willReturn(new ByteArrayInputStream("Foobar".getBytes()) {
@Override @Override

View File

@@ -30,6 +30,7 @@ import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.core.io.buffer.DefaultDataBufferFactory; import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.ResponseCookie; import org.springframework.http.ResponseCookie;
import org.springframework.http.client.reactive.ClientHttpResponse; import org.springframework.http.client.reactive.ClientHttpResponse;
@@ -46,7 +47,7 @@ import org.springframework.util.MultiValueMap;
*/ */
public class MockClientHttpResponse implements ClientHttpResponse { public class MockClientHttpResponse implements ClientHttpResponse {
private final int status; private final HttpStatusCode statusCode;
private final HttpHeaders headers = new HttpHeaders(); private final HttpHeaders headers = new HttpHeaders();
@@ -55,25 +56,25 @@ public class MockClientHttpResponse implements ClientHttpResponse {
private Flux<DataBuffer> body = Flux.empty(); private Flux<DataBuffer> body = Flux.empty();
public MockClientHttpResponse(HttpStatus status) {
Assert.notNull(status, "HttpStatus is required");
this.status = status.value();
}
public MockClientHttpResponse(int status) { public MockClientHttpResponse(int status) {
Assert.isTrue(status > 99 && status < 1000, "Status must be between 100 and 999"); this(HttpStatusCode.valueOf(status));
this.status = status; }
public MockClientHttpResponse(HttpStatusCode status) {
Assert.notNull(status, "HttpStatusCode is required");
this.statusCode = status;
} }
@Override @Override
public HttpStatus getStatusCode() { public HttpStatusCode getStatusCode() {
return HttpStatus.valueOf(this.status); return this.statusCode;
} }
@Override @Override
@Deprecated
public int getRawStatusCode() { public int getRawStatusCode() {
return this.status; return this.statusCode.value();
} }
@Override @Override
@@ -140,7 +141,11 @@ public class MockClientHttpResponse implements ClientHttpResponse {
@Override @Override
public String toString() { public String toString() {
HttpStatus code = HttpStatus.resolve(this.status); if (this.statusCode instanceof HttpStatus status) {
return (code != null ? code.name() + "(" + this.status + ")" : "Status (" + this.status + ")") + this.headers; return status.name() + "(" + this.statusCode + ")" + this.headers;
}
else {
return "Status (" + this.statusCode + ")" + this.headers;
}
} }
} }

View File

@@ -30,7 +30,7 @@ import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.io.buffer.DataBuffer; import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpRequest; import org.springframework.http.HttpRequest;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.ResponseCookie; import org.springframework.http.ResponseCookie;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
@@ -52,21 +52,18 @@ import org.springframework.web.reactive.function.BodyExtractor;
public interface ClientResponse { public interface ClientResponse {
/** /**
* Return the HTTP status code as an {@link HttpStatus} enum value. * Return the HTTP status code as an {@link HttpStatusCode} value.
* @return the HTTP status as an HttpStatus enum value (never {@code null}) * @return the HTTP status as an HttpStatusCode value (never {@code null})
* @throws IllegalArgumentException in case of an unknown HTTP status code
* @since #getRawStatusCode()
* @see HttpStatus#valueOf(int)
*/ */
HttpStatus statusCode(); HttpStatusCode statusCode();
/** /**
* Return the (potentially non-standard) status code of this response. * Return the raw status code of this response.
* @return the HTTP status as an integer value * @return the HTTP status as an integer value
* @since 5.1 * @since 5.1
* @see #statusCode() * @deprecated as of 6.0, in favor of {@link #statusCode()}
* @see HttpStatus#resolve(int)
*/ */
@Deprecated
int rawStatusCode(); int rawStatusCode();
/** /**
@@ -238,7 +235,7 @@ public interface ClientResponse {
* @param statusCode the status code * @param statusCode the status code
* @return the created builder * @return the created builder
*/ */
static Builder create(HttpStatus statusCode) { static Builder create(HttpStatusCode statusCode) {
return create(statusCode, ExchangeStrategies.withDefaults()); return create(statusCode, ExchangeStrategies.withDefaults());
} }
@@ -248,7 +245,7 @@ public interface ClientResponse {
* @param strategies the strategies * @param strategies the strategies
* @return the created builder * @return the created builder
*/ */
static Builder create(HttpStatus statusCode, ExchangeStrategies strategies) { static Builder create(HttpStatusCode statusCode, ExchangeStrategies strategies) {
return new DefaultClientResponseBuilder(strategies).statusCode(statusCode); return new DefaultClientResponseBuilder(strategies).statusCode(statusCode);
} }
@@ -269,7 +266,7 @@ public interface ClientResponse {
* @param messageReaders the message readers * @param messageReaders the message readers
* @return the created builder * @return the created builder
*/ */
static Builder create(HttpStatus statusCode, List<HttpMessageReader<?>> messageReaders) { static Builder create(HttpStatusCode statusCode, List<HttpMessageReader<?>> messageReaders) {
return create(statusCode, new ExchangeStrategies() { return create(statusCode, new ExchangeStrategies() {
@Override @Override
public List<HttpMessageReader<?>> messageReaders() { public List<HttpMessageReader<?>> messageReaders() {
@@ -326,7 +323,7 @@ public interface ClientResponse {
* @param statusCode the new status code * @param statusCode the new status code
* @return this builder * @return this builder
*/ */
Builder statusCode(HttpStatus statusCode); Builder statusCode(HttpStatusCode statusCode);
/** /**
* Set the raw status code of the response. * Set the raw status code of the response.

View File

@@ -34,6 +34,7 @@ import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpRequest; import org.springframework.http.HttpRequest;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.ResponseCookie; import org.springframework.http.ResponseCookie;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
@@ -106,11 +107,12 @@ class DefaultClientResponse implements ClientResponse {
} }
@Override @Override
public HttpStatus statusCode() { public HttpStatusCode statusCode() {
return this.response.getStatusCode(); return this.response.getStatusCode();
} }
@Override @Override
@Deprecated
public int rawStatusCode() { public int rawStatusCode() {
return this.response.getRawStatusCode(); return this.response.getRawStatusCode();
} }
@@ -201,9 +203,8 @@ class DefaultClientResponse implements ClientResponse {
.map(bodyBytes -> { .map(bodyBytes -> {
HttpRequest request = this.requestSupplier.get(); HttpRequest request = this.requestSupplier.get();
Charset charset = headers().contentType().map(MimeType::getCharset).orElse(null); Charset charset = headers().contentType().map(MimeType::getCharset).orElse(null);
int statusCode = rawStatusCode(); HttpStatusCode statusCode = statusCode();
HttpStatus httpStatus = HttpStatus.resolve(statusCode); if (statusCode instanceof HttpStatus httpStatus) {
if (httpStatus != null) {
return WebClientResponseException.create( return WebClientResponseException.create(
statusCode, statusCode,
httpStatus.getReasonPhrase(), httpStatus.getReasonPhrase(),

View File

@@ -30,6 +30,7 @@ import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.http.HttpRequest; import org.springframework.http.HttpRequest;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.ResponseCookie; import org.springframework.http.ResponseCookie;
import org.springframework.http.client.reactive.ClientHttpResponse; import org.springframework.http.client.reactive.ClientHttpResponse;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
@@ -75,7 +76,7 @@ final class DefaultClientResponseBuilder implements ClientResponse.Builder {
private final ExchangeStrategies strategies; private final ExchangeStrategies strategies;
private int statusCode = 200; private HttpStatusCode statusCode = HttpStatus.OK;
@Nullable @Nullable
private HttpHeaders headers; private HttpHeaders headers;
@@ -102,7 +103,7 @@ final class DefaultClientResponseBuilder implements ClientResponse.Builder {
DefaultClientResponseBuilder(ClientResponse other, boolean mutate) { DefaultClientResponseBuilder(ClientResponse other, boolean mutate) {
Assert.notNull(other, "ClientResponse must not be null"); Assert.notNull(other, "ClientResponse must not be null");
this.strategies = other.strategies(); this.strategies = other.strategies();
this.statusCode = other.rawStatusCode(); this.statusCode = other.statusCode();
if (mutate) { if (mutate) {
this.body = other.bodyToFlux(DataBuffer.class); this.body = other.bodyToFlux(DataBuffer.class);
} }
@@ -117,15 +118,15 @@ final class DefaultClientResponseBuilder implements ClientResponse.Builder {
@Override @Override
public DefaultClientResponseBuilder statusCode(HttpStatus statusCode) { public DefaultClientResponseBuilder statusCode(HttpStatusCode statusCode) {
return rawStatusCode(statusCode.value()); Assert.notNull(statusCode, "StatusCode must not be null");
this.statusCode = statusCode;
return this;
} }
@Override @Override
public DefaultClientResponseBuilder rawStatusCode(int statusCode) { public DefaultClientResponseBuilder rawStatusCode(int statusCode) {
Assert.isTrue(statusCode >= 100 && statusCode < 600, "StatusCode must be between 1xx and 5xx"); return statusCode(HttpStatusCode.valueOf(statusCode));
this.statusCode = statusCode;
return this;
} }
@Override @Override
@@ -224,7 +225,7 @@ final class DefaultClientResponseBuilder implements ClientResponse.Builder {
private static class BuiltClientHttpResponse implements ClientHttpResponse { private static class BuiltClientHttpResponse implements ClientHttpResponse {
private final int statusCode; private final HttpStatusCode statusCode;
@Nullable @Nullable
private final HttpHeaders headers; private final HttpHeaders headers;
@@ -238,7 +239,7 @@ final class DefaultClientResponseBuilder implements ClientResponse.Builder {
private final ClientResponse originalResponse; private final ClientResponse originalResponse;
BuiltClientHttpResponse(int statusCode, @Nullable HttpHeaders headers, BuiltClientHttpResponse(HttpStatusCode statusCode, @Nullable HttpHeaders headers,
@Nullable MultiValueMap<String, ResponseCookie> cookies, Flux<DataBuffer> body, @Nullable MultiValueMap<String, ResponseCookie> cookies, Flux<DataBuffer> body,
@Nullable ClientResponse originalResponse) { @Nullable ClientResponse originalResponse) {
@@ -256,13 +257,14 @@ final class DefaultClientResponseBuilder implements ClientResponse.Builder {
} }
@Override @Override
public HttpStatus getStatusCode() { public HttpStatusCode getStatusCode() {
return HttpStatus.valueOf(this.statusCode); return this.statusCode;
} }
@Override @Override
@Deprecated
public int getRawStatusCode() { public int getRawStatusCode() {
return this.statusCode; return this.statusCode.value();
} }
@Override @Override

View File

@@ -39,7 +39,7 @@ import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.http.HttpRequest; import org.springframework.http.HttpRequest;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.http.client.reactive.ClientHttpRequest; import org.springframework.http.client.reactive.ClientHttpRequest;
@@ -491,7 +491,7 @@ class DefaultWebClient implements WebClient {
private static class DefaultResponseSpec implements ResponseSpec { private static class DefaultResponseSpec implements ResponseSpec {
private static final IntPredicate STATUS_CODE_ERROR = (value -> value >= 400); private static final Predicate<HttpStatusCode> STATUS_CODE_ERROR = HttpStatusCode::isError;
private static final StatusHandler DEFAULT_STATUS_HANDLER = private static final StatusHandler DEFAULT_STATUS_HANDLER =
new StatusHandler(STATUS_CODE_ERROR, ClientResponse::createException); new StatusHandler(STATUS_CODE_ERROR, ClientResponse::createException);
@@ -511,28 +511,26 @@ class DefaultWebClient implements WebClient {
@Override @Override
public ResponseSpec onStatus(Predicate<HttpStatus> statusPredicate, public ResponseSpec onStatus(Predicate<HttpStatusCode> statusCodePredicate,
Function<ClientResponse, Mono<? extends Throwable>> exceptionFunction) { Function<ClientResponse, Mono<? extends Throwable>> exceptionFunction) {
return onRawStatus(toIntPredicate(statusPredicate), exceptionFunction); Assert.notNull(statusCodePredicate, "StatusCodePredicate must not be null");
} Assert.notNull(exceptionFunction, "Function must not be null");
int index = this.statusHandlers.size() - 1; // Default handler always last
this.statusHandlers.add(index, new StatusHandler(statusCodePredicate, exceptionFunction));
return this;
private static IntPredicate toIntPredicate(Predicate<HttpStatus> predicate) {
return value -> {
HttpStatus status = HttpStatus.resolve(value);
return (status != null && predicate.test(status));
};
} }
@Override @Override
public ResponseSpec onRawStatus(IntPredicate statusCodePredicate, public ResponseSpec onRawStatus(IntPredicate statusCodePredicate,
Function<ClientResponse, Mono<? extends Throwable>> exceptionFunction) { Function<ClientResponse, Mono<? extends Throwable>> exceptionFunction) {
Assert.notNull(statusCodePredicate, "IntPredicate must not be null"); return onStatus(toStatusCodePredicate(statusCodePredicate), exceptionFunction);
Assert.notNull(exceptionFunction, "Function must not be null"); }
int index = this.statusHandlers.size() - 1; // Default handler always last
this.statusHandlers.add(index, new StatusHandler(statusCodePredicate, exceptionFunction)); private static Predicate<HttpStatusCode> toStatusCodePredicate(IntPredicate predicate) {
return this; return value -> predicate.test(value.value());
} }
@Override @Override
@@ -635,7 +633,7 @@ class DefaultWebClient implements WebClient {
ResponseEntity<Flux<T>> entity = new ResponseEntity<>( ResponseEntity<Flux<T>> entity = new ResponseEntity<>(
body.onErrorResume(WebClientUtils.WRAP_EXCEPTION_PREDICATE, exceptionWrappingFunction(response)), body.onErrorResume(WebClientUtils.WRAP_EXCEPTION_PREDICATE, exceptionWrappingFunction(response)),
response.headers().asHttpHeaders(), response.headers().asHttpHeaders(),
response.rawStatusCode()); response.statusCode());
Mono<ResponseEntity<Flux<T>>> result = applyStatusHandlers(response); Mono<ResponseEntity<Flux<T>>> result = applyStatusHandlers(response);
return (result != null ? result.defaultIfEmpty(entity) : Mono.just(entity)); return (result != null ? result.defaultIfEmpty(entity) : Mono.just(entity));
@@ -647,7 +645,7 @@ class DefaultWebClient implements WebClient {
@Nullable @Nullable
private <T> Mono<T> applyStatusHandlers(ClientResponse response) { private <T> Mono<T> applyStatusHandlers(ClientResponse response) {
int statusCode = response.rawStatusCode(); HttpStatusCode statusCode = response.statusCode();
for (StatusHandler handler : this.statusHandlers) { for (StatusHandler handler : this.statusHandlers) {
if (handler.test(statusCode)) { if (handler.test(statusCode)) {
Mono<? extends Throwable> exMono; Mono<? extends Throwable> exMono;
@@ -667,7 +665,7 @@ class DefaultWebClient implements WebClient {
return null; return null;
} }
private <T> Mono<T> insertCheckpoint(Mono<T> result, int statusCode, HttpRequest request) { private <T> Mono<T> insertCheckpoint(Mono<T> result, HttpStatusCode statusCode, HttpRequest request) {
HttpMethod httpMethod = request.getMethod(); HttpMethod httpMethod = request.getMethod();
URI uri = request.getURI(); URI uri = request.getURI();
String description = statusCode + " from " + httpMethod + " " + uri + " [DefaultWebClient]"; String description = statusCode + " from " + httpMethod + " " + uri + " [DefaultWebClient]";
@@ -677,18 +675,18 @@ class DefaultWebClient implements WebClient {
private static class StatusHandler { private static class StatusHandler {
private final IntPredicate predicate; private final Predicate<HttpStatusCode> predicate;
private final Function<ClientResponse, Mono<? extends Throwable>> exceptionFunction; private final Function<ClientResponse, Mono<? extends Throwable>> exceptionFunction;
public StatusHandler(IntPredicate predicate, public StatusHandler(Predicate<HttpStatusCode> predicate,
Function<ClientResponse, Mono<? extends Throwable>> exceptionFunction) { Function<ClientResponse, Mono<? extends Throwable>> exceptionFunction) {
this.predicate = predicate; this.predicate = predicate;
this.exceptionFunction = exceptionFunction; this.exceptionFunction = exceptionFunction;
} }
public boolean test(int status) { public boolean test(HttpStatusCode status) {
return this.predicate.test(status); return this.predicate.test(status);
} }

View File

@@ -26,7 +26,7 @@ import reactor.core.publisher.Mono;
import org.springframework.core.io.buffer.DataBufferUtils; import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.util.Assert; import org.springframework.util.Assert;
@@ -66,12 +66,12 @@ public abstract class ExchangeFilterFunctions {
/** /**
* Return a filter that generates an error signal when the given * Return a filter that generates an error signal when the given
* {@link HttpStatus} predicate matches. * {@link HttpStatusCode} predicate matches.
* @param statusPredicate the predicate to check the HTTP status with * @param statusPredicate the predicate to check the HTTP status with
* @param exceptionFunction the function that to create the exception * @param exceptionFunction the function that to create the exception
* @return the filter to generate an error signal * @return the filter to generate an error signal
*/ */
public static ExchangeFilterFunction statusError(Predicate<HttpStatus> statusPredicate, public static ExchangeFilterFunction statusError(Predicate<HttpStatusCode> statusPredicate,
Function<ClientResponse, ? extends Throwable> exceptionFunction) { Function<ClientResponse, ? extends Throwable> exceptionFunction) {
Assert.notNull(statusPredicate, "Predicate must not be null"); Assert.notNull(statusPredicate, "Predicate must not be null");

View File

@@ -26,7 +26,6 @@ import org.springframework.core.log.LogFormatUtils;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.http.HttpRequest; import org.springframework.http.HttpRequest;
import org.springframework.http.HttpStatus;
import org.springframework.http.client.reactive.ClientHttpConnector; import org.springframework.http.client.reactive.ClientHttpConnector;
import org.springframework.http.client.reactive.ClientHttpResponse; import org.springframework.http.client.reactive.ClientHttpResponse;
import org.springframework.http.codec.LoggingCodecSupport; import org.springframework.http.codec.LoggingCodecSupport;
@@ -125,12 +124,8 @@ public abstract class ExchangeFunctions {
} }
private void logResponse(ClientHttpResponse response, String logPrefix) { private void logResponse(ClientHttpResponse response, String logPrefix) {
LogFormatUtils.traceDebug(logger, traceOn -> { LogFormatUtils.traceDebug(logger, traceOn -> logPrefix + "Response " + response.getStatusCode() +
int code = response.getRawStatusCode(); (traceOn ? ", headers=" + formatHeaders(response.getHeaders()) : ""));
HttpStatus status = HttpStatus.resolve(code);
return logPrefix + "Response " + (status != null ? status : code) +
(traceOn ? ", headers=" + formatHeaders(response.getHeaders()) : "");
});
} }
private String formatHeaders(HttpHeaders headers) { private String formatHeaders(HttpHeaders headers) {

View File

@@ -20,6 +20,7 @@ import java.nio.charset.Charset;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpRequest; import org.springframework.http.HttpRequest;
import org.springframework.http.HttpStatusCode;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
/** /**
@@ -57,4 +58,17 @@ public class UnknownHttpStatusCodeException extends WebClientResponseException {
headers, responseBody, responseCharset, request); headers, responseBody, responseCharset, request);
} }
/**
* Create a new instance of the {@code UnknownHttpStatusCodeException} with the given
* parameters.
* @since 6.0
*/
public UnknownHttpStatusCodeException(
HttpStatusCode statusCode, HttpHeaders headers, byte[] responseBody, @Nullable Charset responseCharset,
@Nullable HttpRequest request) {
super("Unknown status code [" + statusCode + "]", statusCode, "",
headers, responseBody, responseCharset, request);
}
} }

View File

@@ -35,7 +35,7 @@ import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.ReactiveAdapterRegistry; import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.http.client.reactive.ClientHttpConnector; import org.springframework.http.client.reactive.ClientHttpConnector;
@@ -767,7 +767,7 @@ public interface WebClient {
* @return this builder * @return this builder
* @see ClientResponse#createException() * @see ClientResponse#createException()
*/ */
ResponseSpec onStatus(Predicate<HttpStatus> statusPredicate, ResponseSpec onStatus(Predicate<HttpStatusCode> statusPredicate,
Function<ClientResponse, Mono<? extends Throwable>> exceptionFunction); Function<ClientResponse, Mono<? extends Throwable>> exceptionFunction);
/** /**

View File

@@ -22,6 +22,7 @@ import java.nio.charset.StandardCharsets;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpRequest; import org.springframework.http.HttpRequest;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
/** /**
@@ -35,7 +36,7 @@ public class WebClientResponseException extends WebClientException {
private static final long serialVersionUID = 4127543205414951611L; private static final long serialVersionUID = 4127543205414951611L;
private final int statusCode; private final HttpStatusCode statusCode;
private final String statusText; private final String statusText;
@@ -68,11 +69,21 @@ public class WebClientResponseException extends WebClientException {
@Nullable HttpHeaders headers, @Nullable byte[] body, @Nullable Charset charset, @Nullable HttpHeaders headers, @Nullable byte[] body, @Nullable Charset charset,
@Nullable HttpRequest request) { @Nullable HttpRequest request) {
this(initMessage(status, reasonPhrase, request), status, reasonPhrase, headers, body, charset, request); this(HttpStatusCode.valueOf(status), reasonPhrase, headers, body, charset, request);
} }
private static String initMessage(int status, String reasonPhrase, @Nullable HttpRequest request) { /**
return status + " " + reasonPhrase + * Constructor with response data only, and a default message.
* @since 6.0
*/
public WebClientResponseException(HttpStatusCode statusCode, String reasonPhrase,
@Nullable HttpHeaders headers, @Nullable byte[] body, @Nullable Charset charset,
@Nullable HttpRequest request) {
this(initMessage(statusCode, reasonPhrase, request), statusCode, reasonPhrase, headers, body, charset, request);
}
private static String initMessage(HttpStatusCode status, String reasonPhrase, @Nullable HttpRequest request) {
return status.value() + " " + reasonPhrase +
(request != null ? " from " + request.getMethod() + " " + request.getURI() : ""); (request != null ? " from " + request.getMethod() + " " + request.getURI() : "");
} }
@@ -91,6 +102,17 @@ public class WebClientResponseException extends WebClientException {
public WebClientResponseException(String message, int statusCode, String statusText, public WebClientResponseException(String message, int statusCode, String statusText,
@Nullable HttpHeaders headers, @Nullable byte[] responseBody, @Nullable Charset charset, @Nullable HttpHeaders headers, @Nullable byte[] responseBody, @Nullable Charset charset,
@Nullable HttpRequest request) { @Nullable HttpRequest request) {
this(message, HttpStatusCode.valueOf(statusCode), statusText, headers, responseBody, charset, request);
}
/**
* Constructor with a prepared message.
* @since 6.0
*/
public WebClientResponseException(String message, HttpStatusCode statusCode, String statusText,
@Nullable HttpHeaders headers, @Nullable byte[] responseBody, @Nullable Charset charset,
@Nullable HttpRequest request) {
super(message); super(message);
@@ -107,15 +129,17 @@ public class WebClientResponseException extends WebClientException {
* Return the HTTP status code value. * Return the HTTP status code value.
* @throws IllegalArgumentException in case of an unknown HTTP status code * @throws IllegalArgumentException in case of an unknown HTTP status code
*/ */
public HttpStatus getStatusCode() { public HttpStatusCode getStatusCode() {
return HttpStatus.valueOf(this.statusCode); return this.statusCode;
} }
/** /**
* Return the raw HTTP status code value. * Return the raw HTTP status code value.
* @deprecated as of 6.0, in favor of {@link #getStatusCode()}
*/ */
@Deprecated
public int getRawStatusCode() { public int getRawStatusCode() {
return this.statusCode; return this.statusCode.value();
} }
/** /**
@@ -188,9 +212,18 @@ public class WebClientResponseException extends WebClientException {
public static WebClientResponseException create( public static WebClientResponseException create(
int statusCode, String statusText, HttpHeaders headers, byte[] body, int statusCode, String statusText, HttpHeaders headers, byte[] body,
@Nullable Charset charset, @Nullable HttpRequest request) { @Nullable Charset charset, @Nullable HttpRequest request) {
return create(HttpStatusCode.valueOf(statusCode), statusText, headers, body, charset, request);
}
HttpStatus httpStatus = HttpStatus.resolve(statusCode); /**
if (httpStatus != null) { * Create {@code WebClientResponseException} or an HTTP status specific subclass.
* @since 6.0
*/
public static WebClientResponseException create(
HttpStatusCode statusCode, String statusText, HttpHeaders headers, byte[] body,
@Nullable Charset charset, @Nullable HttpRequest request) {
if (statusCode instanceof HttpStatus httpStatus) {
switch (httpStatus) { switch (httpStatus) {
case BAD_REQUEST: case BAD_REQUEST:
return new WebClientResponseException.BadRequest(statusText, headers, body, charset, request); return new WebClientResponseException.BadRequest(statusText, headers, body, charset, request);

View File

@@ -53,7 +53,7 @@ abstract class WebClientUtils {
new ResponseEntity<>( new ResponseEntity<>(
body != VALUE_NONE ? (T) body : null, body != VALUE_NONE ? (T) body : null,
response.headers().asHttpHeaders(), response.headers().asHttpHeaders(),
response.rawStatusCode())); response.statusCode()));
} }
/** /**
@@ -61,7 +61,7 @@ abstract class WebClientUtils {
*/ */
public static <T> Mono<ResponseEntity<List<T>>> mapToEntityList(ClientResponse response, Publisher<T> body) { public static <T> Mono<ResponseEntity<List<T>>> mapToEntityList(ClientResponse response, Publisher<T> body) {
return Flux.from(body).collectList().map(list -> return Flux.from(body).collectList().map(list ->
new ResponseEntity<>(list, response.headers().asHttpHeaders(), response.rawStatusCode())); new ResponseEntity<>(list, response.headers().asHttpHeaders(), response.statusCode()));
} }
} }

View File

@@ -25,7 +25,7 @@ import reactor.core.publisher.Mono;
import org.springframework.core.ParameterizedTypeReference; import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.ResponseCookie; import org.springframework.http.ResponseCookie;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
@@ -74,11 +74,12 @@ public class ClientResponseWrapper implements ClientResponse {
} }
@Override @Override
public HttpStatus statusCode() { public HttpStatusCode statusCode() {
return this.delegate.statusCode(); return this.delegate.statusCode();
} }
@Override @Override
@Deprecated
public int rawStatusCode() { public int rawStatusCode() {
return this.delegate.rawStatusCode(); return this.delegate.rawStatusCode();
} }

View File

@@ -35,6 +35,7 @@ import org.springframework.http.CacheControl;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.ResponseCookie; import org.springframework.http.ResponseCookie;
import org.springframework.http.codec.HttpMessageWriter; import org.springframework.http.codec.HttpMessageWriter;
@@ -60,7 +61,7 @@ class DefaultEntityResponseBuilder<T> implements EntityResponse.Builder<T> {
private final BodyInserter<T, ? super ServerHttpResponse> inserter; private final BodyInserter<T, ? super ServerHttpResponse> inserter;
private int status = HttpStatus.OK.value(); private HttpStatusCode status = HttpStatus.OK;
private final HttpHeaders headers = new HttpHeaders(); private final HttpHeaders headers = new HttpHeaders();
@@ -76,16 +77,15 @@ class DefaultEntityResponseBuilder<T> implements EntityResponse.Builder<T> {
@Override @Override
public EntityResponse.Builder<T> status(HttpStatus status) { public EntityResponse.Builder<T> status(HttpStatusCode status) {
Assert.notNull(status, "HttpStatus must not be null"); Assert.notNull(status, "HttpStatusCode must not be null");
this.status = status.value(); this.status = status;
return this; return this;
} }
@Override @Override
public EntityResponse.Builder<T> status(int status) { public EntityResponse.Builder<T> status(int status) {
this.status = status; return status(HttpStatusCode.valueOf(status));
return this;
} }
@Override @Override
@@ -209,7 +209,7 @@ class DefaultEntityResponseBuilder<T> implements EntityResponse.Builder<T> {
private final BodyInserter<T, ? super ServerHttpResponse> inserter; private final BodyInserter<T, ? super ServerHttpResponse> inserter;
public DefaultEntityResponse(int statusCode, HttpHeaders headers, public DefaultEntityResponse(HttpStatusCode statusCode, HttpHeaders headers,
MultiValueMap<String, ResponseCookie> cookies, T entity, MultiValueMap<String, ResponseCookie> cookies, T entity,
BodyInserter<T, ? super ServerHttpResponse> inserter, Map<String, Object> hints) { BodyInserter<T, ? super ServerHttpResponse> inserter, Map<String, Object> hints) {

View File

@@ -33,6 +33,7 @@ import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.core.Conventions; import org.springframework.core.Conventions;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.ResponseCookie; import org.springframework.http.ResponseCookie;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
@@ -53,7 +54,7 @@ final class DefaultRenderingResponseBuilder implements RenderingResponse.Builder
private final String name; private final String name;
private int status = HttpStatus.OK.value(); private HttpStatusCode status = HttpStatus.OK;
private final HttpHeaders headers = new HttpHeaders(); private final HttpHeaders headers = new HttpHeaders();
@@ -65,8 +66,7 @@ final class DefaultRenderingResponseBuilder implements RenderingResponse.Builder
public DefaultRenderingResponseBuilder(RenderingResponse other) { public DefaultRenderingResponseBuilder(RenderingResponse other) {
Assert.notNull(other, "RenderingResponse must not be null"); Assert.notNull(other, "RenderingResponse must not be null");
this.name = other.name(); this.name = other.name();
this.status = (other instanceof DefaultRenderingResponse ? this.status = other.statusCode();
((DefaultRenderingResponse) other).statusCode : other.statusCode().value());
this.headers.putAll(other.headers()); this.headers.putAll(other.headers());
this.model.putAll(other.model()); this.model.putAll(other.model());
} }
@@ -78,16 +78,15 @@ final class DefaultRenderingResponseBuilder implements RenderingResponse.Builder
@Override @Override
public RenderingResponse.Builder status(HttpStatus status) { public RenderingResponse.Builder status(HttpStatusCode status) {
Assert.notNull(status, "HttpStatus must not be null"); Assert.notNull(status, "HttpStatusCode must not be null");
this.status = status.value(); this.status = status;
return this; return this;
} }
@Override @Override
public RenderingResponse.Builder status(int status) { public RenderingResponse.Builder status(int status) {
this.status = status; return status(HttpStatusCode.valueOf(status));
return this;
} }
@Override @Override
@@ -165,7 +164,7 @@ final class DefaultRenderingResponseBuilder implements RenderingResponse.Builder
private final Map<String, Object> model; private final Map<String, Object> model;
public DefaultRenderingResponse(int statusCode, HttpHeaders headers, public DefaultRenderingResponse(HttpStatusCode statusCode, HttpHeaders headers,
MultiValueMap<String, ResponseCookie> cookies, String name, Map<String, Object> model) { MultiValueMap<String, ResponseCookie> cookies, String name, Map<String, Object> model) {
super(statusCode, headers, cookies, Collections.emptyMap()); super(statusCode, headers, cookies, Collections.emptyMap());

View File

@@ -41,6 +41,8 @@ import org.springframework.http.HttpCookie;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.http.HttpRange; import org.springframework.http.HttpRange;
import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.codec.HttpMessageReader; import org.springframework.http.codec.HttpMessageReader;
import org.springframework.http.codec.multipart.Part; import org.springframework.http.codec.multipart.Part;
@@ -98,8 +100,8 @@ class DefaultServerRequest implements ServerRequest {
} }
if (exchange.checkNotModified(etag, lastModified)) { if (exchange.checkNotModified(etag, lastModified)) {
Integer statusCode = exchange.getResponse().getRawStatusCode(); HttpStatusCode statusCode = exchange.getResponse().getStatusCode();
return ServerResponse.status(statusCode != null ? statusCode : 200) return ServerResponse.status(statusCode != null ? statusCode : HttpStatus.OK)
.headers(headers -> headers.addAll(exchange.getResponse().getHeaders())) .headers(headers -> headers.addAll(exchange.getResponse().getHeaders()))
.build(); .build();
} }

View File

@@ -39,7 +39,7 @@ import org.springframework.core.codec.Hints;
import org.springframework.http.CacheControl; import org.springframework.http.CacheControl;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.ReactiveHttpOutputMessage; import org.springframework.http.ReactiveHttpOutputMessage;
import org.springframework.http.ResponseCookie; import org.springframework.http.ResponseCookie;
@@ -64,7 +64,7 @@ import org.springframework.web.server.ServerWebExchange;
*/ */
class DefaultServerResponseBuilder implements ServerResponse.BodyBuilder { class DefaultServerResponseBuilder implements ServerResponse.BodyBuilder {
private final int statusCode; private final HttpStatusCode statusCode;
private final HttpHeaders headers = new HttpHeaders(); private final HttpHeaders headers = new HttpHeaders();
@@ -77,22 +77,15 @@ class DefaultServerResponseBuilder implements ServerResponse.BodyBuilder {
Assert.notNull(other, "ServerResponse must not be null"); Assert.notNull(other, "ServerResponse must not be null");
this.headers.addAll(other.headers()); this.headers.addAll(other.headers());
this.cookies.addAll(other.cookies()); this.cookies.addAll(other.cookies());
this.statusCode = other.statusCode();
if (other instanceof AbstractServerResponse abstractOther) { if (other instanceof AbstractServerResponse abstractOther) {
this.statusCode = abstractOther.statusCode;
this.hints.putAll(abstractOther.hints); this.hints.putAll(abstractOther.hints);
} }
else {
this.statusCode = other.statusCode().value();
}
} }
public DefaultServerResponseBuilder(HttpStatus status) { public DefaultServerResponseBuilder(HttpStatusCode status) {
Assert.notNull(status, "HttpStatus must not be null"); Assert.notNull(status, "HttpStatusCode must not be null");
this.statusCode = status.value(); this.statusCode = status;
}
public DefaultServerResponseBuilder(int statusCode) {
this.statusCode = statusCode;
} }
@@ -298,7 +291,7 @@ class DefaultServerResponseBuilder implements ServerResponse.BodyBuilder {
private static final Set<HttpMethod> SAFE_METHODS = Set.of(HttpMethod.GET, HttpMethod.HEAD); private static final Set<HttpMethod> SAFE_METHODS = Set.of(HttpMethod.GET, HttpMethod.HEAD);
final int statusCode; private final HttpStatusCode statusCode;
private final HttpHeaders headers; private final HttpHeaders headers;
@@ -308,7 +301,7 @@ class DefaultServerResponseBuilder implements ServerResponse.BodyBuilder {
protected AbstractServerResponse( protected AbstractServerResponse(
int statusCode, HttpHeaders headers, MultiValueMap<String, ResponseCookie> cookies, HttpStatusCode statusCode, HttpHeaders headers, MultiValueMap<String, ResponseCookie> cookies,
Map<String, Object> hints) { Map<String, Object> hints) {
this.statusCode = statusCode; this.statusCode = statusCode;
@@ -318,13 +311,14 @@ class DefaultServerResponseBuilder implements ServerResponse.BodyBuilder {
} }
@Override @Override
public final HttpStatus statusCode() { public final HttpStatusCode statusCode() {
return HttpStatus.valueOf(this.statusCode); return this.statusCode;
} }
@Override @Override
@Deprecated
public int rawStatusCode() { public int rawStatusCode() {
return this.statusCode; return this.statusCode.value();
} }
@Override @Override
@@ -351,7 +345,7 @@ class DefaultServerResponseBuilder implements ServerResponse.BodyBuilder {
} }
private void writeStatusAndHeaders(ServerHttpResponse response) { private void writeStatusAndHeaders(ServerHttpResponse response) {
response.setRawStatusCode(this.statusCode); response.setStatusCode(this.statusCode);
copy(this.headers, response.getHeaders()); copy(this.headers, response.getHeaders());
copy(this.cookies, response.getCookies()); copy(this.cookies, response.getCookies());
} }
@@ -370,7 +364,7 @@ class DefaultServerResponseBuilder implements ServerResponse.BodyBuilder {
private final BiFunction<ServerWebExchange, Context, Mono<Void>> writeFunction; private final BiFunction<ServerWebExchange, Context, Mono<Void>> writeFunction;
public WriterFunctionResponse(int statusCode, HttpHeaders headers, public WriterFunctionResponse(HttpStatusCode statusCode, HttpHeaders headers,
MultiValueMap<String, ResponseCookie> cookies, MultiValueMap<String, ResponseCookie> cookies,
BiFunction<ServerWebExchange, Context, Mono<Void>> writeFunction) { BiFunction<ServerWebExchange, Context, Mono<Void>> writeFunction) {
@@ -391,7 +385,7 @@ class DefaultServerResponseBuilder implements ServerResponse.BodyBuilder {
private final BodyInserter<T, ? super ServerHttpResponse> inserter; private final BodyInserter<T, ? super ServerHttpResponse> inserter;
public BodyInserterResponse(int statusCode, HttpHeaders headers, public BodyInserterResponse(HttpStatusCode statusCode, HttpHeaders headers,
MultiValueMap<String, ResponseCookie> cookies, MultiValueMap<String, ResponseCookie> cookies,
BodyInserter<T, ? super ServerHttpResponse> body, Map<String, Object> hints) { BodyInserter<T, ? super ServerHttpResponse> body, Map<String, Object> hints) {

View File

@@ -30,7 +30,7 @@ import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.CacheControl; import org.springframework.http.CacheControl;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.ResponseCookie; import org.springframework.http.ResponseCookie;
import org.springframework.http.codec.json.Jackson2CodecSupport; import org.springframework.http.codec.json.Jackson2CodecSupport;
@@ -154,7 +154,7 @@ public interface EntityResponse<T> extends ServerResponse {
* @param status the response status * @param status the response status
* @return this builder * @return this builder
*/ */
Builder<T> status(HttpStatus status); Builder<T> status(HttpStatusCode status);
/** /**
* Set the HTTP status. * Set the HTTP status.

View File

@@ -23,7 +23,7 @@ import java.util.function.Consumer;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode;
import org.springframework.http.ResponseCookie; import org.springframework.http.ResponseCookie;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.util.MultiValueMap; import org.springframework.util.MultiValueMap;
@@ -134,7 +134,7 @@ public interface RenderingResponse extends ServerResponse {
* @param status the response status * @param status the response status
* @return this builder * @return this builder
*/ */
Builder status(HttpStatus status); Builder status(HttpStatusCode status);
/** /**
* Set the HTTP status. * Set the HTTP status.

View File

@@ -35,6 +35,7 @@ import org.springframework.http.CacheControl;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.ResponseCookie; import org.springframework.http.ResponseCookie;
import org.springframework.http.codec.HttpMessageWriter; import org.springframework.http.codec.HttpMessageWriter;
@@ -60,19 +61,17 @@ public interface ServerResponse {
/** /**
* Return the status code of this response. * Return the status code of this response.
* @return the status as an HttpStatus enum value * @return the status as an HttpStatusCode value
* @throws IllegalArgumentException in case of an unknown HTTP status code
* @see HttpStatus#valueOf(int)
*/ */
HttpStatus statusCode(); HttpStatusCode statusCode();
/** /**
* Return the (potentially non-standard) status code of this response. * Return the status code of this response as integer.
* @return the status as an integer * @return the status as an integer
* @since 5.2 * @since 5.2
* @see #statusCode() * @deprecated as of 6.0, in favor of {@link #statusCode()}
* @see HttpStatus#resolve(int)
*/ */
@Deprecated
int rawStatusCode(); int rawStatusCode();
/** /**
@@ -110,7 +109,7 @@ public interface ServerResponse {
* @param status the response status * @param status the response status
* @return the created builder * @return the created builder
*/ */
static BodyBuilder status(HttpStatus status) { static BodyBuilder status(HttpStatusCode status) {
return new DefaultServerResponseBuilder(status); return new DefaultServerResponseBuilder(status);
} }
@@ -121,7 +120,7 @@ public interface ServerResponse {
* @since 5.0.3 * @since 5.0.3
*/ */
static BodyBuilder status(int status) { static BodyBuilder status(int status) {
return new DefaultServerResponseBuilder(status); return new DefaultServerResponseBuilder(HttpStatusCode.valueOf(status));
} }
/** /**

View File

@@ -17,6 +17,7 @@
package org.springframework.web.reactive.handler; package org.springframework.web.reactive.handler;
import org.springframework.core.annotation.AnnotatedElementUtils; import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.http.HttpStatusCode;
import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.server.handler.ResponseStatusExceptionHandler; import org.springframework.web.server.handler.ResponseStatusExceptionHandler;
@@ -37,15 +38,15 @@ import org.springframework.web.server.handler.ResponseStatusExceptionHandler;
public class WebFluxResponseStatusExceptionHandler extends ResponseStatusExceptionHandler { public class WebFluxResponseStatusExceptionHandler extends ResponseStatusExceptionHandler {
@Override @Override
protected int determineRawStatusCode(Throwable ex) { protected HttpStatusCode determineStatus(Throwable ex) {
int status = super.determineRawStatusCode(ex); HttpStatusCode statusCode = super.determineStatus(ex);
if (status == -1) { if (statusCode == null) {
ResponseStatus ann = AnnotatedElementUtils.findMergedAnnotation(ex.getClass(), ResponseStatus.class); ResponseStatus ann = AnnotatedElementUtils.findMergedAnnotation(ex.getClass(), ResponseStatus.class);
if (ann != null) { if (ann != null) {
status = ann.code().value(); statusCode = ann.code();
} }
} }
return status; return statusCode;
} }
} }

View File

@@ -33,7 +33,7 @@ import org.springframework.core.MethodParameter;
import org.springframework.core.ParameterNameDiscoverer; import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.core.ReactiveAdapter; import org.springframework.core.ReactiveAdapter;
import org.springframework.core.ReactiveAdapterRegistry; import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode;
import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils; import org.springframework.util.ObjectUtils;
@@ -157,7 +157,7 @@ public class InvocableHandlerMethod extends HandlerMethod {
return Mono.error(new IllegalStateException(formatInvokeError("Invocation failure", args), ex)); return Mono.error(new IllegalStateException(formatInvokeError("Invocation failure", args), ex));
} }
HttpStatus status = getResponseStatus(); HttpStatusCode status = getResponseStatus();
if (status != null) { if (status != null) {
exchange.getResponse().setStatusCode(status); exchange.getResponse().setStatusCode(status);
} }

View File

@@ -30,7 +30,7 @@ import org.springframework.core.ReactiveAdapter;
import org.springframework.core.ReactiveAdapterRegistry; import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.core.ResolvableType; import org.springframework.core.ResolvableType;
import org.springframework.core.codec.Hints; import org.springframework.core.codec.Hints;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.codec.HttpMessageWriter; import org.springframework.http.codec.HttpMessageWriter;
import org.springframework.http.converter.HttpMessageNotWritableException; import org.springframework.http.converter.HttpMessageNotWritableException;
@@ -152,7 +152,7 @@ public abstract class AbstractMessageWriterResultHandler extends HandlerResultHa
bestMediaType = selectMediaType(exchange, () -> getMediaTypesFor(elementType)); bestMediaType = selectMediaType(exchange, () -> getMediaTypesFor(elementType));
} }
catch (NotAcceptableStatusException ex) { catch (NotAcceptableStatusException ex) {
HttpStatus statusCode = exchange.getResponse().getStatusCode(); HttpStatusCode statusCode = exchange.getResponse().getStatusCode();
if (statusCode != null && statusCode.isError()) { if (statusCode != null && statusCode.isError()) {
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("Ignoring error response content (if any). " + ex.getReason()); logger.debug("Ignoring error response content (if any). " + ex.getReason());

View File

@@ -141,7 +141,7 @@ public class ResponseEntityResultHandler extends AbstractMessageWriterResultHand
httpEntity = (HttpEntity<?>) returnValue; httpEntity = (HttpEntity<?>) returnValue;
} }
else if (returnValue instanceof ErrorResponse response) { else if (returnValue instanceof ErrorResponse response) {
httpEntity = new ResponseEntity<>(response.getBody(), response.getHeaders(), response.getRawStatusCode()); httpEntity = new ResponseEntity<>(response.getBody(), response.getHeaders(), response.getStatusCode());
} }
else if (returnValue instanceof ProblemDetail detail) { else if (returnValue instanceof ProblemDetail detail) {
httpEntity = new ResponseEntity<>(returnValue, HttpHeaders.EMPTY, detail.getStatus()); httpEntity = new ResponseEntity<>(returnValue, HttpHeaders.EMPTY, detail.getStatus());
@@ -161,9 +161,8 @@ public class ResponseEntityResultHandler extends AbstractMessageWriterResultHand
} }
} }
if (httpEntity instanceof ResponseEntity) { if (httpEntity instanceof ResponseEntity<?> responseEntity) {
exchange.getResponse().setRawStatusCode( exchange.getResponse().setStatusCode(responseEntity.getStatusCode());
((ResponseEntity<?>) httpEntity).getStatusCodeValue());
} }
HttpHeaders entityHeaders = httpEntity.getHeaders(); HttpHeaders entityHeaders = httpEntity.getHeaders();

View File

@@ -20,7 +20,7 @@ import java.util.Collections;
import java.util.Map; import java.util.Map;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.ui.Model; import org.springframework.ui.Model;
@@ -40,12 +40,12 @@ class DefaultRendering implements Rendering {
private final Map<String, Object> model; private final Map<String, Object> model;
@Nullable @Nullable
private final HttpStatus status; private final HttpStatusCode status;
private final HttpHeaders headers; private final HttpHeaders headers;
DefaultRendering(Object view, @Nullable Model model, @Nullable HttpStatus status, @Nullable HttpHeaders headers) { DefaultRendering(Object view, @Nullable Model model, @Nullable HttpStatusCode status, @Nullable HttpHeaders headers) {
this.view = view; this.view = view;
this.model = (model != null ? model.asMap() : Collections.emptyMap()); this.model = (model != null ? model.asMap() : Collections.emptyMap());
this.status = status; this.status = status;
@@ -66,7 +66,7 @@ class DefaultRendering implements Rendering {
@Override @Override
@Nullable @Nullable
public HttpStatus status() { public HttpStatusCode status() {
return this.status; return this.status;
} }

View File

@@ -20,7 +20,7 @@ import java.util.Arrays;
import java.util.Map; import java.util.Map;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.ui.ExtendedModelMap; import org.springframework.ui.ExtendedModelMap;
import org.springframework.ui.Model; import org.springframework.ui.Model;
@@ -40,7 +40,7 @@ class DefaultRenderingBuilder implements Rendering.RedirectBuilder {
private Model model; private Model model;
@Nullable @Nullable
private HttpStatus status; private HttpStatusCode status;
@Nullable @Nullable
private HttpHeaders headers; private HttpHeaders headers;
@@ -83,7 +83,7 @@ class DefaultRenderingBuilder implements Rendering.RedirectBuilder {
} }
@Override @Override
public DefaultRenderingBuilder status(HttpStatus status) { public DefaultRenderingBuilder status(HttpStatusCode status) {
this.status = status; this.status = status;
return this; return this;
} }

View File

@@ -27,6 +27,7 @@ import java.util.regex.Pattern;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.http.server.reactive.ServerHttpResponse;
@@ -56,7 +57,7 @@ public class RedirectView extends AbstractUrlBasedView {
private static final Pattern URI_TEMPLATE_VARIABLE_PATTERN = Pattern.compile("\\{([^/]+?)\\}"); private static final Pattern URI_TEMPLATE_VARIABLE_PATTERN = Pattern.compile("\\{([^/]+?)\\}");
private HttpStatus statusCode = HttpStatus.SEE_OTHER; private HttpStatusCode statusCode = HttpStatus.SEE_OTHER;
private boolean contextRelative = true; private boolean contextRelative = true;
@@ -85,7 +86,7 @@ public class RedirectView extends AbstractUrlBasedView {
* redirect status code such as {@link HttpStatus#TEMPORARY_REDIRECT} or * redirect status code such as {@link HttpStatus#TEMPORARY_REDIRECT} or
* {@link HttpStatus#PERMANENT_REDIRECT}. * {@link HttpStatus#PERMANENT_REDIRECT}.
*/ */
public RedirectView(String redirectUrl, HttpStatus statusCode) { public RedirectView(String redirectUrl, HttpStatusCode statusCode) {
super(redirectUrl); super(redirectUrl);
setStatusCode(statusCode); setStatusCode(statusCode);
} }
@@ -96,7 +97,7 @@ public class RedirectView extends AbstractUrlBasedView {
* {@link HttpStatus#TEMPORARY_REDIRECT} or * {@link HttpStatus#TEMPORARY_REDIRECT} or
* {@link HttpStatus#PERMANENT_REDIRECT}. * {@link HttpStatus#PERMANENT_REDIRECT}.
*/ */
public void setStatusCode(HttpStatus statusCode) { public void setStatusCode(HttpStatusCode statusCode) {
Assert.isTrue(statusCode.is3xxRedirection(), "Not a redirect status code"); Assert.isTrue(statusCode.is3xxRedirection(), "Not a redirect status code");
this.statusCode = statusCode; this.statusCode = statusCode;
} }
@@ -104,7 +105,7 @@ public class RedirectView extends AbstractUrlBasedView {
/** /**
* Get the redirect status code to use. * Get the redirect status code to use.
*/ */
public HttpStatus getStatusCode() { public HttpStatusCode getStatusCode() {
return this.statusCode; return this.statusCode;
} }

View File

@@ -20,7 +20,7 @@ import java.util.Collection;
import java.util.Map; import java.util.Map;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.ui.Model; import org.springframework.ui.Model;
@@ -58,7 +58,7 @@ public interface Rendering {
* Return the HTTP status to set the response to. * Return the HTTP status to set the response to.
*/ */
@Nullable @Nullable
HttpStatus status(); HttpStatusCode status();
/** /**
* Return headers to add to the response. * Return headers to add to the response.
@@ -121,7 +121,7 @@ public interface Rendering {
/** /**
* Specify the status to use for the response. * Specify the status to use for the response.
*/ */
B status(HttpStatus status); B status(HttpStatusCode status);
/** /**
* Specify a header to add to the response. * Specify a header to add to the response.

View File

@@ -37,7 +37,7 @@ import org.springframework.core.ReactiveAdapter;
import org.springframework.core.ReactiveAdapterRegistry; import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.core.ResolvableType; import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.ui.Model; import org.springframework.ui.Model;
@@ -214,7 +214,7 @@ public class ViewResolutionResultHandler extends HandlerResultHandlerSupport imp
} }
else if (Rendering.class.isAssignableFrom(clazz)) { else if (Rendering.class.isAssignableFrom(clazz)) {
Rendering render = (Rendering) returnValue; Rendering render = (Rendering) returnValue;
HttpStatus status = render.status(); HttpStatusCode status = render.status();
if (status != null) { if (status != null) {
exchange.getResponse().setStatusCode(status); exchange.getResponse().setStatusCode(status);
} }
@@ -325,7 +325,7 @@ public class ViewResolutionResultHandler extends HandlerResultHandlerSupport imp
bestMediaType = selectMediaType(exchange, () -> mediaTypes); bestMediaType = selectMediaType(exchange, () -> mediaTypes);
} }
catch (NotAcceptableStatusException ex) { catch (NotAcceptableStatusException ex) {
HttpStatus statusCode = exchange.getResponse().getStatusCode(); HttpStatusCode statusCode = exchange.getResponse().getStatusCode();
if (statusCode != null && statusCode.isError()) { if (statusCode != null && statusCode.isError()) {
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("Ignoring error response content (if any). " + ex.getReason()); logger.debug("Ignoring error response content (if any). " + ex.getReason());

View File

@@ -21,7 +21,7 @@ import kotlinx.coroutines.reactive.awaitSingle
import kotlinx.coroutines.reactor.mono import kotlinx.coroutines.reactor.mono
import org.springframework.core.io.Resource import org.springframework.core.io.Resource
import org.springframework.http.HttpMethod import org.springframework.http.HttpMethod
import org.springframework.http.HttpStatus import org.springframework.http.HttpStatusCode
import org.springframework.http.MediaType import org.springframework.http.MediaType
import org.springframework.web.reactive.function.server.RouterFunctions.nest import org.springframework.web.reactive.function.server.RouterFunctions.nest
import java.net.URI import java.net.URI
@@ -660,7 +660,7 @@ class CoRouterFunctionDsl internal constructor (private val init: (CoRouterFunct
/** /**
* @see ServerResponse.status * @see ServerResponse.status
*/ */
fun status(status: HttpStatus) = ServerResponse.status(status) fun status(status: HttpStatusCode) = ServerResponse.status(status)
/** /**
* @see ServerResponse.status * @see ServerResponse.status

View File

@@ -19,6 +19,7 @@ package org.springframework.web.reactive.function.server
import org.springframework.core.io.Resource import org.springframework.core.io.Resource
import org.springframework.http.HttpMethod import org.springframework.http.HttpMethod
import org.springframework.http.HttpStatus import org.springframework.http.HttpStatus
import org.springframework.http.HttpStatusCode
import org.springframework.http.MediaType import org.springframework.http.MediaType
import reactor.core.publisher.Mono import reactor.core.publisher.Mono
import java.net.URI import java.net.URI
@@ -725,7 +726,7 @@ class RouterFunctionDsl internal constructor (private val init: RouterFunctionDs
* @return the created builder * @return the created builder
* @since 5.1 * @since 5.1
*/ */
fun status(status: HttpStatus): ServerResponse.BodyBuilder = fun status(status: HttpStatusCode): ServerResponse.BodyBuilder =
ServerResponse.status(status) ServerResponse.status(status)
/** /**

View File

@@ -28,12 +28,12 @@ import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.http.HttpRequest; import org.springframework.http.HttpRequest;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.ResponseCookie; import org.springframework.http.ResponseCookie;
import org.springframework.web.testfixture.http.client.reactive.MockClientHttpRequest; import org.springframework.web.testfixture.http.client.reactive.MockClientHttpRequest;
import org.springframework.web.testfixture.http.client.reactive.MockClientHttpResponse; import org.springframework.web.testfixture.http.client.reactive.MockClientHttpResponse;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
/** /**
* @author Arjen Poutsma * @author Arjen Poutsma
@@ -106,6 +106,6 @@ public class DefaultClientResponseBuilderTests {
ClientResponse result = other.mutate().build(); ClientResponse result = other.mutate().build();
assertThat(result.rawStatusCode()).isEqualTo(499); assertThat(result.rawStatusCode()).isEqualTo(499);
assertThatIllegalArgumentException().isThrownBy(result::statusCode); assertThat(result.statusCode()).isEqualTo(HttpStatusCode.valueOf(499));
} }
} }

View File

@@ -39,6 +39,7 @@ import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpRange; import org.springframework.http.HttpRange;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.ResponseCookie; import org.springframework.http.ResponseCookie;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
@@ -49,7 +50,6 @@ import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap; import org.springframework.util.MultiValueMap;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.assertj.core.api.Assertions.entry; import static org.assertj.core.api.Assertions.entry;
import static org.mockito.BDDMockito.given; import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
@@ -233,8 +233,7 @@ public class DefaultClientResponseTests {
httpHeaders.setContentType(MediaType.TEXT_PLAIN); httpHeaders.setContentType(MediaType.TEXT_PLAIN);
given(mockResponse.getHeaders()).willReturn(httpHeaders); given(mockResponse.getHeaders()).willReturn(httpHeaders);
given(mockResponse.getStatusCode()).willThrow(new IllegalArgumentException("999")); given(mockResponse.getStatusCode()).willReturn(HttpStatusCode.valueOf(999));
given(mockResponse.getRawStatusCode()).willReturn(999);
given(mockResponse.getBody()).willReturn(body); given(mockResponse.getBody()).willReturn(body);
List<HttpMessageReader<?>> messageReaders = Collections List<HttpMessageReader<?>> messageReaders = Collections
@@ -243,8 +242,7 @@ public class DefaultClientResponseTests {
ResponseEntity<String> result = defaultClientResponse.toEntity(String.class).block(); ResponseEntity<String> result = defaultClientResponse.toEntity(String.class).block();
assertThat(result.getBody()).isEqualTo("foo"); assertThat(result.getBody()).isEqualTo("foo");
assertThatIllegalArgumentException().isThrownBy( assertThat(result.getStatusCode()).isEqualTo(HttpStatusCode.valueOf(999));
result::getStatusCode);
assertThat(result.getStatusCodeValue()).isEqualTo(999); assertThat(result.getStatusCodeValue()).isEqualTo(999);
assertThat(result.getHeaders().getContentType()).isEqualTo(MediaType.TEXT_PLAIN); assertThat(result.getHeaders().getContentType()).isEqualTo(MediaType.TEXT_PLAIN);
} }
@@ -295,8 +293,7 @@ public class DefaultClientResponseTests {
httpHeaders.setContentType(MediaType.TEXT_PLAIN); httpHeaders.setContentType(MediaType.TEXT_PLAIN);
given(mockResponse.getHeaders()).willReturn(httpHeaders); given(mockResponse.getHeaders()).willReturn(httpHeaders);
given(mockResponse.getStatusCode()).willThrow(new IllegalArgumentException("999")); given(mockResponse.getStatusCode()).willReturn(HttpStatusCode.valueOf(999));
given(mockResponse.getRawStatusCode()).willReturn(999);
given(mockResponse.getBody()).willReturn(body); given(mockResponse.getBody()).willReturn(body);
List<HttpMessageReader<?>> messageReaders = Collections List<HttpMessageReader<?>> messageReaders = Collections
@@ -305,8 +302,7 @@ public class DefaultClientResponseTests {
ResponseEntity<List<String>> result = defaultClientResponse.toEntityList(String.class).block(); ResponseEntity<List<String>> result = defaultClientResponse.toEntityList(String.class).block();
assertThat(result.getBody()).isEqualTo(Collections.singletonList("foo")); assertThat(result.getBody()).isEqualTo(Collections.singletonList("foo"));
assertThatIllegalArgumentException().isThrownBy( assertThat(result.getStatusCode()).isEqualTo(HttpStatusCode.valueOf(999));
result::getStatusCode);
assertThat(result.getStatusCodeValue()).isEqualTo(999); assertThat(result.getStatusCodeValue()).isEqualTo(999);
assertThat(result.getHeaders().getContentType()).isEqualTo(MediaType.TEXT_PLAIN); assertThat(result.getHeaders().getContentType()).isEqualTo(MediaType.TEXT_PLAIN);
} }

View File

@@ -38,6 +38,7 @@ import org.springframework.core.NamedThreadLocal;
import org.springframework.core.ParameterizedTypeReference; import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.codec.ClientCodecConfigurer; import org.springframework.http.codec.ClientCodecConfigurer;
import org.springframework.web.reactive.function.BodyExtractors; import org.springframework.web.reactive.function.BodyExtractors;
@@ -73,6 +74,7 @@ public class DefaultWebClientTests {
@BeforeEach @BeforeEach
public void setup() { public void setup() {
ClientResponse mockResponse = mock(ClientResponse.class); ClientResponse mockResponse = mock(ClientResponse.class);
when(mockResponse.statusCode()).thenReturn(HttpStatus.OK);
when(mockResponse.bodyToMono(Void.class)).thenReturn(Mono.empty()); when(mockResponse.bodyToMono(Void.class)).thenReturn(Mono.empty());
given(this.exchangeFunction.exchange(this.captor.capture())).willReturn(Mono.just(mockResponse)); given(this.exchangeFunction.exchange(this.captor.capture())).willReturn(Mono.just(mockResponse));
this.builder = WebClient.builder().baseUrl("/base").exchangeFunction(this.exchangeFunction); this.builder = WebClient.builder().baseUrl("/base").exchangeFunction(this.exchangeFunction);
@@ -414,8 +416,8 @@ public class DefaultWebClientTests {
Mono<Void> result = this.builder.build().get() Mono<Void> result = this.builder.build().get()
.uri("/path") .uri("/path")
.retrieve() .retrieve()
.onStatus(HttpStatus::is4xxClientError, resp -> Mono.error(new IllegalStateException("1"))) .onStatus(HttpStatusCode::is4xxClientError, resp -> Mono.error(new IllegalStateException("1")))
.onStatus(HttpStatus::is4xxClientError, resp -> Mono.error(new IllegalStateException("2"))) .onStatus(HttpStatusCode::is4xxClientError, resp -> Mono.error(new IllegalStateException("2")))
.bodyToMono(Void.class); .bodyToMono(Void.class);
StepVerifier.create(result).expectErrorMessage("1").verify(); StepVerifier.create(result).expectErrorMessage("1").verify();
@@ -428,8 +430,8 @@ public class DefaultWebClientTests {
ClientResponse response = ClientResponse.create(HttpStatus.BAD_REQUEST).build(); ClientResponse response = ClientResponse.create(HttpStatus.BAD_REQUEST).build();
given(exchangeFunction.exchange(any())).willReturn(Mono.just(response)); given(exchangeFunction.exchange(any())).willReturn(Mono.just(response));
Predicate<HttpStatus> predicate1 = mock(Predicate.class); Predicate<HttpStatusCode> predicate1 = mock(Predicate.class);
Predicate<HttpStatus> predicate2 = mock(Predicate.class); Predicate<HttpStatusCode> predicate2 = mock(Predicate.class);
given(predicate1.test(HttpStatus.BAD_REQUEST)).willReturn(false); given(predicate1.test(HttpStatus.BAD_REQUEST)).willReturn(false);
given(predicate2.test(HttpStatus.BAD_REQUEST)).willReturn(false); given(predicate2.test(HttpStatus.BAD_REQUEST)).willReturn(false);

Some files were not shown because too many files have changed in this diff Show More