我有一个班级:
class User(
var name: String
)
一个映射的帖子请求:
@PostMapping("/user")
fun test(@Valid @RequestBody user: User) {
//...
}
如果客户端使用name: null
发送用户的JSON,该怎么办?是否会被MVC Validator拒绝或抛出异常?我应该使用name
注释@NotNull
吗?不幸的是,我无法检查,因为只能编写测试(无法创建User(null)
)。
答案 0 :(得分:5)
由于name
是User
的非空参数,因此无法接受null
s。
保证Kotlin编译器:
在null
构造函数中插入User
检查,如果某些Java代码试图传递null
,则会抛出异常。
使用name
注释@NotNull
以便与Java API保持一致
不添加任何 @NotNull
注释,因为没有人都同意:(
以下是相应的docs
我已经重新检查了它,Kotlin编译器v1.0.6 从@Nullable
插入@NotNull
和org.jetbrains.annotations
。我已相应更新了答案。
答案 1 :(得分:5)
你可以避免使用@NotNull
,因为它永远不会被非可空属性触发(bean验证只有在杰克逊反序列化JSON之后才会启动 - 这就是失败的地方)。
假设您正在使用jackson-module-kotlin,那么您应该以MissingKotlinParameterException
作为根本原因获得例外,然后您可以在@ControllerAdvice
中处理该例外。在您的建议中,您可以处理正常的bean验证异常(例如ConstraintViolationException
引起的@Size
)和缺少非空构造函数参数(MissingKotlinParameterException
)并返回指示错误字段的API响应。
唯一需要注意的是jackson-kotlin-module
fails on the first missing property与Java中的bean验证不同,它将返回所有违规行为。
答案 2 :(得分:0)
在我测试时,@NotNull
根本不影响MVC验证。您只会在控制台中收到WARN
消息,这是正常的:
无法读取HTTP消息:org.springframework.http.converter.HttpMessageNotReadableException:无法读取文档:实例化...
答案 3 :(得分:0)
我现在的工作环境(将文件放置在任何地方):
@Order(Ordered.HIGHEST_PRECEDENCE)
@ControllerAdvice
class ExceptionHandler {
@ResponseStatus(BAD_REQUEST)
@ResponseBody
@ExceptionHandler(MissingKotlinParameterException::class)
fun missingKotlinParameterException(ex: MissingKotlinParameterException): Error? {
return createMissingKotlinParameterViolation(ex)
}
private fun createMissingKotlinParameterViolation(ex: MissingKotlinParameterException): Error{
val error = Error(BAD_REQUEST.value(), "validation error")
val errorFieldRegex = Regex("\\.([^.]*)\\[\\\"(.*)\"\\]\$")
val errorMatch = errorFieldRegex.find(ex.path[0].description)!!
val (objectName, field) = errorMatch.destructured
error.addFieldError(objectName.decapitalize(), field, "must not be null")
return error
}
data class Error(val status: Int, val message: String, val fieldErrors: MutableList<CustomFieldError> = mutableListOf()) {
fun addFieldError(objectName: String, field: String, message: String) {
val error = CustomFieldError(objectName, field, message)
fieldErrors.add(error)
}
}
data class CustomFieldError(val objectName: String, val field: String, val message: String)