Skip to content

Commit

Permalink
Update table of supported controller method return types
Browse files Browse the repository at this point in the history
Closes gh-28814
  • Loading branch information
rstoyanchev committed Oct 11, 2022
1 parent 04f0f1d commit cf2b102
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ public ErrorResponseException(HttpStatusCode status, ProblemDetail body, @Nullab
* resolve the detail message with.
* @since 6.0
*/
protected ErrorResponseException(
public ErrorResponseException(
HttpStatusCode status, ProblemDetail body, @Nullable Throwable cause,
@Nullable String messageDetailCode, @Nullable Object[] messageDetailArguments) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,8 @@ protected ResponseEntity<Object> handleErrorResponseException(
/**
* Customize the handling of {@link ConversionNotSupportedException}.
* <p>By default this method creates a {@link ProblemDetail} with the status
* and a short detail message, and then delegates to
* and a short detail message, and also looks up an override for the detail
* via {@link MessageSource}, before delegating to
* {@link #handleExceptionInternal}.
* @param ex the exception to handle
* @param headers the headers to use for the response
Expand All @@ -393,16 +394,19 @@ protected ResponseEntity<Object> handleErrorResponseException(
protected ResponseEntity<Object> handleConversionNotSupported(
ConversionNotSupportedException ex, HttpHeaders headers, HttpStatusCode status, WebRequest request) {

ProblemDetail body = ProblemDetail.forStatusAndDetail(status,
"Failed to convert '" + ex.getPropertyName() + "' with value: '" + ex.getValue() + "'");
Object[] args = {ex.getPropertyName(), ex.getValue()};

ProblemDetail body = resolveDetailViaMessageSource(
status, args, "Failed to convert '" + args[0] + "' with value: '" + args[1] + "'");

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

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

ProblemDetail body = ProblemDetail.forStatusAndDetail(status,
"Unexpected type for '" + ex.getPropertyName() + "' with value: '" + ex.getValue() + "'");
Object[] args = {ex.getPropertyName(), ex.getValue()};

ProblemDetail body = resolveDetailViaMessageSource(
status, args, "Failed to convert '" + args[0] + "' with value: '" + args[1] + "'");

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

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

ProblemDetail body = ProblemDetail.forStatusAndDetail(status, "Failed to read request body");
ProblemDetail body = resolveDetailViaMessageSource(status, null, "Failed to read request");
return handleExceptionInternal(ex, body, headers, status, request);
}

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

ProblemDetail body = ProblemDetail.forStatusAndDetail(status, "Failed to write response body");
ProblemDetail body = resolveDetailViaMessageSource(status, null, "Failed to write request");
return handleExceptionInternal(ex, body, headers, status, request);
}

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

// For non-Web exceptions
private ProblemDetail resolveDetailViaMessageSource(
HttpStatusCode status, @Nullable Object[] arguments, String defaultDetail) {

ProblemDetail body = ProblemDetail.forStatusAndDetail(status, defaultDetail);
ErrorResponseException errorResponseEx = new ErrorResponseException(status, body, null, null, arguments);
body = resolveDetailViaMessageSource(errorResponseEx);
return body;
}

// For ErrorResponse exceptions
private ProblemDetail resolveDetailViaMessageSource(ErrorResponse response) {
ProblemDetail body = response.getBody();
if (this.messageSource != null) {
Expand Down
19 changes: 19 additions & 0 deletions src/docs/asciidoc/web/webmvc.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -4960,6 +4960,9 @@ The actual message code value is parameterized with placeholders, e.g.
`"HTTP method {0} not supported"` to be expanded from the arguments.
- `ResponseEntityExceptionHandler` uses the message code and the message arguments
to resolve the problem "detail" field.
- Lower level exceptions that cannot implement `ErrorResponse`, e.g. `TypeMismatchException`,
have their problem detail, including message code and arguments set in
`ResponseEntityExceptionHandler`.

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

| `ConversionNotSupportedException`
| (default)
| `{0}` property name, `{1}` property value

| `HttpMediaTypeNotAcceptableException`
| (default)
| `{0}` list of supported media types
Expand All @@ -4991,6 +4998,14 @@ MVC exceptions:
| (default) + ".parseError"
|

| `HttpMessageNotReadableException`
| (default)
|

| `HttpMessageNotWritableException`
| (default)
|

| `HttpRequestMethodNotSupportedException`
| (default)
| `{0}` the current HTTP method, `{1}` the list of supported HTTP methods
Expand Down Expand Up @@ -5029,6 +5044,10 @@ MVC exceptions:
| (default)
|

| `TypeMismatchException`
| (default)
| `{0}` property name, `{1}` property value

| `UnsatisfiedServletRequestParameterException`
| (default)
| `{0}` the list of parameter conditions
Expand Down

0 comments on commit cf2b102

Please sign in to comment.