Kotlin & Spring boot uses @Valid to check invalid solutions

Keywords: Attribute Java curl

kotlin data (corresponding to java entity class)

@Entity
@Table(name = "user")
data class User(
        @NotNull(message = "User name cannot be empty")
        @Column(name = "user_name", nullable = false)
        var userName: String = "",

        @NotNull(message = "user ID Can not be empty")
        @Column(name = "user_id", unique = true)
        var userId: String = "",

        @Email(message = "Invalid mailbox")
        var email: String = "",

        @Column(nullable = false)
        var password: String = ""

) : Serializable 

Look at controller again

@RestController
@RequestMapping("/user")
class UserController {

    @Autowired lateinit var userRepository: UserRepository

    @PutMapping(value = "/put",
     consumes = arrayOf(MediaType.APPLICATION_JSON_UTF8_VALUE))
    @ResponseBody
    fun put(@Valid @RequestBody user: SysUser):
    ResponseEntity<SysUser>? {
        if (result.hasErrors()) {
            val fieldErrors = result.fieldErrors
            for (fieldError in fieldErrors) {
                println("${fieldError.defaultMessage}")
            }
            return fieldErrors
        }
        println(user)
        return ResponseEntity
                .ok()
                .cacheControl(CacheControl.maxAge(30, TimeUnit.DAYS))
                .eTag("AC") 
                .body(user)
    }
}

Invoke put method, @Valid check is invalid

Reason analysis:

In java, validation is annotated on entity class attributes or get/set methods, but in kotlin, attributes are written directly in constructors, and validation annotations do not work on attributes.

Solution:

Using the @field: identifier, the field identifier is only allowed in the accessor function of the property. It can validate annotation functions and attributes.

Modify the kotlin data class slightly:

@Entity
@Table(name = "user")
data class User(
        @field:NotNull(message = "User name cannot be empty")
        @Column(name = "user_name", nullable = false)
        var userName: String = "",

        @field:NotNull(message = "user ID Can not be empty")
        @Column(name = "user_id", unique = true)
        var userId: String = "",

        @field:NotBlank(message = "Mailbox cannot be empty")
        @field:Email(message = "Invalid mailbox")
        var email: String = "",

        @field:NotBlank(message = "Password cannot be empty")
        @Column(nullable = false)
        var password: String = ""

) : Serializable 

After that, @Valid check will work properly.

Re execution

curl -v http://localhost:8080/user/put

See the error message

{
  "timestamp": "2017-03-04 13:54:19",
  "status": 400,
  "error": "Bad Request",
  "exception": "org.springframework.web.bind.MethodArgumentNotValidException",
  "errors": [
    {
      "field": "userId",
      "rejectedValue": null,
      "bindingFailure": false,
      "objectName": "sysUser",
      "codes": [
        "NotNull.sysUser.userId",
        "NotNull.userId",
        "NotNull.java.lang.String",
        "NotNull"
      ],
      "arguments": [
        {
          "codes": [
            "sysUser.userId",
            "userId"
          ],
          "arguments": null,
          "defaultMessage": "userId"
        }
      ],
      "defaultMessage": "user ID Can not be empty"
    }
  ],
  "message": "Validation failed for object='sysUser'. Error count: 1",
  "path": "/user/put"
}

Posted by Sephiriz on Mon, 11 Feb 2019 05:21:18 -0800