Hibernate Validator 中文操作指南

2. Declaring and validating bean constraints

在本章中,您将学习如何声明(请参阅 Section 2.1, “Declaring bean constraints”)和验证(请参阅 Section 2.2, “Validating bean constraints”) Bean 限制。 Section 2.3, “Built-in constraints” 提供了与 Hibernate Validator 集成的所有内置限制的概述。

如果您有兴趣对方法参数和返回值应用约束,请参阅 Chapter 3, Declaring and validating method constraints

2.1. Declaring bean constraints

Jakarta Bean Validation 中的约束通过 Java 注释表示。在本节中,您将学习如何使用这些注释增强对象模型。有四种类型的 bean 约束:

  1. field constraints

  2. property constraints

  3. container element constraints

  4. class constraints

并非所有约束都可以放置在所有这些级别。事实上,Jakarta Bean Validation 定义的所有默认约束都不能放在类级别。约束注释本身中的 java.lang.annotation.Target 注释确定可以放置约束的元素。有关详细信息,请参阅 Chapter 6, Creating custom constraints

2.1.1. Field-level constraints

约束可以通过注释类的字段来表示。 Example 2.1, “Field-level constraints” 显示了字段级别配置示例:

示例 2.1:字段级约束
package org.hibernate.validator.referenceguide.chapter02.fieldlevel;

public class Car {

    @NotNull
    private String manufacturer;

    @AssertTrue
    private boolean isRegistered;

    public Car(String manufacturer, boolean isRegistered) {
        this.manufacturer = manufacturer;
        this.isRegistered = isRegistered;
    }

    //getters and setters...
}

当使用字段级约束时,将使用字段访问策略访问要验证的值。这意味着,即使存在此类访问器,验证引擎也会直接访问实例变量并且不调用属性访问器方法。

可以将约束应用于任何访问类型的字段(public、private 等)。不过,不支持对静态字段的约束。

验证字节码增强对象时,应使用属性级约束,因为字节码增强库将无法通过反射确定字段访问。

2.1.2. Property-level constraints

如果您的模型类遵循 JavaBeans 标准,您还可以注释 Bean 类的属性,而不是它的字段。 Example 2.2, “Property-level constraints” 使用了与 Example 2.1, “Field-level constraints” 中相同的实体,但是使用了属性级别约束。

示例 2.2:属性级约束
package org.hibernate.validator.referenceguide.chapter02.propertylevel;

public class Car {

    private String manufacturer;

    private boolean isRegistered;

    public Car(String manufacturer, boolean isRegistered) {
        this.manufacturer = manufacturer;
        this.isRegistered = isRegistered;
    }

    @NotNull
    public String getManufacturer() {
        return manufacturer;
    }

    public void setManufacturer(String manufacturer) {
        this.manufacturer = manufacturer;
    }

    @AssertTrue
    public boolean isRegistered() {
        return isRegistered;
    }

    public void setRegistered(boolean isRegistered) {
        this.isRegistered = isRegistered;
    }
}

必须注释属性的 getter 方法,而不是它的 setter。这样,无法写入的仅有 getter 方法的属性也能受到约束。

使用属性级别约束时,属性访问策略用于访问待验证的值,即验证引擎通过属性访问器方法访问状态。

建议在一个类中坚持使用 or 属性注释。不建议注释字段 and 和对应的 getter 方法,因为这会导致该字段被验证两次。

2.1.3. Container element constraints

可以在参数化类型的类型参数上直接指定约束:这些约束称为容器元素约束。

这就要求在约束定义中通过 @Target 来指定 ElementType.TYPE_USE。从 Jakarta Bean Validation 2.0 开始,内置 Jakarta Bean Validation 以及 Hibernate Validator 特定的约束会指定 ElementType.TYPE_USE,并且可以直接在此上下文中使用它们。

Hibernate Validator 验证在以下标准 Java 容器上指定的容器元素约束:

  1. java.util.Iterable 的实现(例如 _List_s、_Set_s),

  2. java.util.Map 的实现,支持键和值,

  3. java.util.Optional, java.util.OptionalInt, java.util.OptionalDouble, java.util.OptionalLong,

  4. JavaFX 的 javafx.beans.observable.ObservableValue 的各种实现。

它还支持自定义容器类型上的容器元素约束(请参阅 Chapter 7, Value extraction )。

在 6 以前的版本中,支持容器元素约束的一个子集。在容器级别需要 @Valid 注释来启用它们。从 Hibernate Validator 6 开始不再需要此操作。

下面我们展示几个示例,说明各种 Java 类型上的容器元素约束。

在这些示例中,@ValidPart 是一个自定义约束,允许在 TYPE_USE 上下文中使用。

2.1.3.1. With Iterable

Iterable 类型参数上应用约束时,Hibernate Validator 将验证每个元素。 Example 2.3, “Container element constraint on Set 显示了 Set 和容器元素约束的示例。

示例 2.3: Set 上的容器元素约束
package org.hibernate.validator.referenceguide.chapter02.containerelement.set;

public class Car {

    private Set<@ValidPart String> parts = new HashSet<>();

    public void addPart(String part) {
        parts.add( part );
    }

    //...

}
Car car = new Car();
car.addPart( "Wheel" );
car.addPart( null );

Set<ConstraintViolation<Car>> constraintViolations = validator.validate( car );

assertEquals( 1, constraintViolations.size() );

ConstraintViolation<Car> constraintViolation =
        constraintViolations.iterator().next();
assertEquals(
        "'null' is not a valid car part.",
        constraintViolation.getMessage()
);
assertEquals( "parts[].<iterable element>",
        constraintViolation.getPropertyPath().toString() );

注意属性路径明确指出违规源于可迭代元素。

2.1.3.2. With List

List 类型参数上应用约束时,Hibernate Validator 将验证每个元素。 Example 2.4, “Container element constraint on List 显示了带有容器元素约束的 List 的示例。

示例 2.4: List 上的容器元素约束
package org.hibernate.validator.referenceguide.chapter02.containerelement.list;

