I am trying to validate a simple request body annotated by @Valid annotation in a @RestController annotated by @Validated. Validations are working correctly on primitive variable in request (on age in below example) but not working on pojo request body. @Valid annotation has no effect on request body Person class (i.e. controller accepting blank name and age under 18).
Person class:
import javax.validation.constraints.Min
import javax.validation.constraints.NotBlank
class Person (
@NotBlank
val name : String,
@Min(18)
val age : Int
)
Controller class:
import org.springframework.validation.annotation.Validated
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RestController
import javax.validation.Valid
@RestController
@Validated
class HomeController {
@GetMapping("/{age}")
fun verifyAge(@PathVariable("age") @Min(18) age:Int): String {
return "Eligible age."
}
@PostMapping
fun personValidation(@Valid @RequestBody person : Person) : String {
return "No validation error"
}
}
@NotBlank, @Min and @Valid annotations came from below dependency:
implementation("org.springframework.boot:spring-boot-starter-validation:2.3.0.RELEASE")
How to make @Valid working on Person request body in a @Validated controller?
If the Input class contains a field with another complex type that should be validated, this field, too, needs to be annotated with @Valid . If the validation fails, it will trigger a MethodArgumentNotValidException . By default, Spring will translate this exception to a HTTP status 400 (Bad Request).
Simply put, the @RequestBody annotation maps the HttpRequest body to a transfer or domain object, enabling automatic deserialization of the inbound HttpRequest body onto a Java object. Spring automatically deserializes the JSON into a Java type, assuming an appropriate one is specified.
Spring offers an elegant way to validate the user input. The @RequestBody annotation is used to bind the HTTP request body with a domain object in the method parameter and also this annotation internally uses the HTTP Message converter to convert the body of the HTTP request to a domain object.
The @Valid annotation will tell spring to go and validate the data passed into the controller by checking to see that the integer numberBetweenOneAndTen is between 1 and 10 inclusive because of those min and max annotations.
Don't mark Person as a Spring @Component.
Correct way to achieve field validation is to add @field to your properties. Example code:
class SomeRequest(
@field:NotBlank val name: String
)
This happens because Spring Boot needs this annotations to be applied on fields. Kotlin by default applied them to constructor parameter. See Annotation use-site targets on Kotlin documentation.
In my case in order for @Valid @RequestBody to work in the springboot application it was necessary to use both dependencies
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
[Edited] This also worked for me (adding field annotation on constructor arguments) as answered by one of the user:
import javax.validation.constraints.Min
import javax.validation.constraints.NotBlank
class Person (
@field:NotBlank
val name : String,
@field:Min(18)
val age : Int
)
Though changing the "kotlin" class definition of Person as below (constructor arguments to no-arguments) (note parentheses (...) to curly-brackets{...}) also worked without putting @field annotaion:
import javax.validation.constraints.Min
import javax.validation.constraints.NotBlank
class Person {
@NotBlank
lateinit var name: String
@Min(18)
var age: Int = 0
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With