Hibernate Validator 中文操作指南

8. Configuring via XML

到目前为止,我们已经为 Jakarta Bean Validation 使用了默认的配置源,即注解。但是,还存在两种允许通过 XML 进行配置的 XML 描述符。第一个描述符描述了通用的 Jakarta Bean Validation 行为,并作为 META-INF/validation.xml 提供。第二个描述符描述了约束声明,并且与通过注解的约束声明方法完全匹配。让我们看看这两个文档类型。

XSD 文件在 https://jakarta.ee/xml/ns/validation/ 页面上可用。

8.1. Configuring the validator factory in validation.xml

为 Hibernate 验证器启用 XML 配置的关键文件是 META-INF/validation.xml。如果此文件存在于 classpath 上,则会在创建 ValidatorFactory 时应用其配置。 Figure 1, “Validation configuration schema” 展示了 validation.xml 必须遵守的 XML 模式的模型视图。

validation configuration 2.0

Example 8.1, “validation.xml 展示了 validation.xml 的几个配置选项。所有设置都是可选的,并且相同的配置选项也可以通过 jakarta.validation.Configuration 以编程方式获得。事实上,将通过编程 API 明确指定的值覆盖 XML 配置。甚至可以通过 Configuration#ignoreXmlConfiguration() 完全忽略 XML 配置。另请参见 Section 9.2, “Configuring a ValidatorFactory

示例 8.1: validation.xml
<validation-config
        xmlns="https://jakarta.ee/xml/ns/validation/configuration"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="https://jakarta.ee/xml/ns/validation/configuration
            https://jakarta.ee/xml/ns/validation/validation-configuration-3.0.xsd"
        version="3.0">

    <default-provider>com.acme.ValidationProvider</default-provider>

    <message-interpolator>com.acme.MessageInterpolator</message-interpolator>
    <traversable-resolver>com.acme.TraversableResolver</traversable-resolver>
    <constraint-validator-factory>
        com.acme.ConstraintValidatorFactory
    </constraint-validator-factory>
    <parameter-name-provider>com.acme.ParameterNameProvider</parameter-name-provider>
    <clock-provider>com.acme.ClockProvider</clock-provider>

    <value-extractor>com.acme.ContainerValueExtractor</value-extractor>

    <executable-validation enabled="true">
        <default-validated-executable-types>
            <executable-type>CONSTRUCTORS</executable-type>
            <executable-type>NON_GETTER_METHODS</executable-type>
            <executable-type>GETTER_METHODS</executable-type>
        </default-validated-executable-types>
    </executable-validation>

    <constraint-mapping>META-INF/validation/constraints-car.xml</constraint-mapping>

    <property name="hibernate.validator.fail_fast">false</property>
</validation-config>

类路径中只能有一个名为 META-INF/validation.xml 的文件。如果找到多个,将引发异常。

节点 default-provider 允许选择 Jakarta Bean Validation 提供程序。如果类路径上有多个提供程序,这将会很有用。 message-interpolatortraversable-resolverconstraint-validator-factoryparameter-name-providerclock-provider 允许自定义 jakarta.validation 包中定义的接口 MessageInterpolatorTraversableResolverConstraintValidatorFactoryParameterNameProviderClockProvider 的已用实现。有关这些接口的更多信息,请参阅 Section 9.2, “Configuring a ValidatorFactory 的子部分。

value-extractor 允许声明其他值提取器,以从自定义容器类型中提取值或覆盖内置的值提取器。有关如何实现 jakarta.validation.valueextraction.ValueExtractor 的更多信息,请参见 Chapter 7, Value extraction

executable-validation 及其子节点为方法验证定义了默认值。Jakarta Bean Validation 规范将构造函数和非 getter 方法定义为默认值。enabled 属性充当全局开关,用于打开和关闭方法验证(参见 Chapter 3, Declaring and validating method constraints )。

通过 constraint-mapping 元素,您可以列出任意数量包含实际约束配置的其他 XML 文件。映射文件名必须使用其在类路径上的完全限定名称指定。有关编写映射文件的详细信息,请参见下一节。

