Browse Source

DefaultResponseErrorHandler detects non-standard error code as well

Issue: SPR-17439
pull/2025/head
Juergen Hoeller 6 years ago
parent
commit
738097def2
  1. 42
      spring-web/src/main/java/org/springframework/http/HttpStatus.java
  2. 22
      spring-web/src/main/java/org/springframework/web/client/DefaultResponseErrorHandler.java
  3. 17
      spring-web/src/test/java/org/springframework/web/client/DefaultResponseErrorHandlerHttpStatusTests.java
  4. 60
      spring-web/src/test/java/org/springframework/web/client/DefaultResponseErrorHandlerTests.java

42
spring-web/src/main/java/org/springframework/http/HttpStatus.java

@ -522,7 +522,6 @@ public enum HttpStatus {
return status; return status;
} }
/** /**
* Resolve the given status code to an {@code HttpStatus}, if possible. * Resolve the given status code to an {@code HttpStatus}, if possible.
* @param statusCode the HTTP status code (potentially non-standard) * @param statusCode the HTTP status code (potentially non-standard)
@ -565,18 +564,45 @@ public enum HttpStatus {
return this.value; return this.value;
} }
public static Series valueOf(int status) { /**
int seriesCode = status / 100; * Return the enum constant of this type with the corresponding series.
* @param status a standard HTTP status enum value
* @return the enum constant of this type with the corresponding series
* @throws IllegalArgumentException if this enum has no corresponding constant
*/
public static Series valueOf(HttpStatus status) {
return valueOf(status.value);
}
/**
* Return the enum constant of this type with the corresponding series.
* @param statusCode the HTTP status code (potentially non-standard)
* @return the enum constant of this type with the corresponding series
* @throws IllegalArgumentException if this enum has no corresponding constant
*/
public static Series valueOf(int statusCode) {
Series series = resolve(statusCode);
if (series == null) {
throw new IllegalArgumentException("No matching constant for [" + statusCode + "]");
}
return series;
}
/**
* Resolve the given status code to an {@code HttpStatus.Series}, if possible.
* @param statusCode the HTTP status code (potentially non-standard)
* @return the corresponding {@code Series}, or {@code null} if not found
* @since 5.1.3
*/
@Nullable
public static Series resolve(int statusCode) {
int seriesCode = statusCode / 100;
for (Series series : values()) { for (Series series : values()) {
if (series.value == seriesCode) { if (series.value == seriesCode) {
return series; return series;
} }
} }
throw new IllegalArgumentException("No matching constant for [" + status + "]"); return null;
}
public static Series valueOf(HttpStatus status) {
return valueOf(status.value);
} }
} }

22
spring-web/src/main/java/org/springframework/web/client/DefaultResponseErrorHandler.java

@ -48,8 +48,9 @@ public class DefaultResponseErrorHandler implements ResponseErrorHandler {
*/ */
@Override @Override
public boolean hasError(ClientHttpResponse response) throws IOException { public boolean hasError(ClientHttpResponse response) throws IOException {
HttpStatus statusCode = HttpStatus.resolve(response.getRawStatusCode()); int rawStatusCode = response.getRawStatusCode();
return (statusCode != null && hasError(statusCode)); HttpStatus statusCode = HttpStatus.resolve(rawStatusCode);
return (statusCode != null ? hasError(statusCode) : hasError(rawStatusCode));
} }
/** /**
@ -58,7 +59,7 @@ public class DefaultResponseErrorHandler implements ResponseErrorHandler {
* {@code HttpStatus.Series#CLIENT_ERROR CLIENT_ERROR} or * {@code HttpStatus.Series#CLIENT_ERROR CLIENT_ERROR} or
* {@code HttpStatus.Series#SERVER_ERROR SERVER_ERROR}. * {@code HttpStatus.Series#SERVER_ERROR SERVER_ERROR}.
* Can be overridden in subclasses. * Can be overridden in subclasses.
* @param statusCode the HTTP status code * @param statusCode the HTTP status code as enum value
* @return {@code true} if the response has an error; {@code false} otherwise * @return {@code true} if the response has an error; {@code false} otherwise
*/ */
protected boolean hasError(HttpStatus statusCode) { protected boolean hasError(HttpStatus statusCode) {
@ -66,6 +67,21 @@ public class DefaultResponseErrorHandler implements ResponseErrorHandler {
statusCode.series() == HttpStatus.Series.SERVER_ERROR); statusCode.series() == HttpStatus.Series.SERVER_ERROR);
} }
/**
* Template method called from {@link #hasError(ClientHttpResponse)}.
* <p>The default implementation checks if the given status code is
* {@code HttpStatus.Series#CLIENT_ERROR CLIENT_ERROR} or
* {@code HttpStatus.Series#SERVER_ERROR SERVER_ERROR}.
* Can be overridden in subclasses.
* @param unknownStatusCode the HTTP status code as raw value
* @return {@code true} if the response has an error; {@code false} otherwise
* @since 4.3.21
*/
protected boolean hasError(int unknownStatusCode) {
HttpStatus.Series series = HttpStatus.Series.resolve(unknownStatusCode);
return (series == HttpStatus.Series.CLIENT_ERROR || series == HttpStatus.Series.SERVER_ERROR);
}
/** /**
* Delegates to {@link #handleError(ClientHttpResponse, HttpStatus)} with the response status code. * Delegates to {@link #handleError(ClientHttpResponse, HttpStatus)} with the response status code.
*/ */