public class Car {

    private List<@ValidPart String> parts = new ArrayList<>();

    public void addPart(String part) {
        parts.add( part );
    }

    //...

}
Car car = new Car();
car.addPart( "Wheel" );
car.addPart( null );

Set<ConstraintViolation<Car>> constraintViolations = validator.validate( car );

assertEquals( 1, constraintViolations.size() );

ConstraintViolation<Car> constraintViolation =
        constraintViolations.iterator().next();
assertEquals(
        "'null' is not a valid car part.",
        constraintViolation.getMessage()
);
assertEquals( "parts[1].<list element>",
        constraintViolation.getPropertyPath().toString() );

此处,属性路径还包含无效元素的索引。

2.1.3.3. With Map

容器元素约束也针对映射键和值进行验证。Map 显示了带键约束和值约束的 Example 2.5, “Container element constraint on map keys and values” 示例。

示例 2.5:地图键和值上的容器元素约束
package org.hibernate.validator.referenceguide.chapter02.containerelement.map;

public class Car {

    public enum FuelConsumption {
        CITY,
        HIGHWAY
    }

    private Map<@NotNull FuelConsumption, @MaxAllowedFuelConsumption Integer> fuelConsumption = new HashMap<>();

    public void setFuelConsumption(FuelConsumption consumption, int value) {
        fuelConsumption.put( consumption, value );
    }

    //...

}
Car car = new Car();
car.setFuelConsumption( Car.FuelConsumption.HIGHWAY, 20 );

Set<ConstraintViolation<Car>> constraintViolations = validator.validate( car );

assertEquals( 1, constraintViolations.size() );

ConstraintViolation<Car> constraintViolation =
        constraintViolations.iterator().next();
assertEquals(
        "20 is outside the max fuel consumption.",
        constraintViolation.getMessage()
);
assertEquals(
        "fuelConsumption[HIGHWAY].<map value>",
        constraintViolation.getPropertyPath().toString()
);
Car car = new Car();
car.setFuelConsumption( null, 5 );

Set<ConstraintViolation<Car>> constraintViolations = validator.validate( car );

assertEquals( 1, constraintViolations.size() );

ConstraintViolation<Car> constraintViolation =
        constraintViolations.iterator().next();
assertEquals(
        "must not be null",
        constraintViolation.getMessage()
);
assertEquals(
        "fuelConsumption<K>[].<map key>",
        constraintViolation.getPropertyPath().toString()
);

违规的属性路径尤其有趣:

  1. 无效元素的键包含在属性路径中(在第二个示例中,键是 null)。

  2. 在第一个示例中,违反涉及 &lt;map value&gt;,在第二个示例中涉及 &lt;map key&gt;

  3. 在第二个示例中,你可能已注意到类型参数 &lt;K&gt; 的存在,稍后将详细介绍此内容。

2.1.3.4. With java.util.Optional

Optional 的类型参数上应用约束时,Hibernate Validator 将自动解包类型并验证内部值。Optional 显示了带容器元素约束的 Example 2.6, “Container element constraint on Optional” 示例。

示例 2.6:可选容器上的容器元素约束
package org.hibernate.validator.referenceguide.chapter02.containerelement.optional;

public class Car {

    private Optional<@MinTowingCapacity(1000) Integer> towingCapacity = Optional.empty();

    public void setTowingCapacity(Integer alias) {
        towingCapacity = Optional.of( alias );
    }

    //...

}
Car car = new Car();
car.setTowingCapacity( 100 );

Set<ConstraintViolation<Car>> constraintViolations = validator.validate( car );

assertEquals( 1, constraintViolations.size() );

ConstraintViolation<Car> constraintViolation = constraintViolations.iterator().next();
assertEquals(
        "Not enough towing capacity.",
        constraintViolation.getMessage()
);
assertEquals(
        "towingCapacity",
        constraintViolation.getPropertyPath().toString()
);

此处,属性路径仅包含属性的名称,因为我们将 Optional 视为“透明”容器。

2.1.3.5. With custom container types

自定义容器也可以使用包含元素约束。

ValueExtractor 必须在自定义类型中注册,以便检索要验证的值(请参阅 Chapter 7, Value extraction 以了解有关如何实现自己的 ValueExtractor 及如何注册它的详细信息)。

Example 2.7, “Container element constraint on custom container type” 显示了一个带有类型参数约束的自定义参数化类型示例。

示例 2.7:自定义容器类型上的容器元素约束
package org.hibernate.validator.referenceguide.chapter02.containerelement.custom;

public class Car {

    private GearBox<@MinTorque(100) Gear> gearBox;

    public void setGearBox(GearBox<Gear> gearBox) {
        this.gearBox = gearBox;
    }

    //...

}
package org.hibernate.validator.referenceguide.chapter02.containerelement.custom;

public class GearBox<T extends Gear> {

    private final T gear;

    public GearBox(T gear) {
        this.gear = gear;
    }

    public Gear getGear() {
        return this.gear;
    }
}
package org.hibernate.validator.referenceguide.chapter02.containerelement.custom;

public class Gear {
    private final Integer torque;

    public Gear(Integer torque) {
        this.torque = torque;
    }

    public Integer getTorque() {
        return torque;
    }

    public static class AcmeGear extends Gear {
        public AcmeGear() {
            super( 60 );
        }
    }
}
package org.hibernate.validator.referenceguide.chapter02.containerelement.custom;

public class GearBoxValueExtractor implements ValueExtractor<GearBox<@ExtractedValue ?>> {

    @Override
    public void extractValues(GearBox<@ExtractedValue ?> originalValue, ValueExtractor.ValueReceiver receiver) {
        receiver.value( null, originalValue.getGear() );
    }
}
Car car = new Car();
car.setGearBox( new GearBox<>( new Gear.AcmeGear() ) );

Set<ConstraintViolation<Car>> constraintViolations = validator.validate( car );
assertEquals( 1, constraintViolations.size() );

ConstraintViolation<Car> constraintViolation =
        constraintViolations.iterator().next();
