Hibernate Validator 中文操作指南
10. Using constraint metadata
Jakarta Bean Validation 规范不仅提供了校验引擎,还提供了一个 API,用于以统一的方式检索约束元数据,无论约束是使用注释还是通过 XML 映射声明的。阅读本章以了解有关此 API 及其功能的更多信息。您可以在包 jakarta.validation.metadata 中找到所有元数据 API 类型。
The Jakarta Bean Validation specification provides not only a validation engine, but also an API for retrieving constraint metadata in a uniform way, no matter whether the constraints are declared using annotations or via XML mappings. Read this chapter to learn more about this API and its possibilities. You can find all the metadata API types in the package jakarta.validation.metadata.
本章中介绍的示例基于 @“19”中所示的类和约束声明。
The examples presented in this chapter are based on the classes and constraint declarations shown in Example 10.1, “Example classes”.
. Example 10.1: Example classes
package org.hibernate.validator.referenceguide.chapter10;
public class Person {
public interface Basic {
}
@NotNull
private String name;
//getters and setters ...
}
package org.hibernate.validator.referenceguide.chapter10;
public interface Vehicle {
public interface Basic {
}
@NotNull(groups = Vehicle.Basic.class)
String getManufacturer();
}
package org.hibernate.validator.referenceguide.chapter10;
@ValidCar
public class Car implements Vehicle {
public interface SeverityInfo extends Payload {
}
private String manufacturer;
@NotNull
@Size(min = 2, max = 14)
private String licensePlate;
private Person driver;
private String modelName;
public Car() {
}
public Car(
@NotNull String manufacturer,
String licencePlate,
Person driver,
String modelName) {
this.manufacturer = manufacturer;
this.licensePlate = licencePlate;
this.driver = driver;
this.modelName = modelName;
}
public void driveAway(@Max(75) int speed) {
//...
}
@LuggageCountMatchesPassengerCount(
piecesOfLuggagePerPassenger = 2,
validationAppliesTo = ConstraintTarget.PARAMETERS,
payload = SeverityInfo.class,
message = "There must not be more than {piecesOfLuggagePerPassenger} pieces " +
"of luggage per passenger."
)
public void load(List<Person> passengers, List<PieceOfLuggage> luggage) {
//...
}
@Override
@Size(min = 3)
public String getManufacturer() {
return manufacturer;
}
public void setManufacturer(String manufacturer) {
this.manufacturer = manufacturer;
}
@Valid
@ConvertGroup(from = Default.class, to = Person.Basic.class)
public Person getDriver() {
return driver;
}
//further getters and setters...
}
package org.hibernate.validator.referenceguide.chapter10;
public class Library {
@NotNull
private String name;
private List<@NotNull @Valid Book> books;
//getters and setters ...
}
package org.hibernate.validator.referenceguide.chapter10;
public class Book {
@NotEmpty
private String title;
@NotEmpty
private String author;
//getters and setters ...
}
10.1. BeanDescriptor
元数据 API 的入口点是方法 Validator#getConstraintsForClass() ,它返回 BeanDescriptor 接口的实例。使用此描述符,您可以获取直接在 bean 本身(类级或属性级)上声明的约束的元数据,还可以检索表示单个属性、方法和构造函数的元数据描述符。
The entry point into the metadata API is the method Validator#getConstraintsForClass(), which returns an instance of the BeanDescriptor interface. Using this descriptor, you can obtain metadata for constraints declared directly on the bean itself (class- or property-level), but also retrieve metadata descriptors representing single properties, methods and constructors.
Example 10.2, “Using BeanDescriptor” 展示了如何为 Car 类检索 BeanDescriptor ,以及如何以断言的形式使用此描述符。
Example 10.2, “Using BeanDescriptor” demonstrates how to retrieve a BeanDescriptor for the Car class and how to use this descriptor in form of assertions.
如果请求的类中托管的约束声明无效,将抛出 ValidationException。 |
If a constraint declaration hosted by the requested class is invalid, a ValidationException is thrown. |
. Example 10.2: Using BeanDescriptor
BeanDescriptor carDescriptor = validator.getConstraintsForClass( Car.class );
assertTrue( carDescriptor.isBeanConstrained() );
//one class-level constraint
assertEquals( 1, carDescriptor.getConstraintDescriptors().size() );
//manufacturer, licensePlate, driver
assertEquals( 3, carDescriptor.getConstrainedProperties().size() );
//property has constraint
assertNotNull( carDescriptor.getConstraintsForProperty( "licensePlate" ) );
//property is marked with @Valid
assertNotNull( carDescriptor.getConstraintsForProperty( "driver" ) );
//constraints from getter method in interface and implementation class are returned
assertEquals(
2,
carDescriptor.getConstraintsForProperty( "manufacturer" )
.getConstraintDescriptors()
.size()
);
//property is not constrained
assertNull( carDescriptor.getConstraintsForProperty( "modelName" ) );
//driveAway(int), load(List<Person>, List<PieceOfLuggage>)
assertEquals( 2, carDescriptor.getConstrainedMethods( MethodType.NON_GETTER ).size() );
//driveAway(int), getManufacturer(), getDriver(), load(List<Person>, List<PieceOfLuggage>)
assertEquals(
4,
carDescriptor.getConstrainedMethods( MethodType.NON_GETTER, MethodType.GETTER )
.size()
);
//driveAway(int)
assertNotNull( carDescriptor.getConstraintsForMethod( "driveAway", int.class ) );
//getManufacturer()
assertNotNull( carDescriptor.getConstraintsForMethod( "getManufacturer" ) );
//setManufacturer() is not constrained
assertNull( carDescriptor.getConstraintsForMethod( "setManufacturer", String.class ) );
//Car(String, String, Person, String)
assertEquals( 1, carDescriptor.getConstrainedConstructors().size() );
//Car(String, String, Person, String)
assertNotNull(
carDescriptor.getConstraintsForConstructor(
String.class,
String.class,
Person.class,
String.class
)
);
您可以通过 isBeanConstrained() 确定指定的类是否承载任何类或属性级别的约束。isBeanConstrained() 不考虑方法或构造函数约束。
You can determine whether the specified class hosts any class- or property-level constraints via isBeanConstrained(). Method or constructor constraints are not considered by isBeanConstrained().
方法 getConstraintDescriptors() 适用于所有从 ElementDescriptor 派生的描述符(请参阅 Section 10.4, “ElementDescriptor” ),并返回一组描述符,代表给定元素上直接声明的约束。对于 BeanDescriptor ,将返回 bean 的类级约束。可在 Section 10.7, “ConstraintDescriptor” 中找到关于 ConstraintDescriptor 的更多详细信息。
The method getConstraintDescriptors() is common to all descriptors derived from ElementDescriptor (see Section 10.4, “ElementDescriptor”) and returns a set of descriptors representing the constraints directly declared on the given element. In case of BeanDescriptor, the bean’s class- level constraints are returned. More details on ConstraintDescriptor can be found in Section 10.7, “ConstraintDescriptor”.
通过 getConstraintsForProperty()、getConstraintsForMethod() 和 getConstraintsForConstructor(),您可以获取一个描述符,该描述符表示一个给定的属性或可执行元素,该元素由其名称标识,并且在方法和构造函数中由其参数类型标识。在以下部分中描述了这些方法返回的不同描述符类型。
Via getConstraintsForProperty(), getConstraintsForMethod() and getConstraintsForConstructor() you can obtain a descriptor representing one given property or executable element, identified by its name and, in case of methods and constructors, parameter types. The different descriptor types returned by these methods are described in the following sections.
请注意,这些方法根据 @“34”中所述的约束继承规则考虑在超类型中声明的约束。示例是 @“30”属性的描述符,它提供对 @“31”上定义的所有约束以及实现方法 @“32”的访问。如果指定的元素不存在或未受约束,则返回 @“33”。
Note that these methods consider constraints declared at super-types according to the rules for constraint inheritance as described in Section 2.1.5, “Constraint inheritance”. An example is the descriptor for the manufacturer property, which provides access to all constraints defined on Vehicle#getManufacturer() and the implementing method Car#getManufacturer(). null is returned in case the specified element does not exist or is not constrained.
方法 getConstrainedProperties()、getConstrainedMethods() 和 getConstrainedConstructors() 分别返回(可能是空的)集合,其中包含所有受约束的属性、方法和构造函数。如果一个元素至少有一个约束或标记为级联验证,则该元素被视为受约束。在调用 getConstrainedMethods() 时,可以指定要返回的方法的类型(getters、non-getters 或两者)。
The methods getConstrainedProperties(), getConstrainedMethods() and getConstrainedConstructors() return (potentially empty) sets with all constrained properties, methods and constructors, respectively. An element is considered constrained if it has at least one constraint or is marked for cascaded validation. When invoking getConstrainedMethods(), you can specify the type of the methods to be returned (getters, non-getters or both).
10.2. PropertyDescriptor
接口 PropertyDescriptor 表示类的某个给定属性。只要遵守 JavaBeans 命名约定,就可以透明地声明对字段或属性 getter 的约束。 Example 10.3, “Using PropertyDescriptor” 展示了如何使用 PropertyDescriptor 接口。
The interface PropertyDescriptor represents one given property of a class. It is transparent whether constraints are declared on a field or a property getter, provided the JavaBeans naming conventions are respected. Example 10.3, “Using PropertyDescriptor” shows how to use the PropertyDescriptor interface.
. Example 10.3: Using PropertyDescriptor
PropertyDescriptor licensePlateDescriptor = carDescriptor.getConstraintsForProperty(
"licensePlate"
);
//"licensePlate" has two constraints, is not marked with @Valid and defines no group conversions
assertEquals( "licensePlate", licensePlateDescriptor.getPropertyName() );
assertEquals( 2, licensePlateDescriptor.getConstraintDescriptors().size() );
assertTrue( licensePlateDescriptor.hasConstraints() );
assertFalse( licensePlateDescriptor.isCascaded() );
assertTrue( licensePlateDescriptor.getGroupConversions().isEmpty() );
PropertyDescriptor driverDescriptor = carDescriptor.getConstraintsForProperty( "driver" );
//"driver" has no constraints, is marked with @Valid and defines one group conversion
assertEquals( "driver", driverDescriptor.getPropertyName() );
assertTrue( driverDescriptor.getConstraintDescriptors().isEmpty() );
assertFalse( driverDescriptor.hasConstraints() );
assertTrue( driverDescriptor.isCascaded() );
assertEquals( 1, driverDescriptor.getGroupConversions().size() );
使用 getConstraintDescriptors() ,您可以检索一组 ConstraintDescriptors ,其中提供有关给定属性的各个约束的更多信息。如果将属性标记为级联验证(使用 @Valid 注释或通过 XML),则方法 isCascaded() 返回 true ;否则返回 false 。由 getGroupConversions() 返回任何配置的组转换。有关 GroupConversionDescriptor 的更多详细信息,请参阅 Section 10.6, “GroupConversionDescriptor” 。
Using getConstraintDescriptors(), you can retrieve a set of ConstraintDescriptors providing more information on the individual constraints of a given property. The method isCascaded() returns true if the property is marked for cascaded validation (either using the @Valid annotation or via XML), false otherwise. Any configured group conversions are returned by getGroupConversions(). See Section 10.6, “GroupConversionDescriptor” for more details on GroupConversionDescriptor.
10.3. MethodDescriptor and ConstructorDescriptor
受约束的方法和构造函数分别由界面 MethodDescriptor ConstructorDescriptor 表示。 Example 10.4, “Using MethodDescriptor and ConstructorDescriptor” 展示了如何使用这些描述符。
Constrained methods and constructors are represented by the interfaces MethodDescriptor ConstructorDescriptor, respectively. Example 10.4, “Using MethodDescriptor and ConstructorDescriptor” demonstrates how to work with these descriptors.
. Example 10.4: Using MethodDescriptor and ConstructorDescriptor
//driveAway(int) has a constrained parameter and an unconstrained return value
MethodDescriptor driveAwayDescriptor = carDescriptor.getConstraintsForMethod(
"driveAway",
int.class
);
assertEquals( "driveAway", driveAwayDescriptor.getName() );
assertTrue( driveAwayDescriptor.hasConstrainedParameters() );
assertFalse( driveAwayDescriptor.hasConstrainedReturnValue() );
//always returns an empty set; constraints are retrievable by navigating to
//one of the sub-descriptors, e.g. for the return value
assertTrue( driveAwayDescriptor.getConstraintDescriptors().isEmpty() );
ParameterDescriptor speedDescriptor = driveAwayDescriptor.getParameterDescriptors()
.get( 0 );
//The "speed" parameter is located at index 0, has one constraint and is not cascaded
//nor does it define group conversions
assertEquals( "speed", speedDescriptor.getName() );
assertEquals( 0, speedDescriptor.getIndex() );
assertEquals( 1, speedDescriptor.getConstraintDescriptors().size() );
assertFalse( speedDescriptor.isCascaded() );
assert speedDescriptor.getGroupConversions().isEmpty();
//getDriver() has no constrained parameters but its return value is marked for cascaded
//validation and declares one group conversion
MethodDescriptor getDriverDescriptor = carDescriptor.getConstraintsForMethod(
"getDriver"
);
assertFalse( getDriverDescriptor.hasConstrainedParameters() );
assertTrue( getDriverDescriptor.hasConstrainedReturnValue() );
ReturnValueDescriptor returnValueDescriptor = getDriverDescriptor.getReturnValueDescriptor();
assertTrue( returnValueDescriptor.getConstraintDescriptors().isEmpty() );
assertTrue( returnValueDescriptor.isCascaded() );
assertEquals( 1, returnValueDescriptor.getGroupConversions().size() );
//load(List<Person>, List<PieceOfLuggage>) has one cross-parameter constraint
MethodDescriptor loadDescriptor = carDescriptor.getConstraintsForMethod(
"load",
List.class,
List.class
);
assertTrue( loadDescriptor.hasConstrainedParameters() );
assertFalse( loadDescriptor.hasConstrainedReturnValue() );
assertEquals(
1,
loadDescriptor.getCrossParameterDescriptor().getConstraintDescriptors().size()
);
//Car(String, String, Person, String) has one constrained parameter
ConstructorDescriptor constructorDescriptor = carDescriptor.getConstraintsForConstructor(
String.class,
String.class,
Person.class,
String.class
);
assertEquals( "Car", constructorDescriptor.getName() );
assertFalse( constructorDescriptor.hasConstrainedReturnValue() );
assertTrue( constructorDescriptor.hasConstrainedParameters() );
assertEquals(
1,
constructorDescriptor.getParameterDescriptors()
.get( 0 )
.getConstraintDescriptors()
.size()
);
getName() 返回给定方法或构造函数的名称。方法 hasConstrainedParameters() 和 hasConstrainedReturnValue() 可用于快速检查可执行元素是否有任何参数约束(单个参数上的约束或跨参数约束)或返回值约束。
getName() returns the name of the given method or constructor. The methods hasConstrainedParameters() and hasConstrainedReturnValue() can be used to perform a quick check whether an executable element has any parameter constraints (either constraints on single parameters or cross-parameter constraints) or return value constraints.
请注意,约束不会直接在 MethodDescriptor 和 ConstructorDescriptor 上公开,而是在表示可执行参数、返回值和跨参数约束的专用描述符上公开的。要获取这些描述符中的一个,请分别调用 getParameterDescriptors()、getReturnValueDescriptor() 或 getCrossParameterDescriptor()。
Note that constraints are not directly exposed on MethodDescriptor and ConstructorDescriptor, but rather on dedicated descriptors representing an executable’s parameters, its return value and its cross-parameter constraints. To get hold of one of these descriptors, invoke getParameterDescriptors(), getReturnValueDescriptor() or getCrossParameterDescriptor(), respectively.
这些描述符提供对元素约束 ( getConstraintDescriptors() ) 的访问,在参数和返回值的情况下,还提供对级联验证的配置 ( isValid() 和 getGroupConversions() )。对于参数,您还可以通过 getName() 和 getIndex() 检索由当前使用的参数名称提供程序(请参阅 Section 9.2.4, “ParameterNameProvider” )返回的索引和名称。
These descriptors provide access to the element’s constraints (getConstraintDescriptors()) and, in the case of parameters and return value, to its configuration for cascaded validation (isValid() and getGroupConversions()). For parameters, you also can retrieve the index and the name, as returned by the currently used parameter name provider (see Section 9.2.4, “ParameterNameProvider”) via getName() and getIndex().
遵循 JavaBeans 命名约定的 getter 方法被认为是 bean 属性,也是受约束方法。 |
Getter methods following the JavaBeans naming conventions are considered as bean properties but also as constrained methods. |
这意味着您可以通过获取 PropertyDescriptor (例如 BeanDescriptor.getConstraintsForProperty("foo") )或检查 getter 的 MethodDescriptor (例如 BeanDescriptor.getConstraintsForMethod("getFoo").getReturnValueDescriptor()) )的返回值描述符来检索相关的元数据。
That means you can retrieve the related metadata either by obtaining a PropertyDescriptor (e.g. BeanDescriptor.getConstraintsForProperty("foo")) or by examining the return value descriptor of the getter’s MethodDescriptor (e.g. BeanDescriptor.getConstraintsForMethod("getFoo").getReturnValueDescriptor()).
10.4. ElementDescriptor
ElementDescriptor 接口是单个描述符类型(如 BeanDescriptor 、 PropertyDescriptor 等)的通用基类。除了 getConstraintDescriptors() 之外,它还提供了一些对所有描述符通用的方法。
The ElementDescriptor interface is the common base class for the individual descriptor types such as BeanDescriptor, PropertyDescriptor etc. Besides getConstraintDescriptors() it provides some more methods common to all descriptors.
hasConstraints() 可快速查看元素是否具有任何直接约束(例如,在 BeanDescriptor 的情况下为类级别约束)。
hasConstraints() allows for a quick check whether an element has any direct constraints (e.g. class- level constraints in case of BeanDescriptor).
getElementClass() 返回由给定描述符表示的元素的 Java 类型。更具体地说,该方法返回:
getElementClass() returns the Java type of the element represented by a given descriptor. More specifically, the method returns
-
the object type when invoked on BeanDescriptor,
-
the type of a property or parameter when invoked on PropertyDescriptor or ParameterDescriptor respectively,
-
Object[].class when invoked on CrossParameterDescriptor,
-
the return type when invoked on ConstructorDescriptor, MethodDescriptor or ReturnValueDescriptor. void.class will be returned for methods which don’t have a return value.
Example 10.5, “Using ElementDescriptor methods” 展示了如何使用这些方法。
Example 10.5, “Using ElementDescriptor methods” shows how these methods are used.
. Example 10.5: Using ElementDescriptor methods
PropertyDescriptor manufacturerDescriptor = carDescriptor.getConstraintsForProperty(
"manufacturer"
);
assertTrue( manufacturerDescriptor.hasConstraints() );
assertEquals( String.class, manufacturerDescriptor.getElementClass() );
CrossParameterDescriptor loadCrossParameterDescriptor = carDescriptor.getConstraintsForMethod(
"load",
List.class,
List.class
).getCrossParameterDescriptor();
assertTrue( loadCrossParameterDescriptor.hasConstraints() );
assertEquals( Object[].class, loadCrossParameterDescriptor.getElementClass() );
最后, ElementDescriptor 提供对 ConstraintFinder API 的访问,该 API 可以精细地查询约束条件元数据。 Example 10.6, “Usage of ConstraintFinder” 展示了如何通过 findConstraints() 检索 ConstraintFinder 实例,并使用 API 查询约束条件元数据。
Finally, ElementDescriptor offers access to the ConstraintFinder API which allows you to query for constraint metadata in a fine grained way. Example 10.6, “Usage of ConstraintFinder” shows how to retrieve a ConstraintFinder instance via findConstraints() and use the API to query for constraint metadata.
. Example 10.6: Usage of ConstraintFinder
PropertyDescriptor manufacturerDescriptor = carDescriptor.getConstraintsForProperty(
"manufacturer"
);
//"manufacturer" constraints are declared on the getter, not the field
assertTrue(
manufacturerDescriptor.findConstraints()
.declaredOn( ElementType.FIELD )
.getConstraintDescriptors()
.isEmpty()
);
//@NotNull on Vehicle#getManufacturer() is part of another group
assertEquals(
1,
manufacturerDescriptor.findConstraints()
.unorderedAndMatchingGroups( Default.class )
.getConstraintDescriptors()
.size()
);
//@Size on Car#getManufacturer()
assertEquals(
1,
manufacturerDescriptor.findConstraints()
.lookingAt( Scope.LOCAL_ELEMENT )
.getConstraintDescriptors()
.size()
);
//@Size on Car#getManufacturer() and @NotNull on Vehicle#getManufacturer()
assertEquals(
2,
manufacturerDescriptor.findConstraints()
.lookingAt( Scope.HIERARCHY )
.getConstraintDescriptors()
.size()
);
//Combining several filter options
assertEquals(
1,
manufacturerDescriptor.findConstraints()
.declaredOn( ElementType.METHOD )
.lookingAt( Scope.HIERARCHY )
.unorderedAndMatchingGroups( Vehicle.Basic.class )
.getConstraintDescriptors()
.size()
);
通过 declaredOn(),您可以在某些元素类型上搜索已声明的 ConstraintDescriptors。这对于查找在字段或 getter 方法上声明的属性约束很有用。
Via declaredOn() you can search for ConstraintDescriptors declared on certain element types. This is useful to find property constraints declared on either fields or getter methods.
unorderedAndMatchingGroups() 将所得约束限制为与给定验证组匹配的约束。
unorderedAndMatchingGroups() restricts the resulting constraints to those matching the given validation group(s).
lookingAt() 允许区分直接在元素上指定的约束 (Scope.LOCAL_ELEMENT) 或属于该元素但托管在类层次结构中的约束 (Scope.HIERARCHY)。
lookingAt() allows to distinguish between constraints directly specified on the element (Scope.LOCAL_ELEMENT) or constraints belonging to the element but hosted anywhere in the class hierarchy (Scope.HIERARCHY).
您还可以结合不同的选项,如最后一个示例所示。
You can also combine the different options as shown in the last example.
unorderedAndMatchingGroups() 不受尊重,但尊重组继承和序列继承。
Order is not respected by unorderedAndMatchingGroups(), but group inheritance and inheritance via sequence are.
10.5. ContainerDescriptor and ContainerElementTypeDescriptor
ContainerDescriptor 接口是支持容器元素约束和级联验证( PropertyDescriptor 、 ParameterDescriptor 、 ReturnValueDescriptor )的所有元素的通用接口。
The ContainerDescriptor interface is the common interface for all the elements that support container element constraints and cascading validation (PropertyDescriptor, ParameterDescriptor, ReturnValueDescriptor).
它有一个返回 ContainerElementTypeDescriptor 集合的单个方法 getConstrainedContainerElementTypes()。
It has a single method getConstrainedContainerElementTypes() that returns a set of ContainerElementTypeDescriptor.
ContainerElementTypeDescriptor 扩展 ContainerDescriptor 以支持嵌套容器元素约束。
ContainerElementTypeDescriptor extends ContainerDescriptor to support nested container element constraints.
ContainerElementTypeDescriptor 包含有关容器、约束和级联验证的信息。
ContainerElementTypeDescriptor contains the information about the container, the constraints and the cascading validation.
Example 10.7, “Using ContainerElementTypeDescriptor” 展示了如何使用 getConstrainedContainerElementTypes() 检索 ContainerElementTypeDescriptor 的集合。
Example 10.7, “Using ContainerElementTypeDescriptor” shows how to use getConstrainedContainerElementTypes() to retrieve the set of ContainerElementTypeDescriptor.
. Example 10.7: Using ContainerElementTypeDescriptor
PropertyDescriptor booksDescriptor = libraryDescriptor.getConstraintsForProperty(
"books"
);
Set<ContainerElementTypeDescriptor> booksContainerElementTypeDescriptors =
booksDescriptor.getConstrainedContainerElementTypes();
ContainerElementTypeDescriptor booksContainerElementTypeDescriptor =
booksContainerElementTypeDescriptors.iterator().next();
assertTrue( booksContainerElementTypeDescriptor.hasConstraints() );
assertTrue( booksContainerElementTypeDescriptor.isCascaded() );
assertEquals(
0,
booksContainerElementTypeDescriptor.getTypeArgumentIndex().intValue()
);
assertEquals(
List.class,
booksContainerElementTypeDescriptor.getContainerClass()
);
Set<ConstraintDescriptor<?>> constraintDescriptors =
booksContainerElementTypeDescriptor.getConstraintDescriptors();
ConstraintDescriptor<?> constraintDescriptor =
constraintDescriptors.iterator().next();
assertEquals(
NotNull.class,
constraintDescriptor.getAnnotation().annotationType()
);
10.6. GroupConversionDescriptor
所有表示可能是级联验证对象(即 PropertyDescriptor 、 ParameterDescriptor 和 ReturnValueDescriptor )的元素的描述符类型都通过 getGroupConversions() 提供对元素组转换的访问。返回的集合包含每个已配置转换的 GroupConversionDescriptor ,允许检索转换的源组和目标组。 Example 10.8, “Using GroupConversionDescriptor” 展示了一个示例。
All those descriptor types that represent elements which can be subject of cascaded validation (i.e., PropertyDescriptor, ParameterDescriptor and ReturnValueDescriptor) provide access to the element’s group conversions via getGroupConversions(). The returned set contains a GroupConversionDescriptor for each configured conversion, allowing to retrieve source and target groups of the conversion. Example 10.8, “Using GroupConversionDescriptor” shows an example.
. Example 10.8: Using GroupConversionDescriptor
PropertyDescriptor driverDescriptor = carDescriptor.getConstraintsForProperty( "driver" );
Set<GroupConversionDescriptor> groupConversions = driverDescriptor.getGroupConversions();
assertEquals( 1, groupConversions.size() );
GroupConversionDescriptor groupConversionDescriptor = groupConversions.iterator()
.next();
assertEquals( Default.class, groupConversionDescriptor.getFrom() );
assertEquals( Person.Basic.class, groupConversionDescriptor.getTo() );
10.7. ConstraintDescriptor
最后但并非最不重要的一点, ConstraintDescriptor 接口描述了单个约束及其组成约束。通过此接口的实例,您可以访问约束注释及其参数。
Last but not least, the ConstraintDescriptor interface describes a single constraint together with its composing constraints. Via an instance of this interface you get access to the constraint annotation and its parameters.
Example 10.9, “Using ConstraintDescriptor” 展示了如何从 ConstraintDescriptor 检索默认约束属性(如消息模板、组等),以及自定义约束属性 ( piecesOfLuggagePerPassenger ) 和其他元数据,例如约束的注释类型及其验证者。
Example 10.9, “Using ConstraintDescriptor” shows how to retrieve default constraint attributes (such as message template, groups etc.) as well as custom constraint attributes (piecesOfLuggagePerPassenger) and other metadata such as the constraint’s annotation type and its validators from a ConstraintDescriptor.
. Example 10.9: Using ConstraintDescriptor
//descriptor for the @LuggageCountMatchesPassengerCount constraint on the
//load(List<Person>, List<PieceOfLuggage>) method
ConstraintDescriptor<?> constraintDescriptor = carDescriptor.getConstraintsForMethod(
"load",
List.class,
List.class
).getCrossParameterDescriptor().getConstraintDescriptors().iterator().next();
//constraint type
assertEquals(
LuggageCountMatchesPassengerCount.class,
constraintDescriptor.getAnnotation().annotationType()
);
//standard constraint attributes
assertEquals( SeverityInfo.class, constraintDescriptor.getPayload().iterator().next() );
assertEquals(
ConstraintTarget.PARAMETERS,
constraintDescriptor.getValidationAppliesTo()
);
assertEquals( Default.class, constraintDescriptor.getGroups().iterator().next() );
assertEquals(
"There must not be more than {piecesOfLuggagePerPassenger} pieces of luggage per " +
"passenger.",
constraintDescriptor.getMessageTemplate()
);
//custom constraint attribute
assertEquals(
2,
constraintDescriptor.getAttributes().get( "piecesOfLuggagePerPassenger" )
);
//no composing constraints
assertTrue( constraintDescriptor.getComposingConstraints().isEmpty() );
//validator class
assertEquals(
Arrays.<Class<?>>asList( LuggageCountMatchesPassengerCount.Validator.class ),
constraintDescriptor.getConstraintValidatorClasses()
);