17
spring-web/src/test/java/org/springframework/web/client/DefaultResponseErrorHandlerHttpStatusTests.java

@ -28,7 +28,6 @@ import org.springframework.http.client.ClientHttpResponse;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import static org.mockito.BDDMockito.*; import static org.mockito.BDDMockito.*;
import static org.mockito.Mockito.mock;
import static org.springframework.http.HttpStatus.*; import static org.springframework.http.HttpStatus.*;
/** /**
@ -66,7 +65,7 @@ public class DefaultResponseErrorHandlerHttpStatusTests {
public HttpStatus httpStatus; public HttpStatus httpStatus;
@Parameterized.Parameter(1) @Parameterized.Parameter(1)
public Class expectedExceptionClass; public Class<? extends Throwable> expectedExceptionClass;
private final DefaultResponseErrorHandler handler = new DefaultResponseErrorHandler(); private final DefaultResponseErrorHandler handler = new DefaultResponseErrorHandler();
@ -74,7 +73,13 @@ public class DefaultResponseErrorHandlerHttpStatusTests {
@Test @Test
public void handleErrorIOException() throws Exception { public void hasErrorTrue() throws Exception {
given(this.response.getRawStatusCode()).willReturn(this.httpStatus.value());
assertTrue(this.handler.hasError(this.response));
}
@Test
public void handleErrorException() throws Exception {
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.TEXT_PLAIN); headers.setContentType(MediaType.TEXT_PLAIN);
@ -91,10 +96,4 @@ public class DefaultResponseErrorHandlerHttpStatusTests {
} }
} }
@Test
public void hasErrorTrue() throws Exception {
given(this.response.getRawStatusCode()).willReturn(HttpStatus.NOT_FOUND.value());
assertTrue(handler.hasError(this.response));
}
} }

60
spring-web/src/test/java/org/springframework/web/client/DefaultResponseErrorHandlerTests.java

@ -65,7 +65,7 @@ public class DefaultResponseErrorHandlerTests {
given(response.getRawStatusCode()).willReturn(HttpStatus.NOT_FOUND.value()); given(response.getRawStatusCode()).willReturn(HttpStatus.NOT_FOUND.value());
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("UTF-8"))); given(response.getBody()).willReturn(new ByteArrayInputStream("Hello World".getBytes(StandardCharsets.UTF_8)));
try { try {
handler.handleError(response); handler.handleError(response);
@ -101,8 +101,20 @@ public class DefaultResponseErrorHandlerTests {
handler.handleError(response); handler.handleError(response);
} }
@Test // SPR-16108
public void hasErrorForUnknownStatusCode() throws Exception {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.TEXT_PLAIN);
given(response.getRawStatusCode()).willReturn(999);
given(response.getStatusText()).willReturn("Custom status code");
given(response.getHeaders()).willReturn(headers);
assertFalse(handler.hasError(response));
}
@Test(expected = UnknownHttpStatusCodeException.class) // SPR-9406 @Test(expected = UnknownHttpStatusCodeException.class) // SPR-9406
public void unknownStatusCode() throws Exception { public void handleErrorUnknownStatusCode() throws Exception {
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.TEXT_PLAIN); headers.setContentType(MediaType.TEXT_PLAIN);
@ -113,16 +125,52 @@ public class DefaultResponseErrorHandlerTests {
handler.handleError(response); handler.handleError(response);
} }
@Test // SPR-16108 @Test // SPR-17461
public void hasErrorForUnknownStatusCode() throws Exception { public void hasErrorForCustomClientError() throws Exception {
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.getRawStatusCode()).willReturn(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);
assertFalse(handler.hasError(response)); assertTrue(handler.hasError(response));
}
@Test(expected = UnknownHttpStatusCodeException.class)
public void handleErrorForCustomClientError() throws Exception {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.TEXT_PLAIN);
given(response.getRawStatusCode()).willReturn(499);
given(response.getStatusText()).willReturn("Custom status code");
given(response.getHeaders()).willReturn(headers);
handler.handleError(response);
}
@Test // SPR-17461
public void hasErrorForCustomServerError() throws Exception {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.TEXT_PLAIN);
given(response.getRawStatusCode()).willReturn(599);
given(response.getStatusText()).willReturn("Custom status code");
given(response.getHeaders()).willReturn(headers);
assertTrue(handler.hasError(response));
}
@Test(expected = UnknownHttpStatusCodeException.class)
public void handleErrorForCustomServerError() throws Exception {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.TEXT_PLAIN);
given(response.getRawStatusCode()).willReturn(599);
given(response.getStatusText()).willReturn("Custom status code");
given(response.getHeaders()).willReturn(headers);
handler.handleError(response);
} }
@Test // SPR-16604 @Test // SPR-16604

Loading…
Cancel
Save