assertEquals(
        "Gear is not providing enough torque.",
        constraintViolation.getMessage()
);
assertEquals(
        "gearBox",
        constraintViolation.getPropertyPath().toString()
);
2.1.3.6. Nested container elements

嵌套包含元素也支持约束。

在验证 Example 2.8, “Constraints on nested container elements” 中显示的 Car 对象时,将同时执行 @NotNullPartManufacturer 的约束。

示例 2.8:嵌套容器元素上的约束
package org.hibernate.validator.referenceguide.chapter02.containerelement.nested;

public class Car {

    private Map<@NotNull Part, List<@NotNull Manufacturer>> partManufacturers =
            new HashMap<>();

    //...
}

2.1.4. Class-level constraints

最后但并非最不重要的一点是,也可以在类级别放置约束。在这种情况下,并非单个属性是验证的对象,而是整个对象。如果验证依赖于对象多个属性之间的相关性,类级别约束非常有用。

Example 2.9, “Class-level constraint” 中的 Car 类具有两个属性 seatCountpassengers,应该确保乘客列表的条目数不超过可用座位数。为此,在类级别上添加了 @ValidPassengerCount 约束。该约束的验证器可以访问完整的 Car 对象,从而可以比较座位数和乘客数。

请参阅 Section 6.2, “Class-level constraints”,详细了解如何实现此自定义约束。

示例 2.9:类级约束
package org.hibernate.validator.referenceguide.chapter02.classlevel;

@ValidPassengerCount
public class Car {

    private int seatCount;

    private List<Person> passengers;

    //...
}

2.1.5. Constraint inheritance

当一个类实现接口或扩展另一个类时,在父类型上声明的所有约束注释都将以与在类自身上指定的约束相同的方式进行应用。为了让事情更清晰,我们来看看以下示例:

示例 2.10:约束继承
package org.hibernate.validator.referenceguide.chapter02.inheritance;

public class Car {

    private String manufacturer;

    @NotNull
    public String getManufacturer() {
        return manufacturer;
    }

    //...
}
package org.hibernate.validator.referenceguide.chapter02.inheritance;

public class RentalCar extends Car {

    private String rentalStation;

    @NotNull
    public String getRentalStation() {
        return rentalStation;
    }

    //...
}

此处,类 RentalCarCar 的子类,并添加了属性 rentalStation。如果验证了 RentalCar 实例,不仅会对 rentalStation 上的 @NotNull 约束进行评估,还会对父类上的 manufacturer 约束进行评估。

如果 Car 不是超类而是 RentalCar 实现的接口,则也是如此。

如果覆盖了方法,约束注释也会被聚合。因此,如果 RentalCar 覆盖了 Car 中的 getManufacturer() 方法,除了父类上的 @NotNull 约束外,还会对在覆盖方法上注释的任何约束进行评估。

2.1.6. Object graphs

Jakarta Bean Validation API 不仅允许验证单个类实例,还允许验证完整的对象图(级联验证)。若要执行此操作,只需使用 @Valid 注释代表对另一个对象的引用的字段或属性,如 Example 2.11, “Cascaded validation” 所示。

示例 2.11:级联验证
package org.hibernate.validator.referenceguide.chapter02.objectgraph;

public class Car {

    @NotNull
    @Valid
    private Person driver;

    //...
}
package org.hibernate.validator.referenceguide.chapter02.objectgraph;

public class Person {

    @NotNull
    private String name;

    //...
}

如果验证 Car 的实例,则会将引用的 Person 对象一同验证,因为 driver 字段已用 @Valid 注释。因此,如果引用的 Person 实例的 name 字段为 null,则 Car 的验证将失败。

对象图的验证是递归的,即如果标记为级联验证的引用指向一个本身具有用 @Valid 注释的属性的对象,则验证引擎也会对这些引用进行后续处理。验证引擎将确保在级联验证期间不会出现无限循环,例如,如果两个对象相互持有引用。

请注意,在级联验证期间 null 值会遭到忽略。

作为约束条件,对象图验证也适用于容器元素。这意味着容器的任何类型参数都可以使用 @Valid 注释,这将导致在验证父对象时验证每个包含的元素。

嵌套容器元素也支持级联验证。

示例 2.12:容器的级联验证
package org.hibernate.validator.referenceguide.chapter02.objectgraph.containerelement;

public class Car {

    private List<@NotNull @Valid Person> passengers = new ArrayList<Person>();

    private Map<@Valid Part, List<@Valid Manufacturer>> partManufacturers = new HashMap<>();

    //...
}
package org.hibernate.validator.referenceguide.chapter02.objectgraph.containerelement;

public class Part {

    @NotNull
    private String name;

    //...
}
package org.hibernate.validator.referenceguide.chapter02.objectgraph.containerelement;

public class Manufacturer {

    @NotNull
    private String name;

    //...
}

在验证 Example 2.12, “Cascaded validation of containers” 中显示的 Car 类的实例时,将创建 ConstraintViolation

  1. 如果乘客列表中包含的任何 Person 对象都有 null 名称;

  2. 如果映射键中包含的任何 Part 对象都有 null 名称;

  3. 如果嵌套在地图值列表中的任何 Manufacturer 对象的名称为 null

在 6 之前的版本中,Hibernate Validator 支持对容器元素的子集进行级联验证,并且它在容器级别实现(例如,可使用 @Valid private List<Person>Person 启用级联验证)。

这仍然受支持,但并不推荐。请改用容器元素级别 @Valid 注释,因为它更具表现力。

2.2. Validating bean constraints

Validator 接口是 Jakarta Bean Validation 中最重要的对象。下一节介绍如何获取 Validator 实例。然后,您将学习如何使用 Validator 接口的不同方法。

2.2.1. Obtaining a Validator instance

验证实体实例的第一步是获取 Validator 实例。获取此实例的途径是通过 Validation 类和 ValidatorFactory。最简单的方法是使用静态方法 Validation#buildDefaultValidatorFactory()

示例 2.13: Validation#buildDefaultValidatorFactory()
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
validator = factory.getValidator();

