Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring not null validation throwing HttpMessageNotReadableException instead of MethodArgumentNotValidException in kotlin

I'm making and simple application in Kotlin using Spring but I'm having a problem with the validation.

I have this entity class:

@Entity
@Table(name = "category")
data class Category(
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        val id: Long?,
        @field:NotNull @field:NotEmpty val name: String)

And my controller function like this:

@PostMapping
@ResponseStatus(HttpStatus.CREATED)
fun create(@Valid @RequestBody category: Category): ResponseEntity<Category>

create have some code, but it is irrelevant for the question, my problem is with the request body validation. If I send a category with an empty name field, it is thrown a MethodArgumentNotValidException exception, but if I send null to the field name, the exception thrown HttpMessageNotReadableException instead. Does anyone knows if it is possible to make passing null to a field marked with @NotNull to also throw MethodArgumentNotValidException in Kotlin.

like image 540
Erik Avatar asked Sep 12 '25 06:09

Erik


2 Answers

So your problem is you specify the name field as not nullable, by default jackson module for kotlin will check it and throw HttpMessageNotReadableException which cause by MissingKotlinParameterException during json mapping process. If you mark name filed as nullable json mapping will passed and get to the spring validation phase with @Valid then we will get MethodArgumentNotValidException

@Entity
@Table(name = "category")
data class Category(
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    val id: Long?,
    @field:NotNull @field:NotEmpty val name: String?)
like image 65
Chi Dov Avatar answered Sep 13 '25 19:09

Chi Dov


You can handle this issue by providing HttpMessageNotReadableException handler and then checking if the underlying cause is MissingKotlinParameterException.

After that, you can provide custom validation error. I'm using zalando-problem, so syntax is a bit different from vanilla spring, but you get the idea:

    @ExceptionHandler
    override fun handleMessageNotReadableException(
        exception: HttpMessageNotReadableException,
        request: NativeWebRequest
    ): ResponseEntity<Problem> {
        // workaround
        val cause = exception.cause
        if (cause is MissingKotlinParameterException) {
            val violations = setOf(createMissingKotlinParameterViolation(cause))
            return newConstraintViolationProblem(exception, violations, request)
        }
        return create(Status.BAD_REQUEST, UnableToReadInputMessageProblem(), request)
    }

    private fun createMissingKotlinParameterViolation(cause: MissingKotlinParameterException): Violation {
        val name = cause.path.fold("") { jsonPath, ref ->
            val suffix = when {
                ref.index > -1 -> "[${ref.index}]"
                else -> ".${ref.fieldName}"
            }
            (jsonPath + suffix).removePrefix(".")
        }
        return Violation(name, "must not be null")
    }

This way you get get nice output with proper constraint error.

You may try to declare @ExceptionHandler for MissingKotlinParameterException directly (though I've tried, but it didn't some reason), but I can't guarantee it'll work.

Code samples for path parsing are taken from here

like image 37
Alexander Biryukov Avatar answered Sep 13 '25 19:09

Alexander Biryukov