目录

Bean Validation 规范

Bean Validation Specification

Java Bean Validation Specification

Bean Validation standardizes constraint definition, declaration and validation for the Java platform. Constrain once, validate everywhere.

Bean Validation 标准化了Java平台的约束定义、描述、和验证。

  • Constraints for JavaBeans
  • Validation via API or automatically
    • JPA
    • JSF, Spring MVC, GWT
    • JAX-RS
  • Extensible(custom constraints)
  • BV 1.1: method validation

Jakarta Bean Validation 是一个 Java 规范

  • 允许您通过注释来表达对对象模型的约束
  • 让您以可扩展的方式编写自定义约束
  • 提供 API 来验证对象和对象图
  • 提供 API 来验证方法和构造函数的参数和返回值
  • 报告一组违规行为(本地化)
  • 在 Java SE 上运行并集成在 Jakarta EE 9 和 10 中

Bean Validation 1.0 (JSR-303)

定义了基于注解方式的JavaBean验证元数据模型和API,也可以通过XML进行元数据定义,但注解将覆盖XML的元数据定义。

JSR303 是一套JavaBean参数校验的标准,它定义了很多常用的校验注解,直接将这些注解加在JavaBean的属性上面,就可以在需要校验的时候进行校验了。

内建约束

@Valid 对实体类进行校验

注解 说明
@Null 被注释的元素必须为 null
@NotNull 被注释的元素必须不为 null
@AssertTrue 被注释的元素必须为 true
@AssertFalse 被注释的元素必须为 false
@Min(value) 被注释的元素必须是一个数字,值必须大于等于指定的最小值
@Max(value) 被注释的元素必须是一个数字,值必须小于等于指定的最大值
@DecimalMin(value) 被注释的元素必须是一个数字,值必须大于等于指定的最小值
@DecimalMax(value) 被注释的元素必须是一个数字,值必须小于等于指定的最大值
@Size(max,min) 被注释的元素到校必须在指定范围内
@Digits(integer,fraction) 被注释的元素必须是一个数字,值必须在可接受的范围内
@Past 被注释的元素必须是一个过去的日期
@Future 被注释的元素必须是一个将来的日期
@Pattern(value) 被注释的元素必须符合指定的正则表达式

validation-api 中的 NotNull 注解,hibernate-validator 中 NotNullValidator。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class NotNullValidator implements ConstraintValidator<NotNull, Object> {
  public NotNullValidator() {
  }

  public boolean isValid(Object object, ConstraintValidatorContext constraintValidatorContext) {
    return object != null;
  }
}

@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(NotNull.List.class)
@Documented
@Constraint(
  validatedBy = {}
)
public @interface NotNull {
  String message() default "{javax.validation.constraints.NotNull.message}";

  Class<?>[] groups() default {};

  Class<? extends Payload>[] payload() default {};

  @Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
  @Retention(RetentionPolicy.RUNTIME)
  @Documented
  public @interface List {
    NotNull[] value();
  }
}

Bean Validation 1.1 (JSR-349)

依赖注入

Bean Validation 使用几个组件 MessageInterpolator、TraversableResolver、ParameterNameProvider、ConstraintValidatorFactory、ConstraintValidator。Bean Validation 1.1 标准化了容器如何管理这些对象以及这些对象如何从容器服务中受益。特别是,Java EE 中定义的 CDI 支持。

CDI (Contexts and Dependency Injection) is a standard dependency injection framework included in Java EE 6 and higher. 它允许我们通过特定领域的生命周期上下文管理有状态组件的生命周期,并以类型安全的方式将组件(服务)注入客户端对象。

方法验证

Bean Validation 1.1 允许对任意方法和构造函数的参数和返回值施加约束。这样,Bean Validation API 可用于描述和验证应用于给定方法或构造函数的合约,即:

  • 在调用方法或构造函数之前调用者必须满足的先决条件和
  • 在方法或构造函数调用返回后向调用者保证的后置条件。

这启用了一种称为“按合同编程”(PbC) 的编程风格。与检查参数和返回值的完整性的传统方法相比,这种方法有几个优点:

  • 这些检查以声明方式表达,不必手动执行,从而减少了编写、读取和维护的代码。
  • 申请方法或构造函数的前置条件和后置条件不必在文档中再次表达,因为它的任何注释都会自动包含在生成的 JavaDoc 中。这减少了冗余,从而避免了实施和文档之间的努力和不一致。

Bean Validation 2.0 - JSR 380

1
2
3
4
5
6
 <!--Bean Validation 2.0 接口-->
// https://mvnrepository.com/artifact/javax.validation/validation-api
implementation 'javax.validation:validation-api:2.0.1.Final'
<!-- hibernate validator 实现-->
// https://mvnrepository.com/artifact/org.hibernate/hibernate-validator
implementation 'org.hibernate:hibernate-validator:7.0.4.Final'
  • 支持容器(集合)元素约束 List<@Positive Integer> positiveNumbers
    • 更灵活的级联验证 Map<@Valid CustomerType, @Valid Customer> customersByType
    • 支持 java.util.Optional
  • 所有内建约束标记为可重复 @Repeatable(List.class)
  • 新约束类型 @Email, @NotEmpty, @NotBlank, @Positive, @PositiveOrZero, @Negative, @NegativeOrZero, @PastOrPresent and @FutureOrPresent
  • 支持 JSR 310 date/time types for @Past and @Future
  • ConstraintValidator#initialize() 变为 default 方法

New Constraints

  • @NotEmpty @NotBlank
  • @Email
  • @Positive @PositiveOrZero @Negative @NegativeOrZero
  • @PastOrPresent @FutureOrPrent
1
2
3
4
public interface ConstraintValidator<A extends Annotation, T> {

  default void initialize(A constraintAnnotation) {}
  boolean isValid(T value, ConstraintValidatorContext context);

用例:不同角色不同密码强度

1
2
3
@Size(min = 8, group = Default.class)
@Size(min = 12, group = Admin.class)
private String password;

用例:不为空的集合元素

1
2
3
4
5
@NotEmpty
private List<String> names;
@OnElements(constraint=@NotEmpty)
private List<String> names;
private List<@NotEmpty String> names;

Type Annotations (JSR 308)

  • 新的元素类型 ElementType.TYPE_USE
1
2
3
4
5
6
7
8
9
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Size.List.class)
@Documented
@Constraint(
  validatedBy = {}
)
public @interface Size {
}

级联验证

1
2
3
private List<@Valid Address> addresses;
private Map<@Valid Comment, Integer> scorePerCommnet;
private Map<@valid AddressType,  List<@Valid Address>> addressByType;

Optional

OptionalInt, OptionalLong, OptionalDouble

1
Optional<@Email String> getEmail(){...}

@Past/@Future/@FutureOrPresent for JSR 310 类型:

java.time.LocalDateTime, ZonedDateTime etc.

1
2
@Future
private LocalData deliveryDate;

Jakarta Bean Validation 3.0

1
2
3
4
// https://mvnrepository.com/artifact/jakarta.validation/jakarta.validation-api
implementation 'jakarta.validation:jakarta.validation-api:3.0.1'
// https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator
implementation 'org.hibernate.validator:hibernate-validator:7.0.4.Final'

附录