这将以默认配置启动验证器。请参阅 Chapter 9, Bootstrapping 以了解有关不同启动方法和如何获取特定配置 Validator 实例的详细信息。

2.2.2. Validator methods

Validator 接口包含三种方法,这些方法可用于验证整个实体或仅验证实体的单个属性。

所有三种方法都返回 Set<ConstraintViolation>。如果验证成功,则该集合为空。否则,将为每个违反的约束添加一个 ConstraintViolation 实例。

所有验证方法都有一个 var-args 参数,可用于指定在执行验证时应考虑哪些验证组。如果未指定参数,则使用默认验证组 ( jakarta.validation.groups.Default )。在 Chapter 5, Grouping constraints 中详细讨论了验证组的主题。

2.2.2.1. Validator#validate()

使用 validate() 方法来执行给定 Bean 的所有约束的验证。 Example 2.14, “Using Validator#validate() 显示了从 Example 2.2, “Property-level constraints” 验证 Car 类的实例,该实例不能满足 manufacturer 属性上的 @NotNull 约束。因此,验证调用返回一个 ConstraintViolation 对象。

示例 2.14:使用 Validator#validate()
Car car = new Car( null, true );

Set<ConstraintViolation<Car>> constraintViolations = validator.validate( car );

assertEquals( 1, constraintViolations.size() );
assertEquals( "must not be null", constraintViolations.iterator().next().getMessage() );
2.2.2.2. Validator#validateProperty()

借助 validateProperty(),您可以验证给定对象的单个命名属性。属性名称是 JavaBeans 属性名称。

示例 2.15:使用 Validator#validateProperty()
Car car = new Car( null, true );

Set<ConstraintViolation<Car>> constraintViolations = validator.validateProperty(
        car,
        "manufacturer"
);

assertEquals( 1, constraintViolations.size() );
assertEquals( "must not be null", constraintViolations.iterator().next().getMessage() );
2.2.2.3. Validator#validateValue()

通过使用 validateValue() 方法,您可以检查给定类的单个属性能否使用指定的值成功验证:

示例 2.16:使用 Validator#validateValue()

Set<ConstraintViolation<Car>> constraintViolations = validator.validateValue(
        Car.class,
        "manufacturer",
        null
);

assertEquals( 1, constraintViolations.size() );
assertEquals( "must not be null", constraintViolations.iterator().next().getMessage() );

@Valid 不被 validateProperty()validateValue() 认同。

例如,Validator#validateProperty() 用于将 Jakarta Bean Validation 集成到 JSF 2(请参阅 Section 11.2, “JSF & Seam”)中,以便在将值传播到模型之前验证输入表单中的值。

2.2.3. ConstraintViolation

2.2.3.1. ConstraintViolation methods

现在是仔细观察 ConstraintViolation 的时候了。通过使用 ConstraintViolation 的不同方法,可以确定有关验证失败原因的大量有用的信息。以下是对这些方法的概述。“示例”列下的值是指 Example 2.14, “Using Validator#validate()

getMessage()

插值错误消息

示例“不能为空”

Example

“不能为空”

getMessageTemplate()

非插值错误消息

示例“{…​ NotNull.message}”

Example

“{…​ NotNull.message}”

getRootBean()

正在验证的根 bean

示例 car

Example

car

getRootBeanClass()

正在验证的根 bean 的类

示例 Car.class

Example

Car.class

getLeafBean()

如果是一个 bean 约束,则该约束应用于的 bean 实例;如果是一个属性约束,则该约束应用于的属性所在的 bean 实例

示例 car

Example

car

getPropertyPath()

从根 bean 到已验证值的属性路径

示例包含一个类型为 PROPERTY 、名称为“manufacturer”的节点

Example

包含一个类型为 PROPERTY 、名称为 “制造商” 的节点

getInvalidValue()

未能通过约束的值

Example_null_

Example

null

getConstraintDescriptor()

报告未能通过的约束元数据

@NotNull 的 Exampledescriptor

Example

@NotNull 的 descriptor

2.2.3.2. Exploiting the property path

要确定触发违规的元素,您需要利用 getPropertyPath() 方法的结果。

返回的 Path 由描述元素路径的 Node 组成。

有关 Path 结构,以及 Jakarta Bean Validation 规范的各种 Node_s can be found in link:https://jakarta.ee/specifications/bean-validation/3.0/jakarta-bean-validation-spec-3.0.html#validationapi-constraintviolation[the _ConstraintViolation 分组的详细信息。

2.3. Built-in constraints

Hibernate Validator 由一组常用的基本约束组成。这些约束主要是由 Jakarta Bean Validation 规范定义的(参见 Section 2.3.1, “Jakarta Bean Validation constraints”)。此外,Hibernate Validator 提供了有用的自定义约束(参见 Section 2.3.2, “Additional constraints”)。

2.3.1. Jakarta Bean Validation constraints

以下提供了 Jakarta Bean 验证 API 中指定的所有约束的列表。所有这些约束均应用于字段/属性级别,Jakarta Bean 验证规范中没有定义任何类级别约束。如果您正在使用 Hibernate 对象关系映射器,那么在为模型创建 DDL 时,会考虑一些约束(请参阅“Hibernate 元数据影响”)。

Hibernate Validator 允许将一些约束应用到比 Jakarta Bean Validation 规范要求更多的类型的数据(例如,@Max 可以应用到字符串)。依赖此功能可能会影响你的应用程序在 Jakarta Bean Validation 提供程序之间的可移植性。

@AssertFalse

检查带注释的元素为 false

支持的数据类型 Booleanboolean

Hibernate 元数据影响无

Supported data types

Booleanboolean

Hibernate metadata impact

@AssertTrue

检查带注释的元素为 true

支持的数据类型 Booleanboolean

Hibernate 元数据影响无

Supported data types

Booleanboolean

Hibernate metadata impact

@DecimalMax(value=, inclusive=)

inclusive =false 时,检查带注释的值是否小于指定的最大值。否则,检查值是否小于或等于指定的最大值。参数值是根据 BigDecimal 字符串表示形式的最大值字符串表示形式。