最后但并非最不重要的一点是,你可以在 property 节点中指定提供者特定的属性。在示例中,我们正在使用 Hibernate 验证器特定的 hibernate.validator.fail_fast 属性(参见 Section 12.2, “Fail fast mode”)。

8.2. Mapping constraints via constraint-mappings

通过遵循 Figure 2, “Validation mapping schema” 中模式的文件可以表达 XML 中的约束。请注意,仅当通过 validation.xml 中的 constraint-mapping 列出时,才会处理这些映射文件。

validation mapping 2.0
示例 8.2:通过 XML 配置 Bean 约束
<constraint-mappings
        xmlns="https://jakarta.ee/xml/ns/validation/mapping"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="https://jakarta.ee/xml/ns/validation/mapping
            https://jakarta.ee/xml/ns/validation/validation-mapping-3.0.xsd"
        version="3.0">

    <default-package>org.hibernate.validator.referenceguide.chapter05</default-package>
    <bean class="Car" ignore-annotations="true">
        <field name="manufacturer">
            <constraint annotation="jakarta.validation.constraints.NotNull"/>
        </field>
        <field name="licensePlate">
            <constraint annotation="jakarta.validation.constraints.NotNull"/>
        </field>
        <field name="seatCount">
            <constraint annotation="jakarta.validation.constraints.Min">
                <element name="value">2</element>
            </constraint>
        </field>
        <field name="driver">
            <valid/>
        </field>
        <field name="partManufacturers">
            <container-element-type type-argument-index="0">
                <valid/>
            </container-element-type>
            <container-element-type type-argument-index="1">
                <container-element-type>
                    <valid/>
                    <constraint annotation="jakarta.validation.constraints.NotNull"/>
                </container-element-type>
            </container-element-type>
        </field>
        <getter name="passedVehicleInspection" ignore-annotations="true">
            <constraint annotation="jakarta.validation.constraints.AssertTrue">
                <message>The car has to pass the vehicle inspection first</message>
                <groups>
                    <value>CarChecks</value>
                </groups>
                <element name="max">10</element>
            </constraint>
        </getter>
    </bean>
    <bean class="RentalCar" ignore-annotations="true">
        <class ignore-annotations="true">
            <group-sequence>
                <value>RentalCar</value>
                <value>CarChecks</value>
            </group-sequence>
        </class>
    </bean>
    <constraint-definition annotation="org.mycompany.CheckCase">
        <validated-by include-existing-validators="false">
            <value>org.mycompany.CheckCaseValidator</value>
        </validated-by>
    </constraint-definition>
</constraint-mappings>
示例 8.3:通过 XML 配置方法约束
<constraint-mappings
        xmlns="https://jakarta.ee/xml/ns/validation/mapping"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="https://jakarta.ee/xml/ns/validation/mapping
            https://jakarta.ee/xml/ns/validation/validation-mapping-3.0.xsd"
        version="3.0">

    <default-package>org.hibernate.validator.referenceguide.chapter08</default-package>

    <bean class="RentalStation" ignore-annotations="true">
        <constructor>
            <return-value>
                <constraint annotation="ValidRentalStation"/>
            </return-value>
        </constructor>

        <constructor>
            <parameter type="java.lang.String">
                <constraint annotation="jakarta.validation.constraints.NotNull"/>
            </parameter>
        </constructor>

        <method name="getCustomers">
            <return-value>
                <constraint annotation="jakarta.validation.constraints.NotNull"/>
                <constraint annotation="jakarta.validation.constraints.Size">
                    <element name="min">1</element>
                </constraint>
            </return-value>
        </method>

        <method name="rentCar">
            <parameter type="Customer">
                <constraint annotation="jakarta.validation.constraints.NotNull"/>
            </parameter>
            <parameter type="java.util.Date">
                <constraint annotation="jakarta.validation.constraints.NotNull"/>
                <constraint annotation="jakarta.validation.constraints.Future"/>
            </parameter>
            <parameter type="int">
                <constraint annotation="jakarta.validation.constraints.Min">
                    <element name="value">1</element>
                </constraint>
            </parameter>
        </method>

        <method name="addCars">
            <parameter type="java.util.List">
                <container-element-type>
                    <valid/>
                    <constraint annotation="jakarta.validation.constraints.NotNull"/>
                </container-element-type>
            </parameter>
        </method>
    </bean>

    <bean class="Garage" ignore-annotations="true">
        <method name="buildCar">
            <parameter type="java.util.List"/>
            <cross-parameter>
                <constraint annotation="ELAssert">
                    <element name="expression">...</element>
                    <element name="validationAppliesTo">PARAMETERS</element>
                </constraint>
            </cross-parameter>
        </method>
        <method name="paintCar">
            <parameter type="int"/>
            <return-value>
                <constraint annotation="ELAssert">
                    <element name="expression">...</element>
                    <element name="validationAppliesTo">RETURN_VALUE</element>
                </constraint>
            </return-value>
        </method>
    </bean>

