The last big missing piece of the spec was the ability do configure Bean Validation via XML. An META-INF/validation.xml file can optionally be used for that:
 - choose the default provider
 - choose MessageInterpolator and the other integration point
 - list XML Mapping files
 - list provider specific properties

Here is an attempt to formalize that. Note that I did change the Configuration object a bit (see the API below (section 4.4.3) and its role in the bootstrap process. It is know responsible for parsing valiation.xml and merge metadata from the programmatic calls and from XML. You can also force BV to ignore validation.xml (especially useful for containers that want to parse such resources themselves).

Th proposal is still rough on the edges. Let me know what is confusing.




4.4.6. XML Configuration: META-INF/validation.xml

Unless explicitly ignored by calling Configuration.ignoreXMLConfiguration(), a ValidatorFactory takes into account the configuration available in META-INF/validation.xml. This configuration file is optional but can be used by application to refine some of the Bean Validation behavior.

Unless stated otherwise, XML based configuration settings are overridden by values explicitly set via the Configuration API. For example, the MessageInterpolator defined viaConfiguration.messageInterpolator(MessageInterpolator) has priority over the message-interpolator definition.

default-provider: represents the class name of the provider specific Configuration sub-interface. If defined, the provider suitable for this interface is used (unless a specific provider has been chosen via the programmatic approach).

message-interpolator: represents the fully qualified class name of the MessageInterpolator implementation. This implementation must have a public no-arg constructor. This element is optional.

traversable-resolver: represents the fully qualified class name of the TravedrsableResolver implementation. This implementation must have a public no-arg constructor. This element is optional.

constraint-validator-factory: represents the fully qualified class name of the ConstraintValidatorFactory implementation. This implementation must have a public no-arg constructor. This element is optional.

constraint-mapping: represents the resource path of an XML mapping file. More than one constraint-mapping element can be present. Mappings provided viaConfiguration.addMapping(InputString) are added to the list of mappings described via constraint-mapping.

property: represents a key/value pair property providing room to provider specific configuration. Vendors should use vendor namespaces for properties (e.g.,com.acme.validation.logging). Entries that make use of the namespace javax.validation and its subnamespaces must not be used for vendor-specific information. The namespacejavax.validation is reserved for use by this specification. Properties defined via Configuration.addProperty(String, String) are added to the properties defined via property. If a property with the same name are defined in both XML and via the programmatic API, the value provided via programmatic API has priority.

Example 4.23. META-INF/validation.xml file

<?xml version="1.0" encoding="UTF-8"?>
<validation-config
        xmlns="http://jboss.org/xml/ns/javax/validation/configuration"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://jboss.org/xml/ns/javax/validation/configuration validation-configuration-1.0.xsd">
    <default-provider>com.acme.ACMEValidatorConfiguration</default-provider>
    <message-interpolator>com.acme.ACMEAwareMessageInterpolator</message-interpolator>

    <constraint-mapping>META-INF/validation/order-constraints.xml</constraint-mapping>
    <constraint-mapping>META-INF/validation/catalog-constraints.xml</constraint-mapping>
    <constraint-mapping>META-INF/validation/customer-constraints.xml</constraint-mapping>

    <property name="com.acme.validation.logging">WARN</property>
    <property name="com.acme.validation.safetyChecking">failOnError</property>

</validation-config>

The XML schema is described in Section 7.2, “Configuration schema”.


7.2. Configuration schema

XML Configuration is set in META-INF/validation.xml. The file is optional. The XML schema followed by the configuration file is as followed.

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema attributeFormDefault="unqualified"
           elementFormDefault="qualified"
           targetNamespace="http://jboss.org/xml/ns/javax/validation/configuration"
           xmlns:xs="http://www.w3.org/2001/XMLSchema"
           version="1.0">
    <xs:element name="validation-config" type="validation-configType"/>
    <xs:complexType name="validation-configType">
        <xs:sequence>
            <xs:element type="xs:string" name="default-provider" minOccurs="0"/>
            <xs:element type="xs:string" name="message-interpolator" minOccurs="0"/>
            <xs:element type="xs:string" name="traversable-resolver" minOccurs="0"/>
            <xs:element type="xs:string" name="constraint-validator-factory" minOccurs="0"/>
            <xs:element type="xs:string" name="constraint-mapping" maxOccurs="unbounded" minOccurs="0"/>
            <xs:element type="propertyType" name="property" maxOccurs="unbounded" minOccurs="0"/>
        </xs:sequence>
    </xs:complexType>
    <xs:complexType name="propertyType">
        <xs:attribute name="name" use="required" type="xs:string"/>
    </xs:complexType>
</xs:schema>

See Section 4.4.6, “XML Configuration: META-INF/validation.xml” for more information on XML based configuration.



4.4.3. Configuration

Configuration collects configuration informations, determines the correct provider implementation and delegates it the ValidatorFactory creation. This class lets you define:

  • the message interpolator strategy instance

  • the traversable resolver strategy instance

  • the constraint validator factory instance

  • XML constraint mappings

  • provider specific properties

  • whether or not META-INF/validation.xml is considered.

Configuration does provide a MessageInterpolator implementation following the default Bean Validation MessageInterpolator rules as defined in Section 4.3.1, “Default message interpolation” by calling getDefaultMessageInterpolator(). Such an implementation is useful to let a custom MessageInterpolator delegates to the standard MessageInterpolator(see Section 4.3.2, “Custom message interpolation” and an example making use of getDefaultMessageInterpolator() in Example 4.3, “Contextual container possible MessageInterpolator implementation”).

Clients call Configuration.buildValidatorFactory() to retrieve the initialized ValidatorFactory instance.

Example 4.12. Configuration interface

/**
 * Receives configuration information, selects the appropriate
 * Bean Validation provider and build the appropriate
 * ValidatorFactory.
 * <p/>
 * Usage:
 * <pre>
 * Configuration<?> configuration = //provided by one of the Validation bootstrap methods
 *     ValidatorFactory = configuration
 *         .messageInterpolator( new CustomMessageInterpolator() )
 *         .buildValidatorFactory();
 * </pre>
 * <p/>
 *
 * By default, the configuration information is retrieved from
 * META-INF/validation.xml
 * It is possible to override the configuration retrieved from the XML file
 * by using one or more of the Configuration methods.
 *
 * The ValidationProviderResolver is specified at Configuration time
 * (see {@link javax.validation.spi.ValidationProvider}).
 * If none is explicitely requested, the default ValidationProviderResolver is used.
 * <p/>
 * The provider is selected in the following way:
 * - if a specific Configuration subclass is requested programmatically using
 * Validation.byProvider(Class), find the first provider matching it
 * - if a specific Configuration subclass is defined in META-INF/validation.xml,
 * find the first provider matching it
 * - otherwise, use the first provider returned by the ValidationProviderResolver
 * <p/>
 * Implementations are not meant to be thread-safe
 *
 * @author Emmanuel Bernard
 */
public interface Configuration<T extends Configuration<T>> {

    /**
     * Ignore data from the META-INF/validation.xml file if this
     * method is called.
     * This method is typically useful for containers that parse
     * META-INF/validation.xml themselves and pass the information
     * via the Configuration methods.
     */
    T ignoreXmlConfiguration();
    /**
     * Defines the message interpolator used. Has priority over the configuration
     * based message interpolator.
     *
     * @param interpolator message interpolator implementation.
     *
     * @return <code>this</code> following the chaining method pattern.
     */
    T messageInterpolator(MessageInterpolator interpolator);

    /**
     * Defines the traversable resolver used. Has priority over the configuration
     * based traversable resolver.
     *
     * @param resolver traversable resolver implementation.
     *
     * @return <code>this</code> following the chaining method pattern.
     */
    T traversableResolver(TraversableResolver resolver);

    /**
     * Defines the constraint validator factory. Has priority over the configuration
     * based constraint factory.
     *
     * @param constraintValidatorFactory constraint factory inmplementation.
     *
     * @return <code>this</code> following the chaining method pattern.
     */
    T constraintValidatorFactory(ConstraintValidatorFactory constraintValidatorFactory);

    /**
     * Add a stream describing constaint mapping in the Bean Validation
     * XML format.
     * <p/>
     * The stream should be closed by the client API after the
     * ValidatorFactory has been built. The Bean Validation provider
     * must not close the stream.
     *
     * @param stream XML mapping stream.
     *
     * @return <code>this</code> following the chaining method pattern.
     */
    T addMapping(InputStream stream);

    /**
     * Add a provider specific property. This property is equivalent to
     * XML Configuration properties.
     * If the underlying provider does not know how to handle the property,
     * it must silently ignore it.
     *
     * Note: Using this non type-safe method is generally not recommended.
     *
     * It is more appropriate to use, if available, the type-safe equivalent provided
     * by a specific provider in its Configuration subclass.
     * <code>ValidatorFactory factory = Validation.byProvider(ACMEConfiguration.class)
     *        .configure()
     *           .providerSpecificProperty(ACMEState.FAST)
     *           .buildValidatorFactory();
     * </code>
     * This method is typically used by containers parsing META-INF/validation.xml
     * themselves and injecting the state to the Configuration object.
     *
     * If a property with a given name is defined both via this method and in the
     * XML configuration, the value set programmatically has priority.
     */
    T addProperty(String name, String value);

    /**
     * Return an implementation of the MessageInterpolator interface following the
     * default MessageInterpolator defined in the specification:
     *  - use the ValidationMessages resource bundle to load keys
     *  - use Locale.getDefault()
     *
     * @return default MessageInterpolator implementation compliant with the specification
     */
    MessageInterpolator getDefaultMessageInterpolator();

    /**
     * Build a ValidatorFactory implementation.
     *
     * @return ValidatorFactory
     */
    ValidatorFactory buildValidatorFactory();
}

A Bean Validation provider must define a sub interface of Configuration uniquely identifying the provider. The isSuitable() method of its ValidationProvider implementation must return true when this sub interface type is passed as a parameter, false otherwise. The Configuration sub interface typically hosts provider specific configuration methods.

To facilitate the use of provider specific configuration methods, Configuration uses generics: Configuration<T extends Configuration<T>> ; the generic return type T is returned by chaining methods. The provider specific sub interface must resolve the generic T as itself as shown in the following example.

Example 4.13. Example of provider specific Configuration sub interface

/**
 * Unique identifier of the ACME provider
 * also host some provider specific configuration methods
 */
public interface ACMEConfiguration 
    extends Configuration<ACMEonfiguration> {

    /**
     * Enables contraints implementation dynamic reloading when using ACME
     * default to false
     */
    Configuration enableDynamicReloading(boolean);

}

When Configuration.buildValidatorFactory() is called, the initialized ValidatorFactory is returned. More specifically, the requested Bean Validation provider is determined and the result of validationProvider.buildValidatorFactory(ConfigurationState) is returned. ConfigurationState gives access to the configuration artifacts defined in META-INF/validation.xml (unless XML configuration is ignored) and provided programmatically to Configuration. Generally speaking, programmatically defined elements have priority over XML defined configuration elements (read the Configuration JavaDoc and see Section 4.4.6, “XML Configuration: META-INF/validation.xml” for more information). A typical implementation ofConfiguration also implements ConfigurationState, hence this can be passed to buildValidatorFactory(ConfigurationState).

Streams represented in the XML configuration and opened by the Configuration implementation must be closed by the Configuration implementation after the ValidatorFactorycreation (or if an exception occurs). Streams provided programmatically are the responsibility of the application.

Example 4.14. ConfigurationState interface

/**
 * Contract between a <code>Configuration</code> and a
 * </code>ValidatorProvider</code> to create a <code>ValidatorFactory</code>.
 * The configuration artifacts defined in the XML configuration and provided to the
 * <code>Configuration</code> are merged and passed along via ConfigurationState.
 *
 * @author Emmanuel Bernard
 * @author Hardy Ferentschik
 */
public interface ConfigurationState {

    /**
     * returns true if Configuration.ignoreXMLConfiguration() has been called
     * In this case, the ValiatorFactory must ignore META-INF/validation.xml
     * @return true if META-INF/validation.xml should be ignored
     */
    boolean isIgnoreXmlConfiguration();

    /**
     * Message interpolator as defined in the following decresing priority:
     *  - set via the Configuration programmatic API
     *  - defined in META-INF/validation.xml provided that ignoredXmlConfiguration
     * is false. In this case the instance is created via its no-arg constructor.
     *  - null if undefined.
     *
     * @return message provider instance or null if not defined
     */
    MessageInterpolator getMessageInterpolator();

    /**
     * Returns a set of stream corresponding to:
     *  - mapping XML streams passed programmatically in Configuration
     *  - mapping XML stream located in the resources defined in
     * META-INF/validation.xml (constraint-mapping element)
     *
     * Streams represented in the XML configuration and opened by the 
     * configuration implementation must be closed by the configuration
     * implementation after the ValidatorFactory creation (or if an exception
     * occurs).
     *
     * @return set of input stream
     */
    Set<InputStream> getMappingStreams();

    /**
     * ConstraintValidatorFactory implementation as defined in the following
     * decreasing priority:
     *  - set via the Configuration programmatic API
     *  - defined in META-INF/validation.xml provided that ignoredXmlConfiguration
     * is false. In this case the instance is created via its no-arg constructor.
     *  - null if undefined.
     *
     * @return factory instance or null if not defined
     */
    ConstraintValidatorFactory getConstraintValidatorFactory();

    /**
     * TraversableResolver as defined in the following decresing priority:
     *  - set via the Configuration programmatic API
     *  - defined in META-INF/validation.xml provided that ignoredXmlConfiguration
     * is false. In this case the instance is created via its no-arg constructor.
     *  - null if undefined.
     *
     * @return traversable provider instance or null if not defined
     */
    TraversableResolver getTraversableResolver();

    /**
     * return  non type-safe properties defined via:
     *  - Configuration.addProperty(String, String)
     *  - META-INF/validation.xml provided that ignoredXmlConfiguration
     * is false.
     *
     * If a property is defined both programmatically and in XML,
     * the value defined programmatically has priority 
     *
     * @return Map whose key is the property key and the value the property value
     */
    Map<String, String> getProperties();
}

The requested provider implementation is resolved according to the following rules in the following order:

  • Use the provider implementation requested if Configuration has been created from Validation.byProvider(Class).

  • Use the provider implementation associated with the Configuration implementation described in the XML configuration (under validation.provider) if defined: the value of this element is the fully qualified class name of the Configuration sub interface uniquely identifying the provider.

  • Use the first provider implementation returned by validationProviderResolver.getValidationProviders().

The ValidationProviderResolver is specified when Configuration instances are created (see ValidationProvider). If no ValidationProviderResolver instance has been specified, the default ValidationProviderResolver is used.

Configuration instances are provided to the Bean Validation client through the Validation methods. Configuration instances are created by ValidationProvider.

Here is an example of Configuration use.

Example 4.15. Use Configuration

Configuration configuration = ...
ValidatorFactory factory = configuration
              .messageInterpolator( new WBMessageInterpolator() )
              .traversableResolver( new JPAAwareTraversableResolver() )
              .buildValidatorFactory();