[英]Cascaded bean validation 2.0 not working with nested object inside Map
Although, this question has been answered I'm interested why @Validated
is needed for a working cascaded validation of Map<String, @Valid Employee>
.虽然,这个问题已经得到回答,但我很感兴趣为什么需要@Validated
来进行Map<String, @Valid Employee>
的工作级联验证。
Update 2 : For some deeper understanding I've found those posts ( One , Two and Three ), which explains, that @Validated
is neeeded to activate method level validation.更新 2 :为了更深入地了解,我找到了这些帖子(一、二和三),这解释了@Validated
来激活方法级别验证。 With the help of this, collections can be validated, due they are no JavaBeans which are validated instead (JSR 303).借助于此,可以验证 collections,因为它们不是经过验证的 JavaBeans (JSR 303)。
Solution : I've updated my code snippets and my repository with working code examples.解决方案:我已经用工作代码示例更新了我的代码片段和我的存储库。 All I have to do is to annotate my controller with @Validated
and add some getters in Employee
.我所要做的就是用 @Validated 注释我的@Validated
并在Employee
中添加一些吸气剂。 MethodValidationPostProcessor
is not necessary at all. MethodValidationPostProcessor
根本不是必需的。
Update : I've updated my question and forked Spring Boot Rest example to add a minimal Rest API to demonstrate:更新:我更新了我的问题并分叉 Spring Boot Rest 示例以添加最小的 Rest API 来演示:
Github Repo . Github 回购。 The example values are inside README.md!示例值在 README.md 中!
I've got an Spring Boot 2 API to store some employees.我有一个 Spring Boot 2 API 来存放一些员工。 I can pass either one Employee
or either a Map<String, Employee>
.我可以传递一个Employee
或Map<String, Employee>
。
@Validated //this is the solution to activate map validation
@RestController
class EmployeeController {
@PostMapping("/employees")
List<Employee> newEmployee(@RequestBody @Valid Employee newEmployee) {
...
}
@PostMapping("/employees/bulk")
List<Employee> newEmployee(@RequestBody Map<String, @Valid Employee>
newEmployees) {
...
}
}
Employee exists of some inner static classes which also needs to be validated: Employee 存在一些内部 static 类也需要验证:
public class Employee {
@NotBlank
public final String name;
@Valid
public final EmployeeRole role;
@JsonCreator
public Employee(@JsonProperty("name") String name,
@JsonProperty("role") EmployeeRole role) {
this.name = name;
this.role = role;
}
// getters
public static class EmployeeRole {
@NotBlank
public String rolename;
@Min(0)
public int rating;
@JsonCreator
public EmployeeRole(@JsonProperty("rolename") String rolename,
@JsonProperty("rating") int rating) {
this.rolename = rolename;
this.rating = rating;
}
// getters
}
}
For now, validation for single requests are working but not for my bulk requests.目前,对单个请求的验证有效,但对我的批量请求无效。 As far as i know this should be possible with Bean validation 2.0.据我所知,这应该可以通过 Bean 验证 2.0 实现。
Do you know what I've did wrong?你知道我做错了什么吗? Do i need to write a custom validator?我需要编写自定义验证程序吗?
To make it working you have to do following:要使其正常工作,您必须执行以下操作:
Add
MethodValidationPostProcessor
bean to configuration将MethodValidationPostProcessor
bean 添加到配置中
@Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
return new MethodValidationPostProcessor();
}
Add
@Validated
to yourEmployeeController
将@Validated
添加到您的EmployeeController
@Validated
@RestController
public class EmployeeController {}'
Add
@Valid
toMap
or toEmployee
将@Valid
添加到Map
或Employee
public List<Employee> newEmployee(@RequestBody @Valid Map<String, Employee> newEmployees) {}
public List<Employee> newEmployee(@RequestBody Map<String, @Valid Employee> newEmployees) {}
That's all.就这样。 This is entire EmployeeController
:这是整个EmployeeController
:
@Validated
@RestController
public class EmployeeController {
@PostMapping("/employees")
public List<Employee> newEmployee(@RequestBody @Valid Employee newEmployee) {
return Collections.singletonList(newEmployee);
}
@PostMapping("/employees/bulk")
public List<Employee> newEmployee(@RequestBody @Valid Map<String, Employee> newEmployees) {
return new ArrayList<>(newEmployees.values());
}
}
And SpringBoot configuration file和SpringBoot配置文件
@SpringBootApplication
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
return new MethodValidationPostProcessor();
}
}
Hope it help you.希望对你有帮助。
There are two kinds of validation in spring system. spring系统中有两种验证方式。
@Valid
or @Validated
aside A: spring boot controller methods parameter validation, 只对controller中的@Valid
post request body data有效,@Valid or @Validated
aside@Validated
on class and @Valid
aside values to be validated B:方法级别验证,适用于任何方法参数和返回值@Validated
on class 和@Valid
aside values to be validatedWe can see that A is more narrow while B is a more common one.我们可以看到 A 更窄,而 B 更常见。 I'd like to answer the question on two aspects.我想从两个方面回答这个问题。
As describe in this post , the more detail
part, A and B triggers method enhancement via aop by calling different method in org.hibernate.validator.internal.engine.ValidatorImpl
, which leads to the difference.如本文所述, more detail
的部分,A 和 B 通过调用org.hibernate.validator.internal.engine.ValidatorImpl
中的不同方法通过 aop 触发方法增强,这导致了差异。
validate
method in ValidatorImpl
via RequestResponseBodyMethodProcessor
通过RequestResponseBodyMethodProcessor
调用ValidatorImpl
中的validate
方法validateParameters
method in ValidatorImpl
via MethodValidationInterceptor
B call 通过MethodValidationInterceptor
调用ValidatorImpl
中的validateParameters
方法They are different methods with different functions, so lead to different results.它们是具有不同功能的不同方法,因此导致不同的结果。 You can find the answer by reading the two methods.通过阅读这两种方法,您可以找到答案。
The JSR-303 defines functions of the methods we discussed above. JSR-303定义了我们上面讨论的方法的功能。
validate
method is explained in the validation method part, and the implementation must obey the logic defined in validation routine , in which it states that it will execute all the constraint validation for all reachable fields of the object, this is why element of List
object (or other collection instance) cannot be validated via this method - the elements of the collection are not fields of the collection instance. validate
方法部分解释了validate方法,其实现必须遵循验证例程中定义的逻辑,其中声明将对object的所有可达字段执行所有约束验证,这就是为什么List
object的元素(或其他集合实例)无法通过此方法验证 - 集合的元素不是集合实例的字段。
But validateParameters
, JSR-303 actually doesn't treat it as main topic and put it in Appendix C. Proposal for method-level validation
.但是validateParameters
,JSR-303 其实并没有把它作为主要话题,而是放在了Appendix C. Proposal for method-level validation
中。 It provides some description:它提供了一些描述:
The constraints declarations evaluated are the constraints hosted on the parameters of the method or constructor. If @Valid is placed on a parameter, constraints declared on the object itself are considered.
validateReturnedValue evaluates the constraints hosted on the method itself. If @Valid is placed on the method, the constraints declared on the object itself are considered.
public @NotNull String saveItem(@Valid @NotNull Item item, @Max(23) BigDecimal price)
In the previous example,
- item is validated against @NotNull and all the constraints it hosts
- price is validated against @Max(23)
- the result of saveItem is validated against @NotNull
and exclaim that Bean Validation providers are free to implement this proposal as a specific extension
.并声明Bean Validation providers are free to implement this proposal as a specific extension
。 As far as I know, the Hibernate Validation
project implements this method, makes constraints works on the object itself, and element of collection object.据我所知, Hibernate Validation
项目实现了此方法,使约束适用于 object 本身和集合 object 的元素。
I don't know why the spring framework guys call validate
in RequestResponseBodyMethodProcessor
, makes lots of related questions appeare in stackoverflow.我不知道为什么 spring 框架人员在RequestResponseBodyMethodProcessor
中调用validate
,使得很多相关问题出现在 stackoverflow 中。 Maybe it's just because http post body data usually is a form data, and can be represented by a java bean naturally.也许只是因为 http post body 数据通常是表单数据,自然可以用 java bean 表示。 If it's me, I'll call the validateParametes
in RequestResponseBodyMethodProcessor
for easy use.如果是我,我会调用RequestResponseBodyMethodProcessor
中的validateParametes
,方便使用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.