</constraint-mappings>

XML 配置紧密反映编程 API。因此,仅添加一些注释就足够了。default-package 用于所有需要类名的字段。如果指定的类不是完全限定的,则将使用配置的默认包。然后每个映射文件可以有多个 bean 节点,每个节点描述具有指定类名的实体上的约束。

一个特定的类在所有配置文件中只能配置一次。对给定约束注释的约束定义同样适用。它仅能出现在一个映射文件中。如果违反这些规则,将抛出 ValidationException

ignore-annotations 设置为 true 表示忽略放置在配置的 Bean 中的约束注解。此值默认设置为 true。ignore-annotations 也可用于 classfieldsgetterconstructormethodparametercross-parameterreturn-value 节点。如果没有在此类级别上明确指定,则应用配置的 Bean 值。

classfieldgettercontainer-element-typeconstructormethod 节点(及其子节点参数)确定约束放置在哪个级别。valid 节点用于启用级联验证,constraint 节点用于在相应级别上添加约束。每个约束定义都必须通过 annotation 属性定义类。Jakarta Bean Validation 规范所需的约束属性(messagegroupspayload)具有专用的节点。所有其他特定于约束的属性都使用 element 节点配置。

container-element-type 允许定义级联验证行为和容器元素的约束。在上面的示例中,您可以看到嵌套在 Map 值中的 List 上的嵌套容器元素约束的示例。type-argument-index 用于精确指出 Map 的哪个类型参数涉及配置。如果类型只有一个类型参数(例如,我们示例中的 List),则可以省略它。

class_节点还允许通过 _group-sequence_节点重新配置默认的组顺序(参见 Section 5.4, “Redefining the default group sequence”)。在示例中未显示的是 _convert-group_的使用,用于指定组转换(参见 Section 5.5, “Group conversion”)。此节点在 _fieldgettercontainer-element-type、_parameter_和 _return-value_上可用,并指定属性 _from_和 _to_来指定组。

最后但并非最不重要的是,可以通過 constraint-definition 節點變更與給定約束相關聯的 ConstraintValidator 實例列表。annotation 屬性表示要變更的約束註釋。validated-by 元素表示與約束相關聯的 ConstraintValidator 實例的(已排序)列表。如果 include-existing-validator 設置為 false,則會忽略約束註釋上定義的驗證器。如果設置為 true,則 XML 中描述的約束驗證器列表會連接至註釋上指定的驗證器列表。

约束定义的一个用例是更改 @URL 的默认约束定义。从历史上看,Hibernate Validator 对此约束的默认约束验证器使用 java.net.URL 构造函数来验证 URL 是否有效。然而,还有一个基于纯正则表达式的版本,可以使用 XML 进行配置:

使用 XML 注册基于正则表达式的约束定义以进行 @URL_ <constraint-definition annotation="org.hibernate.validator.constraints.URL"> <validated-by include-existing-validators="false"> <value>org.hibernate.validator.constraintvalidators.RegexpURLValidator</value> </validated-by></constraint-definition>_

使用 XML 注册基于正则表达式的约束定义以进行 @URL <constraint-definition annotation="org.hibernate.validator.constraints.URL"> <validated-by include-existing-validators="false"> <value>org.hibernate.validator.constraintvalidators.RegexpURLValidator</value> </validated-by> </constraint-definition>