支持的数据类型 BigDecimalBigIntegerCharSequencebyteshortintlong 及原始类型的相应包装器;HV 另外支持:任何 Numberjavax.money.MonetaryAmount 的子类型(如果 JSR 354 API 和其实现位于类路径中)

Hibernate 元数据影响无

Supported data types

BigDecimalBigIntegerCharSequencebyteshortintlong 及原始类型的相应包装器;HV 另外支持:任何 Numberjavax.money.MonetaryAmount 的子类型(如果 JSR 354 API 和其实现位于类路径中)

Hibernate metadata impact

@DecimalMin(value=, inclusive=)

inclusive =false 时,检查带注释的值是否大于指定的最大值。否则,检查值是否大于或等于指定的最大值。参数值是根据 BigDecimal 字符串表示形式的最小值字符串表示形式。

支持的数据类型 BigDecimalBigIntegerCharSequencebyteshortintlong 及原始类型的相应包装器;HV 另外支持:任何 Numberjavax.money.MonetaryAmount 的子类型

Hibernate 元数据影响无

Supported data types

BigDecimalBigIntegerCharSequencebyteshortintlong 及原始类型的相应包装器;HV 另外支持:任何 Numberjavax.money.MonetaryAmount 的子类型

Hibernate metadata impact

@Digits(integer=, fraction=)

检查注释的值是否为一个数字,包含 integer 个数字和 fraction 个小数位

支持的数据类型BigDecimal、 BigIntegerCharSequencebyteshortintlong 和基本类型的相应包装器;此外,HV 支持: Numberjavax.money.MonetaryAmount 的任何子类型

Hibernate 元数据影响定义列精度和小数位

Supported data types

BigDecimal、 BigIntegerCharSequencebyteshortintlong 和基本类型的相应包装器;此外,HV 支持: Numberjavax.money.MonetaryAmount 的任何子类型

Hibernate metadata impact

定义列精度和小数位

@Email

检查指定字符序列是否为一个有效的电子邮件地址。可选参数 regexpflags 允许指定一个额外的正则表达式(包括正则表达式标志)供电子邮件匹配。

支持的数据类型_CharSequence_

Hibernate 元数据影响无

Supported data types

CharSequence

Hibernate metadata impact

@Future

检查注释的日期是否在未来

支持的数据类型_java.util.Date_、 java.util.Calendarjava.time.Instantjava.time.LocalDatejava.time.LocalDateTimejava.time.LocalTimejava.time.MonthDayjava.time.OffsetDateTimejava.time.OffsetTimejava.time.Yearjava.time.YearMonthjava.time.ZonedDateTimejava.time.chrono.HijrahDatejava.time.chrono.JapaneseDatejava.time.chrono.MinguoDatejava.time.chrono.ThaiBuddhistDate ;此外,如果 Joda Time 日期/时间 API 在类路径中,则 HV 支持: ReadablePartialReadableInstant 的任何实现

Hibernate 元数据影响无

Supported data types

java.util.Datejava.util.Calendarjava.time.Instantjava.time.LocalDatejava.time.LocalDateTimejava.time.LocalTimejava.time.MonthDayjava.time.OffsetDateTimejava.time.OffsetTimejava.time.Yearjava.time.YearMonthjava.time.ZonedDateTimejava.time.chrono.HijrahDatejava.time.chrono.JapaneseDatejava.time.chrono.MinguoDatejava.time.chrono.ThaiBuddhistDate ;此外,如果 Joda Time 日期/时间 API 在类路径中,则 HV 支持: ReadablePartialReadableInstant 的任何实现

Hibernate metadata impact

@FutureOrPresent

检查注释的日期是否在现在或未来

支持的数据类型_java.util.Date_、 java.util.Calendarjava.time.Instantjava.time.LocalDatejava.time.LocalDateTimejava.time.LocalTimejava.time.MonthDayjava.time.OffsetDateTimejava.time.OffsetTimejava.time.Yearjava.time.YearMonthjava.time.ZonedDateTimejava.time.chrono.HijrahDatejava.time.chrono.JapaneseDatejava.time.chrono.MinguoDatejava.time.chrono.ThaiBuddhistDate ;此外,如果 Joda Time 日期/时间 API 在类路径中,则 HV 支持: ReadablePartialReadableInstant 的任何实现

Hibernate 元数据影响无

Supported data types

java.util.Datejava.util.Calendarjava.time.Instantjava.time.LocalDatejava.time.LocalDateTimejava.time.LocalTimejava.time.MonthDayjava.time.OffsetDateTimejava.time.OffsetTimejava.time.Yearjava.time.YearMonthjava.time.ZonedDateTimejava.time.chrono.HijrahDatejava.time.chrono.JapaneseDatejava.time.chrono.MinguoDatejava.time.chrono.ThaiBuddhistDate ;此外,如果 Joda Time 日期/时间 API 在类路径中,则 HV 支持: ReadablePartialReadableInstant 的任何实现

Hibernate metadata impact

@Max(value=)

检查注释的值是否小于或等于指定的较大值

支持的数据类型_BigDecimal_、 BigIntegerbyteshortintlong 和基本类型的相应包装器;此外,HV 支持: CharSequence 的任何子类型(评估由字符序列表示的数字值)、 Numberjavax.money.MonetaryAmount 的任何子类型

Hibernate 元数据影响为列添加检查约束

Supported data types

BigDecimalBigIntegerbyteshortintlong 和基本类型的相应包装器;此外,HV 支持: CharSequence 的任何子类型(评估由字符序列表示的数字值)、 Numberjavax.money.MonetaryAmount 的任何子类型

Hibernate metadata impact

为列添加检查约束

@Min(value=)

检查注释的值是否大于或等于指定的较小值

支持的数据类型_BigDecimal_、 BigIntegerbyteshortintlong 和基本类型的相应包装器;此外,HV 支持: CharSequence 的任何子类型(评估由字符序列表示的数字值)、 Numberjavax.money.MonetaryAmount 的任何子类型

