首先,我想不出这个问题的更好的标题,因此我愿意接受更改。
我正在尝试通过带有Spring Boot的bean验证机制(JSR-380)来验证bean。
所以我有一个像这样的控制器:
@Controller
@RequestMapping("/users")
class UserController {
@PostMapping
fun createUser(@Validated user: User, bindingResult: BindingResult): ModelAndView {
return ModelAndView("someview", "user", user)
}
}
这是用kotlin编写的User类:
data class User(
@field:NotEmpty
var roles: MutableSet<@NotNull Role> = HashSet()
)
这是测试:
@Test
internal fun shouldNotCreateNewTestWithInvalidParams() {
mockMvc.perform(post("/users")
.param("roles", "invalid role"))
.andExpect(model().attributeHasFieldErrors("user", "roles[]"))
}
无效的角色映射为null。
如您所见,我希望roles
包含至少一个项目,且所有项目都不为空。
但是,在测试以上代码时,如果roles
包含空值,则不会报告绑定错误。如果集合为空,则报告错误。
我以为这可能是kotlin代码如何编译的问题,因为当用Java编写User类时,相同的代码可以正常工作。像这样:
@Data // just lombok...
public class User {
@NotEmpty
private Set<@NotNull Role> roles = new HashSet<>();
}
相同的控制器,相同的测试。
检查完字节码后,我注意到kotlin版本不包含嵌套的@NotNull
注释(请参见下文)。
Java:
private Ljava/util/Set; roles
@Ljavax/validation/constraints/NotEmpty;()
@Ljavax/validation/constraints/NotNull;() : FIELD, 0;
@Ljavax/validation/constraints/NotEmpty;() : FIELD, null
科特琳:
private Ljava/util/Set; roles
@Ljavax/validation/constraints/NotEmpty;()
@Lorg/jetbrains/annotations/NotNull;() // added because roles is not nullable in kotlin
现在的问题是为什么?
这里是sample project,以防您想尝试一些东西。
答案 0 :(得分:2)
尝试像这样添加?
:
data class User(
@field:Valid
@field:NotEmpty
var roles: MutableSet<@NotNull Role?> = HashSet()
)
然后kotlin编译器应该意识到角色可能是null
,并且它可能会兑现验证,我对JSR380知之甚少,所以我只是在猜测。
答案 1 :(得分:2)
这似乎是kotlin的问题。有关更多信息,请参见KT-27049。
Rafal G.已经指出,我们可以使用自定义验证器作为解决方法。所以这是一些代码:
注释:
import javax.validation.ConstraintValidator
import javax.validation.ConstraintValidatorContext
class NoNullElementsValidator : ConstraintValidator<NoNullElements, Collection<Any>> {
override fun isValid(value: Collection<Any>?, context: ConstraintValidatorContext): Boolean {
// null values are valid
if (value == null) {
return true
}
return value.stream().noneMatch { it == null }
}
}
ConstraintValidator:
data class User(
@field:NotEmpty
@field:NoNullElements
var roles: MutableSet<Role> = HashSet()
)
最后是更新的User类:
elementType
现在可以进行所有验证,结果ConstrainViolation略有不同。例如,propertyPath
和{{1}}如下所示。
Java:
科特琳:
可在此处找到来源:https://gitlab.com/darkatra/jsr380-kotlin-issue/tree/workaround
再次感谢您的帮助Rafal G.