当使用 @Component 注释自定义验证器时,将忽略 JSR-303 验证
JSR-303 validation is ignored when custom Validator is annotated with @Component
我注意到,当声明用 @Component
注释的自定义验证器 bean 时,JSR-303 验证在 Spring 中被完全忽略。有趣的是,自定义验证器甚至不必由任何 类 填写或使用。 Spring 扫描其组件这一事实似乎足以使 Spring 在对象绑定期间完全跳过 JSR-303 验证。从自定义验证器中删除 @Component
并重新启动 Web 应用程序可按预期启用 JSR-303 验证。使用 @Component
注释自定义验证器有其用途,例如具有 Spring Autowire 依赖项。
考虑下面的简单示例:
/* Simple JSR-303 annotated User object */
public class User {
@NotNull @Size(min = 2, max = 5)
protected String username;
@Size(min = 2, max = 32)
protected String firstName;
@Size(min = 2, max = 32)
protected String lastName;
@NotNull @Past @DateTimeFormat(pattern="dd/MM/yyyy")
protected Date dateOfBirth;
@NotNull @Email
protected String email;
protected String phone;
//getters and setters
}
/* Controller example */
@RestController
public class UserController {
@PostMapping("/users/register")
public ResponseEntity postUser(@Valid @RequestBody User user, BindingResult result) {
if (result.hasErrors()) {
return new ResponseEntity(result.getAllErrors(), HttpStatus.INTERNAL_SERVER_ERROR);
}
return new ResponseEntity(user, HttpStatus.CREATED);
}
}
/* Custom validator (doesn't even have to be in use) */
@Component //commenting out @Component annotation enables JSR-303 again
public class SomeValidator implements Validator {
@Override
public boolean supports(Class<?> clazz) {
//just an example
return false;
}
@Override
public void validate(Object target, Errors errors) {
//empty
}
}
我一直在摸不着头脑,无法弄清楚为什么我的 JSR-303 对象没有经过验证,但我设法缩小了范围,并使用包含上述内容的 Spring 启动项目复制了它类。
这是为什么?我是不是遗漏了什么或者这是一个 Spring 错误?
编辑
所以您的代码中存在许多问题。首先,您的自定义验证器不支持任何东西,因此它永远不会被调用。你可能已经意识到了这一点,所以我会把它留给你来解决。
不过,您真正的问题是,通过创建这样的验证器 bean,Spring 不会创建 defaultValidator
bean(这是一个 LocalValidatorFactoryBean
),也不会创建methodValidationPostProcessor
bean(验证方法参数需要它)。这是人们 运行 和 Spring 一起遇到的一个常见问题:一旦你做了一些事情来干扰自动配置过程,你就必须手动定义一些东西。解决方案很简单:创建一个定义这些 bean 的配置 class。示例:
@Configuration
public class ValidationConfig {
@Bean public LocalValidatorFactoryBean defaultValidator() {
return new LocalValidatorFactoryBean();
}
@Bean public MethodValidationPostProcessor methodValidationPostProcessor() {
return new MethodValidationPostProcessor();
}
}
我注意到,当声明用 @Component
注释的自定义验证器 bean 时,JSR-303 验证在 Spring 中被完全忽略。有趣的是,自定义验证器甚至不必由任何 类 填写或使用。 Spring 扫描其组件这一事实似乎足以使 Spring 在对象绑定期间完全跳过 JSR-303 验证。从自定义验证器中删除 @Component
并重新启动 Web 应用程序可按预期启用 JSR-303 验证。使用 @Component
注释自定义验证器有其用途,例如具有 Spring Autowire 依赖项。
考虑下面的简单示例:
/* Simple JSR-303 annotated User object */
public class User {
@NotNull @Size(min = 2, max = 5)
protected String username;
@Size(min = 2, max = 32)
protected String firstName;
@Size(min = 2, max = 32)
protected String lastName;
@NotNull @Past @DateTimeFormat(pattern="dd/MM/yyyy")
protected Date dateOfBirth;
@NotNull @Email
protected String email;
protected String phone;
//getters and setters
}
/* Controller example */
@RestController
public class UserController {
@PostMapping("/users/register")
public ResponseEntity postUser(@Valid @RequestBody User user, BindingResult result) {
if (result.hasErrors()) {
return new ResponseEntity(result.getAllErrors(), HttpStatus.INTERNAL_SERVER_ERROR);
}
return new ResponseEntity(user, HttpStatus.CREATED);
}
}
/* Custom validator (doesn't even have to be in use) */
@Component //commenting out @Component annotation enables JSR-303 again
public class SomeValidator implements Validator {
@Override
public boolean supports(Class<?> clazz) {
//just an example
return false;
}
@Override
public void validate(Object target, Errors errors) {
//empty
}
}
我一直在摸不着头脑,无法弄清楚为什么我的 JSR-303 对象没有经过验证,但我设法缩小了范围,并使用包含上述内容的 Spring 启动项目复制了它类。 这是为什么?我是不是遗漏了什么或者这是一个 Spring 错误?
编辑
所以您的代码中存在许多问题。首先,您的自定义验证器不支持任何东西,因此它永远不会被调用。你可能已经意识到了这一点,所以我会把它留给你来解决。
不过,您真正的问题是,通过创建这样的验证器 bean,Spring 不会创建 defaultValidator
bean(这是一个 LocalValidatorFactoryBean
),也不会创建methodValidationPostProcessor
bean(验证方法参数需要它)。这是人们 运行 和 Spring 一起遇到的一个常见问题:一旦你做了一些事情来干扰自动配置过程,你就必须手动定义一些东西。解决方案很简单:创建一个定义这些 bean 的配置 class。示例:
@Configuration
public class ValidationConfig {
@Bean public LocalValidatorFactoryBean defaultValidator() {
return new LocalValidatorFactoryBean();
}
@Bean public MethodValidationPostProcessor methodValidationPostProcessor() {
return new MethodValidationPostProcessor();
}
}