Two kind of XML descriptors are used by Bean Validation. The first one describes the Bean Validation configuration provided as META-INF/validation.xml. The second one describes constraints declarations and closely matches the annotations declaration approach.
Bean Validation lets you declare constraints via XML rather than annotations. You can either ignore constraints declared via annotations or consider XML as adding additional constraints on top of annotation constraints. While it is not possible to define a new constraint via XML, you can redefine the list of ConstraintValidator classes associated to a given constraint definition.
There is no distinction between an annotation based constraint declaration and an XML based constraint declaration: they are considered equivalent and should be treaded as such by the Bean Validation provider.. Specifically when exploring metadata, the Bean Validation provider must ensure that an annotation instance corresponding to the XML declaration is provided viaConstraintDescriptor.getAnnnotation(). The annotation elements as well as ConstraintValidator.getParameters() must reflect the values described in the XML declaration (seeSection 7.1.3, “Converting the string representation of a value”). Likewise, ConstraintDescriptor.getConstraintValidatorClasses() must reflect XML based constraint definition overriding (see Section 7.1.2, “Overriding constraint definitions in XML”).
A given class must not be described more than once amongst the XML mapping descriptors. A given field or getter must not be described more than once on a given class description. A given constraint definition must not be overridden more than once amongst the XML mapping descriptors. If any of these rule is violated in a given validation deployment, aDuplicateMappingException is raised during the creation of the ValidatorFactory.
The schema is provided in Section 7.1.4, “XML Schema”.
If default-package is set, all unqualified class names (including annotations) are considered part of the package described by default-package.
A given JavaBean is described by the bean element. The name of the class is mandatory. By default, all constraint declarations expressed via annotation are ignored for classes described in XML. You can force Bean Validation to consider both annotation and XML constraint declarations by using ignore-annotation="false" on bean.
If the name of the class does refer to a class not present in in the classpath, a ConfigurationException is raised.
Example 7.1. Example of bean XML declaration
<constraint-mappings xmlns="http://jboss.org/xml/ns/javax/validation/mapping" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jboss.org/xml/ns/javax/validation/mapping validation-mapping-1.0.xsd"> <default-package>com.acme.app.domain</default-package> <bean class="Customer" ignore-annotations="false"> [...] </bean> <bean class="com.acme.common.model.Address"> [...] </bean> </constraint-mappings>
Class level annotations are described via the class element. If ignore-annotations is declared, Bean Validation must honor the explicit value for this element. If not declared, the default value for the bean is considered.
When ignore annotations is true, class-level Bean Validation annotations are ignored for this class (including the @GroupSequence). When ignore annotations is false:
Constraints declared in XML and constraints declared in annotations are added and form the list of class-level declared constraints.
@GroupSequence is considered unless group-sequence element is explicitly used.
Example 7.2. Example of class-level declaration
<constraint-mappings xmlns="http://jboss.org/xml/ns/javax/validation/mapping" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jboss.org/xml/ns/javax/validation/mapping validation-mapping-1.0.xsd"> <default-package>com.acme.app.domain</default-package> <bean class="Customer" ignore-annotations="false"> <class ignore-annotations="true"> [...] </class> </bean> <bean class="com.acme.common.model.Address"> <class> [...] </class> </bean> </constraint-mappings>
Field level annotations are described via the field element. The name attribute correspond to the name of the field considered. If ignore-annotations is declared, Bean Validation must honor the explicit value for this element. If not declared, the default value for the bean is considered.
When ignore annotations is true, field-level Bean Validation annotations on the targeted field are ignored (including the @Valid). When ignore annotations is false:
Constraints declared in XML and constraints declared in annotations are added and form the list of field-level declared constraints.
@Valid is considered unless valid element is explicitly use. Note that the only way to disable cascading on a field marked as @Valid is to use ignore-validation=true.
If the name of the field does not correspond to a field in the given bean a ConfigurationException is raised.
Example 7.3. Field-level declaration
<constraint-mappings xmlns="http://jboss.org/xml/ns/javax/validation/mapping" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jboss.org/xml/ns/javax/validation/mapping validation-mapping-1.0.xsd"> <default-package>com.acme.app.domain</default-package> <bean class="Customer" ignore-annotations="false"> <field name="firstName"> [...] </field> <field name="orders"> <valid/> [...] </field> </bean> </constraint-mappings>
Property-level annotations are described via the getter element. The name attribute correspond to the name of the property considered as defined in Section 3.1.2, “Field and property validation” (for example a getter String getAge() would have <getter name="age"/> as a corresponding descriptor). If ignore-annotations is declared, Bean Validation must honor the explicit value for this element. If not declared, the default value for the bean is considered.
When ignore annotations is true, property-level Bean Validation annotations on the targeted property are ignored (including the @Valid). When ignore annotations is false:
Constraints declared in XML and constraints declared in annotations are added and form the list of property-level declared constraints.
@Valid is considered unless valid element is explicitly use. Note that the only way to disable cascading on a field marked as @Valid is to use ignore-validation=true.
If the name of the property does not correspond to a property in the given bean a ConfigurationException is raised.
Example 7.4. Property-level declaration
<constraint-mappings xmlns="http://jboss.org/xml/ns/javax/validation/mapping" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jboss.org/xml/ns/javax/validation/mapping validation-mapping-1.0.xsd"> <default-package>com.acme.app.domain</default-package> <bean class="Customer" ignore-annotations="false"> <getter name="firstName"> [...] </getter> <getter name="orders"> <valid/> [...] </getter> </bean> </constraint-mappings>
A new constraint declaration is represented by the constraint element. The annotation attribute is the class name of the annotation representing the constraint. Message and groups are defined respectively by the message and groups elements.
Other custom elements of an annotation are represented by element. The name attribute is mandatory and represents the name of the element in the constraint declaration. “message”, “groups” are not permitted names, use the message or groups elements instead.
If the element represents a primitive type, a class or an enum, the string representation of its value is placed in the element itself. See Section 7.1.3, “Converting the string representation of a value” for a detailed explanation of the conversion rules from string to the type.
If the element represents a primitive type array, a class array or an enum array, the string representation of each value is placed in a value element placed under the element itself.
If the element represents an annotation, the annotation element is used to represent the annotation and placed under element. An annotation element contains element elements.
If the element represents an array of annotations, one or more annotation elements are placed under element.
Elements with default values in the annotation definition do not have to be represented in XML: the default value will be used in this case. If an XML constraint declaration is missing mandatory elements, or if it contains elements not part of the constraint definition, a ConfigurationException is raised.
Example 7.5. Constraint declaration
<constraint-mappings xmlns="http://jboss.org/xml/ns/javax/validation/mapping" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jboss.org/xml/ns/javax/validation/mapping validation-mapping-1.0.xsd"> <default-package>com.acme.app.domain</default-package> <bean class="Customer" ignore-annotations="false"> <field name="firstName"> <!-- @LooksLike(patterns={ @Pattern(value="myRegExp", flag=PatternFlag.INSENSITIVE), @Pattern(value="my2ndRegExp")} ) --> <constraint annotation="com.acme.app.constraint.LooksLike"> <element name="patterns"> <annotation> <element name="value">myRegExp</element> <element name="flag"> <value>INSENSITIVE</value> </element> </annotation> <annotation> <element name="value">my2ndRegExp</element> </annotation> </element> </constraint> </field> <field name="orders"> <valid/> <!-- @DiscreteSize(value={ 0, 20 } ) --> <constraint annotation="com.acme.app.constraint.DiscreteSize"> <element name="value"> <value>0</value> <value>20</value> </element> </constraint> </field> <getter name="orders"> <valid/> <!-- @Size(message="Size is limited", groups={Default.class, LightValidation.class}, max=30 ) --> <constraint annotation="javax.validation.constraint.Size"> <message>Size is limited</message> <groups> <value>com.acme.app.model.LightValidation</value> <value>javax.persistence.Default</value> </groups> <element name="max">30</element> </constraint> </getter> </bean> </constraint-mappings>
A constraint definition (ie. the annotation representing a constraint), cannot be fully expressed in XML but the list of ConstraintValidator associated to a given constraint can be altered.
A constraint definition is represented by a constraint-definition element. The annotation attribute represents the constraint annotation being altered. The validated-by elements represent the (ordered) list of ConstraintValidator implementations associated to the constraint.
If include-existing-validator is set to false, ConstraintValidator defined on the constraint annotation are ignored. If set to true, the list of ConstraintValidators described in XML are concatenated to the list of ConstraintValidator described on the annotation to form a new array of ConstraintValidator evaluated. Annotation based ConstraintValidator come before XML based ConstraintValidatot in the array. The new array is returned by ConstraintDescriptor.getConstraintValidatorClasses().
Example 7.6. Overriding constraint definitions
<constraint-mappings xmlns="http://jboss.org/xml/ns/javax/validation/mapping" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jboss.org/xml/ns/javax/validation/mapping validation-mapping-1.0.xsd"> <default-package>com.acme.app.domain</default-package> <bean class="com.acme.common.model.Address"> [...] </bean> <constraint-definition annotation="javax.validation.constraint.Size"> <validated-by include-existing-validators="true"> <value>com.acme.app.constraint.SizeValidatorForDictionary</value> </validated-by> </constraint-definition> <constraint-definition annotation="AcmeOrderNumber"> [...] </constraint-definition> </constraint-mappings>
Primitive types, Class and Enum are represented as strings in the XML descriptor. Elements of an array are represented by the value element.
byte are represented according to the rules defined in Byte.parseByte(String).
short are represented according to the rules defined in Short.parseShort(String).
int are represented according to the rules defined in Integer.parseInt(String).
long are represented according to the rules defined in Long.parseLong(String).
float are represented according to the rules defined in Float.parseFloat(String).
double are represented according to the rules defined in Double.parseDouble(String).
boolean are represented according to the rules defined in Boolean.parseBoolean(String).
char are represented according to the following rules:
the string must be of one character long
the character extracted from the string is the returned char
A Class is represented by the fully qualified class name of the class. Note that if the raw string is unqualified, default package is taken into account.
An enum is represented by its enum.name() value.
If any of the string representation does not match its type counterpart, a ConfigurationException is raised.
This section contains the XML schema used for constraint mapping.
<?xml version="1.0" encoding="UTF-8"?> <xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="http://jboss.org/xml/ns/javax/validation/mapping" xmlns:xs="http://www.w3.org/2001/XMLSchema" version="1.0"> <xs:element name="constraint-mappings" type="map:constraint-mappingsType" xmlns:map="http://jboss.org/xml/ns/javax/validation/mapping"/> <xs:complexType name="groupsType"> <xs:sequence> <xs:element type="xs:string" name="value" maxOccurs="unbounded" minOccurs="0"/> </xs:sequence> </xs:complexType> <xs:complexType name="groupSequenceType"> <xs:sequence> <xs:element type="xs:string" name="value" maxOccurs="unbounded" minOccurs="0"/> </xs:sequence> </xs:complexType> <xs:complexType name="constraint-mappingsType"> <xs:sequence> <xs:element type="xs:string" name="default-package" minOccurs="0"/> <xs:element type="map:beanType" name="bean" maxOccurs="unbounded" minOccurs="0" xmlns:map="http://jboss.org/xml/ns/javax/validation/mapping"/> <xs:element type="map:constraint-definitionType" name="constraint-definition" maxOccurs="unbounded" minOccurs="0" xmlns:map="http://jboss.org/xml/ns/javax/validation/mapping"/> </xs:sequence> </xs:complexType> <xs:complexType name="validated-byType"> <xs:sequence> <xs:element type="xs:string" name="value" maxOccurs="unbounded" minOccurs="0"/> </xs:sequence> <xs:attribute type="xs:boolean" name="include-existing-validators" use="optional"/> </xs:complexType> <xs:complexType name="constraintType"> <xs:sequence> <xs:element type="xs:string" name="message" minOccurs="0"/> <xs:element type="map:groupsType" name="groups" minOccurs="0" xmlns:map="http://jboss.org/xml/ns/javax/validation/mapping"/> <xs:element type="map:elementType" name="element" maxOccurs="unbounded" minOccurs="0" xmlns:map="http://jboss.org/xml/ns/javax/validation/mapping"/> </xs:sequence> <xs:attribute type="xs:string" name="annotation" use="required"/> </xs:complexType> <xs:complexType name="elementType" mixed="true"> <xs:sequence> <xs:element type="xs:string" name="value" maxOccurs="unbounded" minOccurs="0"/> <xs:element type="map:annotationType" name="annotation" maxOccurs="unbounded" minOccurs="0" xmlns:map="http://jboss.org/xml/ns/javax/validation/mapping"/> </xs:sequence> <xs:attribute type="xs:string" name="name" use="required"/> </xs:complexType> <xs:complexType name="classType"> <xs:sequence> <xs:element type="groupSequenceType" name="group-sequence" minOccurs="0"/> <xs:element type="xs:simpleType" name="stop-constraint-inheritance" fixed="" minOccurs="0"/> <xs:element type="map:constraintType" name="constraint" maxOccurs="unbounded" minOccurs="0" xmlns:map="http://jboss.org/xml/ns/javax/validation/mapping"/> </xs:sequence> <xs:attribute type="xs:boolean" name="ignore-annotations" use="optional"/> </xs:complexType> <xs:complexType name="beanType"> <xs:sequence> <xs:element type="map:classType" name="class" minOccurs="0" xmlns:map="http://jboss.org/xml/ns/javax/validation/mapping"> </xs:element> <xs:element type="map:fieldType" name="field" minOccurs="0" maxOccurs="unbounded" xmlns:map="http://jboss.org/xml/ns/javax/validation/mapping"/> <xs:element type="map:getterType" name="getter" minOccurs="0" maxOccurs="unbounded" xmlns:map="http://jboss.org/xml/ns/javax/validation/mapping"/> </xs:sequence> <xs:attribute type="xs:string" name="class" use="required"/> <xs:attribute type="xs:boolean" name="ignore-annotations" use="optional"/> </xs:complexType> <xs:complexType name="annotationType"> <xs:sequence> <xs:element type="map:elementType" name="element" maxOccurs="unbounded" minOccurs="0" xmlns:map="http://jboss.org/xml/ns/javax/validation/mapping"/> </xs:sequence> </xs:complexType> <xs:complexType name="getterType"> <xs:sequence> <xs:element type="xs:string" name="valid" minOccurs="0" fixed=""/> <xs:element type="xs:string" name="stop-constraint-inheritance" minOccurs="0" fixed=""/> <xs:element type="map:constraintType" name="constraint" minOccurs="0" maxOccurs="unbounded" xmlns:map="http://jboss.org/xml/ns/javax/validation/mapping"/> </xs:sequence> <xs:attribute type="xs:string" name="name" use="required"/> <xs:attribute type="xs:boolean" name="ignore-annotations" use="optional"/> </xs:complexType> <xs:complexType name="constraint-definitionType"> <xs:sequence> <xs:element type="map:validated-byType" name="validated-by" xmlns:map="http://jboss.org/xml/ns/javax/validation/mapping"/> </xs:sequence> <xs:attribute type="xs:string" name="annotation" use="required"/> </xs:complexType> <xs:complexType name="fieldType"> <xs:sequence> <xs:element type="xs:string" name="valid" minOccurs="0" fixed=""/> <xs:element type="xs:string" name="stop-constraint-inheritance" minOccurs="0" fixed=""/> <xs:element type="map:constraintType" name="constraint" minOccurs="0" maxOccurs="unbounded" xmlns:map="http://jboss.org/xml/ns/javax/validation/mapping"/> </xs:sequence> <xs:attribute type="xs:string" name="name" use="required"/> <xs:attribute type="xs:boolean" name="ignore-annotations" use="optional"/> </xs:complexType> </xs:schema>