kotlin 与@ExceptionHandler配对的@RestControllerAdvice未从数据类返回JSON

enyaitl3  于 2023-01-31  发布在  Kotlin
关注(0)|答案(1)|浏览(160)

我正在使用Kotlin和Sping Boot 3编写一个小应用程序。我希望有一个很好的异常处理,所以我创建了一个用@RestControllerAdvice注解的类,有几个用@ExceptionHandler注解的方法。我创建了一个data class来存储返回的主体数据:

data class ApiError(
    private val requestUri: String? = null,
    private val status: Int = 0,
    private val statusText: String? = null,
    private val createdAt: ZonedDateTime = ZonedDateTime.now(ZoneId.of("Europe/Warsaw")),
    private val errorMessage: String? = null,
)

剩下的就很简单了:

@RestControllerAdvice
class ControllerExceptionHandler {

    @ExceptionHandler(HttpRequestMethodNotSupportedException::class)
    fun methodNotSupportedException(
        exception: HttpRequestMethodNotSupportedException,
        request: HttpServletRequest,
    ): ResponseEntity<ApiError> {
        println(buildApiError(request, HttpStatus.METHOD_NOT_ALLOWED, exception))
        return ResponseEntity(
            buildApiError(request, HttpStatus.METHOD_NOT_ALLOWED, exception),
            HttpStatus.METHOD_NOT_ALLOWED,
        )
    }

    @ExceptionHandler(NotFoundException::class)
    fun notFoundExceptionHandler(
        exception: NotFoundException,
        request: HttpServletRequest,
    ): ResponseEntity<ApiError> {
        println(buildApiError(request, HttpStatus.NOT_FOUND, exception))
        return ResponseEntity(
            buildApiError(request, HttpStatus.NOT_FOUND, exception),
            HttpStatus.NOT_FOUND,
        )
    }

    private fun buildApiError(
        request: HttpServletRequest,
        httpStatus: HttpStatus,
        throwable: Throwable,
    ): ApiError {
        return ApiError(
            requestUri = request.requestURI,
            status = httpStatus.value(),
            statusText = httpStatus.reasonPhrase,
            errorMessage = throwable.message,
        )
    }
}

而且还有这个(不要担心这个代码的质量,它只是为了测试的目的。

@RestController
@RequestMapping(
    path = ["/hello"],
)
class HelloController {

    @GetMapping("/{name}", produces = [MediaType.APPLICATION_JSON_VALUE])
    private fun hello(@PathVariable name: String): ResponseEntity<Map<String, String>> {

        // this is a forced exception so the @ExceptionHandlers could handle them.
        if (name.lowercase() == "stefan") throw NotFoundException("Name not found!")
        return ResponseEntity.ok(mapOf("Hello" to "$name!"))
    }
}

问题是,当我运行应用程序并向'http://localhost:8080/hello/myrealname发送一个GET请求时,我只收到一个很小的对象:

{
    "Hello": "myrealname"
}

但是,当我POST到这个端点或使用名称“stefan”进行GET以触发异常时,我收到了一个正确的状态代码500或404,但是响应的主体是空的!
后来我试着返回一个字符串或者一个Map来代替我的ApiError类,一切都很好,主体在那里,要么是Map要么是字符串。但是当我想返回ApiError的一个示例时,主体是空的。裸'{}'。我的对象有什么问题吗?这不是我第一次在控制器通知类中处理异常,我从来没有遇到过这样的情况。
这个问题的可能原因是什么?有没有更好的,更像Kotlin的方法来解决这个问题?有没有我不知道的扩展方法?
真诚的感谢你的任何线索:)

gdx19jrr

gdx19jrr1#

由于您将ApiError数据类中的所有属性都定义为private,因此这些属性对于包含在spring-web中的JacksonObjectMapper序列化程序不可见。
因此,要解决您的问题,您只需 * 删除privatemodifier*,如下所示:

data class ApiError(
    val requestUri: String? = null,
    val status: Int = 0,
    val statusText: String? = null,
    val createdAt: ZonedDateTime = ZonedDateTime.now(ZoneId.of("Europe/Warsaw")),
    val errorMessage: String? = null,
)

相关问题