hfhbd / kotlinx-uuid

kotlinx-uuid is a multiplatform (MPP) Kotlin library adding helper methods to kotlin.uuid.Uuid.
https://uuid.softwork.app/
Apache License 2.0
88 stars 3 forks source link

Make UUIDFormatException public? #242

Closed florentsorel closed 1 year ago

florentsorel commented 1 year ago

I was trying to handle a bad format uuid inside a spring boot application and something seems weird to handle this case.

I have a basic controller with a @PathVariable annotation:

@RestController
@RequestMapping("/v1/actors")
class GetActorController(
    private val getActorByUuidQuery: GetActorByUuidQuery
) {
    @GetMapping("/{uuid}")
    fun invoke(@PathVariable uuid: UUID): ResponseEntity<ActorResponse> {
        val response = getActorByUuidQuery.handle(GetActorByUuidRequest(uuid))
        return ResponseEntity(response.actor.toResponse(), HttpStatus.OK)
    }
}

When the uuid is not valid for example /v1/actors/test a MethodArgumentTypeMismatchException is thrown with this error:

Failed to convert value of type 'java.lang.String' to required type 'kotlinx.uuid.UUID'; Failed to convert from type [java.lang.String] to type [@org.springframework.web.bind.annotation.PathVariable kotlinx.uuid.UUID] for value [test]

So instead of handle MethodArgumentTypeMismatchException inside a @RestControllerAdvice I created a converter to parse the string into an uuid with a custom exception:

class UUIDConverter : Converter<String, UUID> {
    override fun convert(source: String): UUID {
        try {
            return UUID(source)
        } catch (ex: Exception) {
            throw UUIDConverterException("test")
        }
    }
}

The thing is, I catch Exception here and it's handle inside my RestControllerAdvice, if I remove the case for @ExceptionHandler(Exception::class) my custom exception is thrown and the @ExceptionHandler(UUIDConverterException::class) is called.

@ExceptionHandler(UUIDConverterException::class)
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
fun onUuidConverterException(ex: UUIDConverterException, request: WebRequest): ErrorResponse {
    return ErrorResponse(
        HttpStatus.BAD_REQUEST.value(),
        "UUID is not valid"
    )

}

@ExceptionHandler(Exception::class)
@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
fun globalExceptionHandler(ex: Exception, request: WebRequest): ErrorResponse {
    return ErrorResponse(
        HttpStatus.INTERNAL_SERVER_ERROR.value(),
        ex.message!!,
        ex.javaClass.name
    )
}

UUIDFormatException extends from Exception so onUuidConverterException method is never called.

class UUIDConverter : Converter<String, UUID> {
    override fun convert(source: String): UUID {
        try {
            return UUID(source)
        } catch (ex: UUIDFormatException) { // better than generic "Exception"?
            throw UUIDConverterException("test")
        }
    }
}

So, it would be better if we can use UUIDFormatException to handle this kind of case? Or extends it from RuntimeException instead of Exception?

hfhbd commented 1 year ago

Sorry, I didn't get a notification about this issue. I will extend UUIDFormatException from IllegalArgumentException. If you don't care about the exception message, you could just use String.toUUIDOrNull().