Hibernate 元数据影响为列添加检查约束

Supported data types

BigDecimalBigIntegerbyteshortintlong 和基本类型的相应包装器;此外,HV 支持: CharSequence 的任何子类型(评估由字符序列表示的数字值)、 Numberjavax.money.MonetaryAmount 的任何子类型

Hibernate metadata impact

为列添加检查约束

@NotBlank

检查注释的字符序列不为 null 且修剪后的长度大于 0。与 @NotEmpty 的区别在于此约束只能应用于字符序列,并且会忽略尾随空格。

支持的数据类型_CharSequence_

Hibernate 元数据影响无

Supported data types

CharSequence

Hibernate metadata impact

@NotEmpty

检查带注释元素是否既非空也非 null

支持的数据类型_CharSequence_, Collection , Map 和数组

Hibernate 元数据影响无

Supported data types

CharSequence , Collection , Map 和数组

Hibernate metadata impact

@NotNull

检查已注释值是否不等于 null

支持的数据类型任何类型

Hibernate 元数据不可空列

Supported data types

任何类型

Hibernate metadata impact

列不可空

@Negative

检查元素是否严格为负。零值视为无效。

支持的数据类型_BigDecimal_、 BigIntegerbyteshortintlong 和基本类型的相应包装器;此外,HV 支持: CharSequence 的任何子类型(评估由字符序列表示的数字值)、 Numberjavax.money.MonetaryAmount 的任何子类型

Hibernate 元数据影响无

Supported data types

BigDecimalBigIntegerbyteshortintlong 和基本类型的相应包装器;此外,HV 支持: CharSequence 的任何子类型(评估由字符序列表示的数字值)、 Numberjavax.money.MonetaryAmount 的任何子类型

Hibernate metadata impact

@NegativeOrZero

检查元素是否为负或零。

支持的数据类型_BigDecimal_、 BigIntegerbyteshortintlong 和基本类型的相应包装器;此外,HV 支持: CharSequence 的任何子类型(评估由字符序列表示的数字值)、 Numberjavax.money.MonetaryAmount 的任何子类型

Hibernate 元数据影响无

Supported data types

BigDecimalBigIntegerbyteshortintlong 和基本类型的相应包装器;此外,HV 支持: CharSequence 的任何子类型(评估由字符序列表示的数字值)、 Numberjavax.money.MonetaryAmount 的任何子类型

Hibernate metadata impact

@Null

检查已注释值是否为 null

支持的数据类型任何类型

Hibernate 元数据影响无

Supported data types

任何类型

Hibernate metadata impact

@Past

检查注释日期是否在过去

支持的数据类型_java.util.Date_, java.util.Calendar , java.time.Instant , java.time.LocalDate , java.time.LocalDateTime , java.time.LocalTime , java.time.MonthDay , java.time.OffsetDateTime , java.time.OffsetTime , java.time.Year , java.time.YearMonth , java.time.ZonedDateTime , java.time.chrono.HijrahDate , java.time.chrono.JapaneseDate , java.time.chrono.MinguoDate , java.time.chrono.ThaiBuddhistDate ;HV 也支持,如果 Joda Time 日期/时间 API 在类路径中: ReadablePartialReadableInstant 的所有实现

Hibernate 元数据影响无

Supported data types

java.util.Date , java.util.Calendar , java.time.Instant , java.time.LocalDate , java.time.LocalDateTime , java.time.LocalTime , java.time.MonthDay , java.time.OffsetDateTime , java.time.OffsetTime , java.time.Year , java.time.YearMonth , java.time.ZonedDateTime , java.time.chrono.HijrahDate , java.time.chrono.JapaneseDate , java.time.chrono.MinguoDate , java.time.chrono.ThaiBuddhistDate ;HV 也支持,如果 Joda Time 日期/时间 API 在类路径中: ReadablePartialReadableInstant 的所有实现

Hibernate metadata impact

@PastOrPresent

检查已注释日期是否在过去或现在

支持的数据类型_java.util.Date_, java.util.Calendar , java.time.Instant , java.time.LocalDate , java.time.LocalDateTime , java.time.LocalTime , java.time.MonthDay , java.time.OffsetDateTime , java.time.OffsetTime , java.time.Year , java.time.YearMonth , java.time.ZonedDateTime , java.time.chrono.HijrahDate , java.time.chrono.JapaneseDate , java.time.chrono.MinguoDate , java.time.chrono.ThaiBuddhistDate ;HV 也支持,如果 Joda Time 日期/时间 API 在类路径中: ReadablePartialReadableInstant 的所有实现

Hibernate 元数据影响无

Supported data types

java.util.Date , java.util.Calendar , java.time.Instant , java.time.LocalDate , java.time.LocalDateTime , java.time.LocalTime , java.time.MonthDay , java.time.OffsetDateTime , java.time.OffsetTime , java.time.Year , java.time.YearMonth , java.time.ZonedDateTime , java.time.chrono.HijrahDate , java.time.chrono.JapaneseDate , java.time.chrono.MinguoDate , java.time.chrono.ThaiBuddhistDate ;HV 也支持,如果 Joda Time 日期/时间 API 在类路径中: ReadablePartialReadableInstant 的所有实现

Hibernate metadata impact

@Pattern(regex=, flags=)

检查带注释的字符串是否与正则表达式 regex 匹配,并考虑给定的标记 match

支持的数据类型_CharSequence_

Hibernate 元数据影响无

Supported data types

CharSequence

Hibernate metadata impact

@Positive

检查元素是否严格为正。零值视为无效。

支持的数据类型_BigDecimal_、 BigIntegerbyteshortintlong 和基本类型的相应包装器;此外,HV 支持: CharSequence 的任何子类型(评估由字符序列表示的数字值)、 Numberjavax.money.MonetaryAmount 的任何子类型

Hibernate 元数据影响无

Supported data types

