Skip to content

Commit cf2b102

Browse files
committed
Update table of supported controller method return types
Closes gh-28814
1 parent 04f0f1d commit cf2b102

File tree

3 files changed

+49
-11
lines changed

3 files changed

+49
-11
lines changed

spring-web/src/main/java/org/springframework/web/ErrorResponseException.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ public ErrorResponseException(HttpStatusCode status, ProblemDetail body, @Nullab
8080
* resolve the detail message with.
8181
* @since 6.0
8282
*/
83-
protected ErrorResponseException(
83+
public ErrorResponseException(
8484
HttpStatusCode status, ProblemDetail body, @Nullable Throwable cause,
8585
@Nullable String messageDetailCode, @Nullable Object[] messageDetailArguments) {
8686

spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ResponseEntityExceptionHandler.java

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,8 @@ protected ResponseEntity<Object> handleErrorResponseException(
380380
/**
381381
* Customize the handling of {@link ConversionNotSupportedException}.
382382
* <p>By default this method creates a {@link ProblemDetail} with the status
383-
* and a short detail message, and then delegates to
383+
* and a short detail message, and also looks up an override for the detail
384+
* via {@link MessageSource}, before delegating to
384385
* {@link #handleExceptionInternal}.
385386
* @param ex the exception to handle
386387
* @param headers the headers to use for the response
@@ -393,16 +394,19 @@ protected ResponseEntity<Object> handleErrorResponseException(
393394
protected ResponseEntity<Object> handleConversionNotSupported(
394395
ConversionNotSupportedException ex, HttpHeaders headers, HttpStatusCode status, WebRequest request) {
395396

396-
ProblemDetail body = ProblemDetail.forStatusAndDetail(status,
397-
"Failed to convert '" + ex.getPropertyName() + "' with value: '" + ex.getValue() + "'");
397+
Object[] args = {ex.getPropertyName(), ex.getValue()};
398+
399+
ProblemDetail body = resolveDetailViaMessageSource(
400+
status, args, "Failed to convert '" + args[0] + "' with value: '" + args[1] + "'");
398401

399402
return handleExceptionInternal(ex, body, headers, status, request);
400403
}
401404

402405
/**
403406
* Customize the handling of {@link TypeMismatchException}.
404407
* <p>By default this method creates a {@link ProblemDetail} with the status
405-
* and a short detail message, and then delegates to
408+
* and a short detail message, and also looks up an override for the detail
409+
* via {@link MessageSource}, before delegating to
406410
* {@link #handleExceptionInternal}.
407411
* @param ex the exception to handle
408412
* @param headers the headers to use for the response
@@ -415,16 +419,19 @@ protected ResponseEntity<Object> handleConversionNotSupported(
415419
protected ResponseEntity<Object> handleTypeMismatch(
416420
TypeMismatchException ex, HttpHeaders headers, HttpStatusCode status, WebRequest request) {
417421

418-
ProblemDetail body = ProblemDetail.forStatusAndDetail(status,
419-
"Unexpected type for '" + ex.getPropertyName() + "' with value: '" + ex.getValue() + "'");
422+
Object[] args = {ex.getPropertyName(), ex.getValue()};
423+
424+
ProblemDetail body = resolveDetailViaMessageSource(
425+
status, args, "Failed to convert '" + args[0] + "' with value: '" + args[1] + "'");
420426

421427
return handleExceptionInternal(ex, body, headers, status, request);
422428
}
423429

424430
/**
425431
* Customize the handling of {@link HttpMessageNotReadableException}.
426432
* <p>By default this method creates a {@link ProblemDetail} with the status
427-
* and a short detail message, and then delegates to
433+
* and a short detail message, and also looks up an override for the detail
434+
* via {@link MessageSource}, before delegating to
428435
* {@link #handleExceptionInternal}.
429436
* @param ex the exception to handle
430437
* @param headers the headers to use for the response
@@ -437,14 +444,15 @@ protected ResponseEntity<Object> handleTypeMismatch(
437444
protected ResponseEntity<Object> handleHttpMessageNotReadable(
438445
HttpMessageNotReadableException ex, HttpHeaders headers, HttpStatusCode status, WebRequest request) {
439446

440-
ProblemDetail body = ProblemDetail.forStatusAndDetail(status, "Failed to read request body");
447+
ProblemDetail body = resolveDetailViaMessageSource(status, null, "Failed to read request");
441448
return handleExceptionInternal(ex, body, headers, status, request);
442449
}
443450

444451
/**
445452
* Customize the handling of {@link HttpMessageNotWritableException}.
446453
* <p>By default this method creates a {@link ProblemDetail} with the status
447-
* and a short detail message, and then delegates to
454+
* and a short detail message, and also looks up an override for the detail
455+
* via {@link MessageSource}, before delegating to
448456
* {@link #handleExceptionInternal}.
449457
* @param ex the exception to handle
450458
* @param headers the headers to use for the response
@@ -457,7 +465,7 @@ protected ResponseEntity<Object> handleHttpMessageNotReadable(
457465
protected ResponseEntity<Object> handleHttpMessageNotWritable(
458466
HttpMessageNotWritableException ex, HttpHeaders headers, HttpStatusCode status, WebRequest request) {
459467

460-
ProblemDetail body = ProblemDetail.forStatusAndDetail(status, "Failed to write response body");
468+
ProblemDetail body = resolveDetailViaMessageSource(status, null, "Failed to write request");
461469
return handleExceptionInternal(ex, body, headers, status, request);
462470
}
463471

@@ -528,6 +536,17 @@ protected ResponseEntity<Object> handleExceptionInternal(
528536
return createResponseEntity(body, headers, statusCode, request);
529537
}
530538

539+
// For non-Web exceptions
540+
private ProblemDetail resolveDetailViaMessageSource(
541+
HttpStatusCode status, @Nullable Object[] arguments, String defaultDetail) {
542+
543+
ProblemDetail body = ProblemDetail.forStatusAndDetail(status, defaultDetail);
544+
ErrorResponseException errorResponseEx = new ErrorResponseException(status, body, null, null, arguments);
545+
body = resolveDetailViaMessageSource(errorResponseEx);
546+
return body;
547+
}
548+
549+
// For ErrorResponse exceptions
531550
private ProblemDetail resolveDetailViaMessageSource(ErrorResponse response) {
532551
ProblemDetail body = response.getBody();
533552
if (this.messageSource != null) {

src/docs/asciidoc/web/webmvc.adoc

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4960,6 +4960,9 @@ The actual message code value is parameterized with placeholders, e.g.
49604960
`"HTTP method {0} not supported"` to be expanded from the arguments.
49614961
- `ResponseEntityExceptionHandler` uses the message code and the message arguments
49624962
to resolve the problem "detail" field.
4963+
- Lower level exceptions that cannot implement `ErrorResponse`, e.g. `TypeMismatchException`,
4964+
have their problem detail, including message code and arguments set in
4965+
`ResponseEntityExceptionHandler`.
49634966

49644967
Message codes default to "problemDetail." + the fully qualified exception class name. Some
49654968
exceptions may expose additional message codes in which case a suffix is added to
@@ -4975,6 +4978,10 @@ MVC exceptions:
49754978
| (default)
49764979
|
49774980

4981+
| `ConversionNotSupportedException`
4982+
| (default)
4983+
| `{0}` property name, `{1}` property value
4984+
49784985
| `HttpMediaTypeNotAcceptableException`
49794986
| (default)
49804987
| `{0}` list of supported media types
@@ -4991,6 +4998,14 @@ MVC exceptions:
49914998
| (default) + ".parseError"
49924999
|
49935000

5001+
| `HttpMessageNotReadableException`
5002+
| (default)
5003+
|
5004+
5005+
| `HttpMessageNotWritableException`
5006+
| (default)
5007+
|
5008+
49945009
| `HttpRequestMethodNotSupportedException`
49955010
| (default)
49965011
| `{0}` the current HTTP method, `{1}` the list of supported HTTP methods
@@ -5029,6 +5044,10 @@ MVC exceptions:
50295044
| (default)
50305045
|
50315046

5047+
| `TypeMismatchException`
5048+
| (default)
5049+
| `{0}` property name, `{1}` property value
5050+
50325051
| `UnsatisfiedServletRequestParameterException`
50335052
| (default)
50345053
| `{0}` the list of parameter conditions

0 commit comments

Comments
 (0)