Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring boot @Valid on requestBody in controller method not working

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?

like image 727
Manishoaham Avatar asked May 24 '20 21:05

Manishoaham


People also ask

What happens when @valid fails?

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).

How do I use RequestBody in Spring boot?

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.

How do you validate a RequestBody?

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.

What does @valid mean in Spring boot?

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.


3 Answers

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.

like image 77
Piotr Solarski Avatar answered Sep 20 '22 23:09

Piotr Solarski


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>
like image 24
Valeriy Emelyanov Avatar answered Sep 21 '22 23:09

Valeriy Emelyanov


[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
}
like image 21
Manishoaham Avatar answered Sep 19 '22 23:09

Manishoaham