Commit 8ef937357b29243ed0ee368559d8b68ad32a4646
1 parent
02ac41c1
fix: GlobalExceptionHandler propagates ResponseStatusException status codes
Showing
1 changed file
with
19 additions
and
0 deletions
platform/platform-bootstrap/src/main/kotlin/org/vibeerp/platform/bootstrap/web/GlobalExceptionHandler.kt
| ... | ... | @@ -3,8 +3,10 @@ package org.vibeerp.platform.bootstrap.web |
| 3 | 3 | import org.slf4j.LoggerFactory |
| 4 | 4 | import org.springframework.http.HttpStatus |
| 5 | 5 | import org.springframework.http.ProblemDetail |
| 6 | +import org.springframework.http.ResponseEntity | |
| 6 | 7 | import org.springframework.web.bind.annotation.ExceptionHandler |
| 7 | 8 | import org.springframework.web.bind.annotation.RestControllerAdvice |
| 9 | +import org.springframework.web.server.ResponseStatusException | |
| 8 | 10 | import org.vibeerp.platform.security.AuthenticationFailedException |
| 9 | 11 | import org.vibeerp.platform.security.authz.PermissionDeniedException |
| 10 | 12 | import java.time.Instant |
| ... | ... | @@ -87,6 +89,23 @@ class GlobalExceptionHandler { |
| 87 | 89 | problem(HttpStatus.FORBIDDEN, "permission denied: '${ex.permissionKey}'") |
| 88 | 90 | |
| 89 | 91 | /** |
| 92 | + * Spring's `ResponseStatusException` carries its own HTTP status code | |
| 93 | + * (e.g. 400, 403, 409). Handlers and filters that throw it expect the | |
| 94 | + * status to propagate verbatim. Without this handler the catch-all | |
| 95 | + * `Throwable` branch would swallow it as a generic 500. | |
| 96 | + */ | |
| 97 | + @ExceptionHandler(ResponseStatusException::class) | |
| 98 | + fun handleResponseStatus(ex: ResponseStatusException): ResponseEntity<Map<String, Any?>> { | |
| 99 | + return ResponseEntity.status(ex.getStatusCode()).body(mapOf( | |
| 100 | + "type" to "about:blank", | |
| 101 | + "title" to ex.getStatusCode().toString(), | |
| 102 | + "status" to ex.getStatusCode().value(), | |
| 103 | + "detail" to (ex.reason ?: ex.message), | |
| 104 | + "timestamp" to Instant.now().toString(), | |
| 105 | + )) | |
| 106 | + } | |
| 107 | + | |
| 108 | + /** | |
| 90 | 109 | * Last-resort fallback. Anything not handled above is logged with a |
| 91 | 110 | * full stack trace and surfaced as a generic 500 to the caller. The |
| 92 | 111 | * detail message is intentionally vague so we don't leak internals. | ... | ... |