Validation of a list of objects in Spring

后端 未结 12 1278
無奈伤痛
無奈伤痛 2020-11-28 05:30

I have the following controller method:

@RequestMapping(value=\"/map/update\", method=RequestMethod.POST, produces = \"application/json; charset=utf-8\")
@Re         


        
12条回答
  •  孤街浪徒
    2020-11-28 05:39

    (this answer is in Kotlin, for Java see https://stackoverflow.com/a/64061936)

    For those using kotlin and jackson, here is the ValidatedList class that do not require wrapping, that is, it will still be serialized/deserialized as a usual list:

    class ValidatedList {
        /**
         * By default, spring-boot cannot validate lists, as they are generic AND do not conform to the Java Bean definition.
         * This is one work-around: create a wrapper that fits the Java Bean definition, and use Jackson annotations to
         * make the wrapper disappear upon (de)serialization.
         * Do not change anything (such as making the _value field private) or it won't work anymore !
         * 
         * Usage:
         * ```
         * @PostMapping("/something")
         * fun someRestControllerMethod(@Valid @RequestBody pojoList: ValidatedList){
         *     // access list with:
         *     pojoList.values
         *}
         * ```
         */
    
        @JsonValue
        @Valid
        @NotNull
        @Size(min = 1, message = "array body must contain at least one item.")
        var _values: List? = null
    
        val values: List
            get() = _values!!
    
        @JsonCreator
        constructor(vararg list: E) {
            this._values = list.asList()
        }
    }
    

    Advantages:

    • no need for the @Validated annotation
    • will throw an error if the body is an empty array (see @Size)
    • the exception will be mapped correctly to 400 Bad Request (which is not the case when using javax and @Validated annotation)

    Example:

    data class N(
        @field:Min(value = 0, message = "id must be positive.")
        val id: Long? = null,
    
        @field:NotNull
        @field:Size(min = 2, max = 32, message = "wrong size: should be 32 chars long.")
        val token: String? = null
    )
    
    @RestController
    class XController {
        @PostMapping("/ns")
        fun getNs(@Valid @NotNull @RequestBody wrap: ListWrapper) = wrap
    }
    

    Submit ok:

     curl -H "Content-Type: application/json" -X POST http://localhost:8080/ns -d '[{"id": 11, "token": "something"}]'
    
    [{"id" : 11, "token" : "something"}]
    

    Submit empty body:

    curl -H "Content-Type: application/json" -X POST http://localhost:8080/ns -d '[]'
    
    {
       "timestamp" : "2020-09-25T08:49:30.324+00:00",
       "message" : "Validation failed for object='listWrapper'. Error count: 1",
       "error" : "Bad Request",
       "path" : "/ns",
       "status" : 400,
       "exception" : "org.springframework.web.bind.MethodArgumentNotValidException",
       "trace":"org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument [0] in public com.example.demo.test.XController$ListWrapper com.example.demo.test.XController.getNs(com.example.demo.test.XController$ListWrapper): [Field error in object 'listWrapper' on field '_values': rejected value [[]]; codes [Size.listWrapper._values,Size._values,Size.java.util.List,Size]; [...]"
    }
    

    Submit invalid items:

    curl -H "Content-Type: application/json" -X POST http://localhost:8080/ns -d '[{"id": -11, "token": ""}]'
    
    {
       "message" : "Validation failed for object='listWrapper'. Error count: 2",
       "path" : "/ns",
       "exception" : "org.springframework.web.bind.MethodArgumentNotValidException",
       "timestamp" : "2020-09-25T08:49:54.505+00:00",
       "error" : "Bad Request",
       "status" : 400,
       "trace":"org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument [0] in public com.example.demo.test.XController$ListWrapper com.example.demo.test.XController.getNs(com.example.demo.test.XController$ListWrapper) with 2 errors: [...]"
    }
    

提交回复
热议问题