在我使用 Kotlin 构建的 Spring 应用程序中,我想对如下所示的数据类使用 bean 验证。
data class CustomerDto(
@field: NotBlank
val firstName: String,
@field: NotBlank
val lastName: String)
在向客户端点发送带有空名字的帖子时,我想获得约束验证,但由于字段不允许空值,我没有获得验证,而是收到以下错误。
"status": 400,
"error": "Bad Request",
"message": "JSON parse error: Instantiation of [simple type, class pkg.CustomerDto] value failed for JSON property firstName due to missing (therefore NULL) value for creator parameter firstName which is a non-nullable type; nested exception is com.fasterxml.jackson.module.kotlin.MissingKotlinParameterException: Instantiation of [simple type, class pkg.CustomerDto] value failed for JSON property firstName due to missing (therefore NULL) value for creator parameter firstName which is a non-nullable type\n at [Source: (PushbackInputStream); line: 19, column: 1] (through reference chain: pkg.CustomerDto[\"firstName\"])",
"path": "/shop/5/customer"
是否有其他选项可以将 dto 字段标记为非可选,并且仍然违反约束?当我将它们标记为可选时,我必须使用 !!将代码中的不可空字段映射到我的实体时。
谢谢。
我相信你的做法是错误的。
Kotlin 的 null 安全运算符的确切目的是强制您在代码中显式表达可空性行为,以极大地减少 NPE,或者至少确保您自己故意导致它们:)。在您(或任何类似 MVC 的访问模式)情况下,您将面临以下场景
虽然它在逻辑流程方面是有意义的,但实际上是一种可能导致 NPE 的违规行为,因为模型/合约中没有任何内容保证这些字段不会为空
不过,在 java 中,你刚刚使用 getter 做出了最后的假设(无论如何你都会使用 getter,它是 java,对吧?)。
嗯 - 在 kotlin 中没有什么不同,如果这就是你的需要:
data class CustomerDto(@field:NotNull
@JsonProperty("firstName") private val _firstName: String? = null,
@field:NotNull
@JsonProperty("lastName") private val _lastName: String? = null) {
val firstName get() = _firstName!!
val lastName get() = _lastName!!
}
(此示例假设您使用
jackson
进行 JSON 解/序列化)
虽然仍然使用
!!
运算符手动强制不可空性(这是您想要避免的),但您现在正在从代码库的其余部分中抽象出该方面,获得类似 java-getter 的行为
我认为更好的解决方案是在属性中使用 Kotlin 的默认值:
data class CustomerDto(
@field: NotBlank
val firstName: String="",
@field: NotBlank
val lastName: String="")
名字和姓氏属性将始终有一个值(来自 json 或默认值 ="")。该解决方案并不完美,但它的工作原理与预期一致。
我参加这里的聚会迟到了,但我希望它可以帮助其他人。
由于 Spring 在实际尝试绑定字段之前首先尝试创建一个用
@ModelAttribute
注释的 bean 实例(请参阅ModelAttributeMethodProcessor),因此我们没有太多选择。虽然我们可以为字段使用默认值,但这不适用于复杂对象(例如 MultipartFile
)。
查看源代码,我发现 Spring 可以使用 DataBinder 设置这些值。因此,我们可以声明稍后要初始化的字段,而无需可以为空。
class MyClassDTO {
@field:NotBlank(message = "Name cannot be blank")
lateinit var name: String
@field:NotBlank(message = "Topic cannot be blank")
lateinit var topic: String
@field:NotNull(message = "File cannot be null")
lateinit var file: MultipartFile
}