BigDecimalBigIntegerbyteshortintlong 和基本类型的相应包装器;此外,HV 支持: CharSequence 的任何子类型(评估由字符序列表示的数字值)、 Numberjavax.money.MonetaryAmount 的任何子类型

Hibernate metadata impact

@PositiveOrZero

检查元素是否为正或零。

支持的数据类型_BigDecimal_、 BigIntegerbyteshortintlong 和基本类型的相应包装器;此外,HV 支持: CharSequence 的任何子类型(评估由字符序列表示的数字值)、 Numberjavax.money.MonetaryAmount 的任何子类型

Hibernate 元数据影响无

Supported data types

BigDecimalBigIntegerbyteshortintlong 和基本类型的相应包装器;此外,HV 支持: CharSequence 的任何子类型(评估由字符序列表示的数字值)、 Numberjavax.money.MonetaryAmount 的任何子类型

Hibernate metadata impact

@Size(min=, max=)

检查已注释元素的大小是否在 minmax 之间(包括 minmax

支持的数据类型_CharSequence_, Collection , Map 和数组

Hibernate 元数据 impactColumn 长度将被设置为 max

Supported data types

CharSequence , Collection , Map 和数组

Hibernate metadata impact

列长度将被设置为 max

除了上面列出的参数外,每个约束都有参数 message、groups 和 payload。这是 Jakarta Bean Validation 规范的要求。

2.3.2. Additional constraints

除了 Jakarta Bean 验证 API 定义的约束外,Hibernate 验证器还提供了以下列出的几个有用的自定义约束。除了一个例外外,这些约束也适用于字段/属性级别,只有 @ScriptAssert 是类级别约束。

@CreditCardNumber(ignoreNonDigitCharacters=)

检查注释的字符串序列是否通过了 Luhn 校验和测试。请注意,此验证旨在检查用户错误,而不是信用卡有效性!另请参见 Anatomy of a credit card numberignoreNonDigitCharacters 允许忽略非数字字符。默认值为 false

支持的数据类型_CharSequence_

Hibernate 元数据影响无

Supported data types

CharSequence

Hibernate metadata impact

@Currency(value=)

检查注释的 javax.money.MonetaryAmount 的货币单位是否属于指定的货币单位。

支持的数据类型任何 javax.money.MonetaryAmount 的子类型(如果 JSR 354 API 和一个实现位于类路径中)

Hibernate 元数据影响无

Supported data types

任何 javax.money.MonetaryAmount 的子类型(如果 JSR 354 API 和一个实现位于类路径中)

Hibernate metadata impact

@DurationMax(days=, hours=, minutes=, seconds=, millis=, nanos=, inclusive=)

检查注释的 java.time.Duration 元素是否不大于由注释参数构造的元素。如果 inclusive 标志设置为 true ,则允许相等。

支持的数据类型_java.time.Duration_

Hibernate 元数据影响无

Supported data types

java.time.Duration

Hibernate metadata impact

@DurationMin(days=, hours=, minutes=, seconds=, millis=, nanos=, inclusive=)

检查注释的 java.time.Duration 元素是否不小于由注释参数构造的元素。如果 inclusive 标志设置为 true ,则允许相等。

支持的数据类型_java.time.Duration_

Hibernate 元数据影响无

Supported data types

java.time.Duration

Hibernate metadata impact

@EAN

检查注释的字符串序列是否为有效的 EAN 条形码。type 确定条形码的类型。默认值为 EAN-13。

支持的数据类型_CharSequence_

Hibernate 元数据影响无

Supported data types

CharSequence

Hibernate metadata impact

@ISBN

检查注释的字符串序列是否为有效的 ISBNtype 确定 ISBN 的类型。默认值为 ISBN-13。

支持的数据类型_CharSequence_

Hibernate 元数据影响无

Supported data types

CharSequence

Hibernate metadata impact

@Length(min=, max=)

验证注释的字符串序列位于 minmax 之间(包括 minmax

支持的数据类型_CharSequence_

Hibernate 元数据 impactColumn 长度将被设置为 max

Supported data types

CharSequence

Hibernate metadata impact

列长度将被设置为 max

@CodePointLength(min=, max=, normalizationStrategy=)

验证注释的字符串序列的代码点长度位于 minmax 之间(包括 minmax )。如果 normalizationStrategy 已设置,则验证标准化值。

支持的数据类型_CharSequence_

Hibernate 元数据影响无

Supported data types

CharSequence

Hibernate metadata impact

@LuhnCheck(startIndex= , endIndex=, checkDigitIndex=, ignoreNonDigitCharacters=)

检查注释的字符串序列中的数字是否通过 Luhn 校验和算法(另请参见 Luhn algorithm )。 startIndexendIndex 允许仅对指定的子字符串运行算法。 checkDigitIndex 允许在字符串序列中使用任意数字作为校验数字。如果未指定,则假设校验数字是指定范围的一部分。最后, ignoreNonDigitCharacters 允许忽略非数字字符。

支持的数据类型_CharSequence_

Hibernate 元数据影响无

Supported data types

CharSequence

Hibernate metadata impact

@Mod10Check(multiplier=, weight=, startIndex=, endIndex=, checkDigitIndex=, ignoreNonDigitCharacters=)

检查注释的字符串序列中的数字是否通过通用模 10 校验和算法。 multiplier 确定奇数的乘数(默认为 3), weight 确定偶数的权重(默认为 1)。 startIndexendIndex 允许仅对指定的子字符串运行算法。 checkDigitIndex 允许在字符串序列中使用任意数字作为校验数字。如果未指定,则假设校验数字是指定范围的一部分。最后, ignoreNonDigitCharacters 允许忽略非数字字符。

支持的数据类型_CharSequence_

Hibernate 元数据影响无

Supported data types

CharSequence

Hibernate metadata impact

@Mod11Check(threshold=, startIndex=, endIndex=, checkDigitIndex=, ignoreNonDigitCharacters=, treatCheck10As=, treatCheck11As=)

检查注释的字符串序列中的数字是否通过模 11 校验和算法。 threshold 指定模 11 乘数增长的阈值;如果未指定值,则乘数将无限增长。 treatCheck10AstreatCheck11As 分别指定当模 11 校验和等于 10 或 11 时要使用的校验数字。分别默认为 X 和 0。 startIndexendIndexcheckDigitIndexignoreNonDigitCharacters 具有与 @Mod10Check 中相同的语义。

支持的数据类型_CharSequence_

Hibernate 元数据影响无

Supported data types

CharSequence

Hibernate metadata impact

@Normalized(form=)

验证带注释字符序列是否按照给定的 form 规范化。

支持的数据类型_CharSequence_

Hibernate 元数据影响无

Supported data types

CharSequence

Hibernate metadata impact

@Range(min=, max=)

检查带注释的值是否介于 (包括) 指定的最小值与最大值之间

支持的数据类型_BigDecimal_、 BigIntegerCharSequencebyteshortintlong 和基本类型的相应包装器

Hibernate 元数据影响无

Supported data types

BigDecimalBigIntegerCharSequencebyteshortintlong 和基本类型的相应包装器

Hibernate metadata impact

@ScriptAssert(lang=, script=, alias=, reportOn=)

检查给定的脚本是否可以成功用于带注释的元素。为了使用该限制,JSR 223(“适用于 JavaTM 平台的脚本”)定义的 Java 脚本 API 实现必须成为类路径的一部分。要评估的表达式可以用任何脚本或表达式语言编写,为此可以在类路径中找到 JSR 223 兼容引擎。即使这是一个类级约束,也可以使用 reportOn 属性报告特定属性的约束违规,而不是整个对象。

支持的数据类型任何类型

Hibernate 元数据影响无

Supported data types

任何类型

Hibernate metadata impact

@UniqueElements

检查带注释的集合是否只包含唯一元素。使用 equals() 方法确定相等性。默认消息不包括重复元素列表,但你可以通过覆盖消息并使用 {duplicates} 消息参数来包含它。重复元素列表也包含在约束违规的动态有效负载中。

支持的数据类型_Collection_

Hibernate 元数据影响无

Supported data types

Collection

Hibernate metadata impact

@URL(protocol=, host=, port=, regexp=, flags=)

根据 RFC2396 检查带注释字符序列是否是有效的 URL。如果指定了任何可选参数 protocolhostport ,则相应的 URL 片段必须与指定的值相匹配。可选参数 regexpflags 允许指定一个附加正则表达式(包括正则表达式标记),URL 必须与此相匹配。默认情况下,此约束使用 java.net.URL 构造函数来验证给定的字符串是否表示有效的 URL。同时还有一个基于正则表达式的版本 - RegexpURLValidator - 可以通过 XML(参见 Section 8.2, “Mapping constraints via constraint-mappings )或编程 API(参见 Section 12.15.2, “Adding constraint definitions programmatically” )进行配置。

支持的数据类型_CharSequence_

Hibernate 元数据影响无

Supported data types

CharSequence

Hibernate metadata impact

@UUID(allowEmpty=, allowNil=, version=, variant=, letterCase=)

根据 RFC 4122 检查带注释字符序列是否是有效的通用唯一标识符。 null 始终有效。选项 allowEmpty 允许空字符序列。 allowNil 包含空 UUID ( 00000000-0000-0000-0000-000000000000 )。 versionvariant 参数控制哪些 UUID 版本和变体被允许。 letterCase 确保小写或大写,但也可以将其配置为不区分大小写。

支持的数据类型_CharSequence_

Hibernate 元数据影响无

Supported data types

CharSequence

Hibernate metadata impact

2.3.2.1. Country specific constraints

Hibernate 验证器还提供一些国家/地区特定约束,例如用于验证社会安全号码的约束。

如果你必须实现一个特定国家的约束,可以考虑将其贡献给 Hibernate Validator!

@CNPJ

检查带注释字符序列是否表示巴西公司纳税人注册号 (Cadastro de Pessoa Jurídica)

支持的数据类型_CharSequence_

Hibernate 元数据影响无

国家/地区巴西

Supported data types

CharSequence

Hibernate metadata impact

Country

巴西

@CPF

检查带注释字符序列是否表示巴西个人纳税人注册号 (Cadastro de Pessoa Física)

支持的数据类型_CharSequence_

Hibernate 元数据影响无

国家/地区巴西

Supported data types

CharSequence

Hibernate metadata impact

Country

巴西

@TituloEleitoral

检查带注释字符序列是否表示巴西选民身份证号码 ( Título Eleitoral )

支持的数据类型_CharSequence_

Hibernate 元数据影响无

国家/地区巴西

Supported data types

CharSequence

Hibernate metadata impact

Country

巴西

@NIP

检查带注释字符序列是否表示波兰 VAT 识别号 ( NIP )

支持的数据类型_CharSequence_

Hibernate 元数据影响无

国家/地区波兰

Supported data types

CharSequence

Hibernate metadata impact

Country

波兰

@PESEL

检查带注释字符序列是否表示波兰国家身份证号码 ( PESEL )

支持的数据类型_CharSequence_

Hibernate 元数据影响无

国家/地区波兰

Supported data types

CharSequence

Hibernate metadata impact

Country

波兰

@REGON

检查带注释字符序列是否代表波兰纳税人身份识别号 ( REGON )。可以应用于 REGON 的 9 位数和 14 位数版本

支持的数据类型_CharSequence_

Hibernate 元数据影响无

国家/地区波兰

Supported data types

CharSequence

Hibernate metadata impact

Country

波兰

@INN

检查带注释字符序列是否代表俄罗斯纳税人身份识别号 ( INN )。可以应用于 INN 的个人和司法版本

支持的数据类型_CharSequence_

Hibernate 元数据影响无

国家俄罗斯

Supported data types

CharSequence

Hibernate metadata impact

Country

俄罗斯

在某些情况下 Jakarta Bean Validation 约束或 Hibernate Validator 提供的自定义约束无法满足您的要求。在这种情况下,您可以轻松编写自己的约束。您可以在 Chapter 6, Creating custom constraints 中找到更多信息。