<?xml version="1.0" encoding="UTF-8"?>
<!--
	~ JBoss, Home of Professional Open Source
	~ Copyright 2009, Red Hat, Inc. and/or its affiliates, and individual contributors
	~ by the @authors tag. See the copyright.txt in the distribution for a
	~ full listing of individual contributors.
	~
	~ Licensed under the Apache License, Version 2.0 (the "License");
	~ you may not use this file except in compliance with the License.
	~ You may obtain a copy of the License at
	~ http://www.apache.org/licenses/LICENSE-2.0
	~ Unless required by applicable law or agreed to in writing, software
	~ distributed under the License is distributed on an "AS IS" BASIS,
	~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
	~ See the License for the specific language governing permissions and
	~ limitations under the License.
-->
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!ENTITY % BOOK_ENTITIES SYSTEM "../hv.ent">
%BOOK_ENTITIES;
]>
<chapter id="validator-metadata-api">
  <title>Using constraint metadata</title>

  <para>The 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
  <package>javax.validation.metadata</package>.</para>

  <para>The examples presented in this chapter are based on the classes and
  constraint declarations shown in <xref
  linkend="metadata-example-car"/>.</para>

  <example id="metadata-example-car">
    <title>Example classes</title>

    <programlisting language="JAVA" role="JAVA">package org.hibernate.validator.referenceguide.chapter07;

public class Person {

	public interface Basic {
	}

	@NotNull
	private String name;

	//getters and setters ...
}</programlisting>

    <programlisting language="JAVA" role="JAVA">public interface Vehicle {

	public interface Basic {
	}

	@NotNull(groups = Vehicle.Basic.class)
	String getManufacturer();
}</programlisting>

    <programlisting language="JAVA" role="JAVA">@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&lt;Person&gt; passengers, List&lt;PieceOfLuggage&gt; 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...
}</programlisting>
  </example>

  <section>
    <title><classname
    id="section-bean-descriptor">BeanDescriptor</classname></title>

    <para>The entry point into the metadata API is the method
    <code>Validator#getConstraintsForClass()</code>, which returns an instance
    of the <ulink
    url="http://docs.jboss.org/hibernate/beanvalidation/spec/1.1/api/index.html?javax/validation/metadata/BeanDescriptor.html"><classname>BeanDescriptor</classname></ulink>
    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.</para>

    <para><xref linkend="metadata-example-using-beandescriptor"/> demonstrates
    how to retrieve a <classname>BeanDescriptor</classname> for the
    <classname>Car</classname> class and how to use this descriptor in form of
    assertions.</para>

    <para><tip>
        <para>If a constraint declaration hosted by the requested class is
        invalid, a <classname>ValidationException</classname> is
        thrown.</para>
      </tip></para>

    <example id="metadata-example-using-beandescriptor">
      <title>Using <classname>BeanDescriptor</classname></title>

      <programlisting language="JAVA" role="JAVA">Validator validator = Validation.buildDefaultValidatorFactory().getValidator();

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&lt;Person&gt;, List&lt;PieceOfLuggage&gt;)
assertEquals( 2, carDescriptor.getConstrainedMethods( MethodType.NON_GETTER ).size() );

//driveAway(int), getManufacturer(), getDriver(), load(List&lt;Person&gt;, List&lt;PieceOfLuggage&gt;)
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
		)
);</programlisting>
    </example>

    <para>You can determine whether the specified class hosts any class- or
    property-level constraints via <code>isBeanConstrained()</code>. Method or
    constructor constraints are not considered by
    <methodname>isBeanConstrained()</methodname>.</para>

    <para>The method <code>getConstraintDescriptors()</code> is common to all
    descriptors derived from <classname>ElementDescriptor</classname> (see
    <xref linkend="validator-metadata-api-elementdescriptor"/>) and returns a
    set of descriptors representing the constraints directly declared on the
    given element. In case of <classname>BeanDescriptor</classname>, the
    bean's class-level constraints are returned. More details on
    <classname>ConstraintDescriptor</classname> can be found in <xref
    linkend="section-constraint-descriptor"/>.</para>

    <para>Via <methodname>getConstraintsForProperty()</methodname>,
    <methodname>getConstraintsForMethod()</methodname> and
    <methodname>getConstraintsForConstructor()</methodname> 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.</para>

    <para>Note that these methods consider constraints declared at super-types
    according to the rules for constraint inheritance as described in <xref
    linkend="section-constraint-inheritance"/>. An example is the descriptor
    for the <varname>manufacturer</varname> property, which provides access to
    all constraints defined on
    <methodname>Vehicle#getManufacturer()</methodname> and the implementing
    method <methodname>Car#getManufacturer()</methodname>.
    <literal>null</literal> is returned in case the specified element does not
    exist or is not constrained.</para>

    <para>The methods <methodname>getConstrainedProperties()</methodname>,
    <methodname>getConstrainedMethods()</methodname> and
    <methodname>getConstrainedConstructors()</methodname> 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
    <methodname>getConstrainedMethods()</methodname>, you can specify the type
    of the methods to be returned (getters, non-getters or both).</para>
  </section>

  <section id="section-property-descriptor">
    <title><classname>PropertyDescriptor</classname></title>

    <para>The interface <ulink
    url="http://docs.jboss.org/hibernate/beanvalidation/spec/1.1/api/index.html?javax/validation/metadata/PropertyDescriptor.html"><classname>PropertyDescriptor</classname></ulink>
    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. <xref
    linkend="metadata-example-using-propertydescriptor"/> shows how to use the
    <classname>PropertyDescriptor</classname> interface.</para>

    <example id="metadata-example-using-propertydescriptor">
      <title>Using <classname>PropertyDescriptor</classname></title>

      <programlisting language="JAVA" role="JAVA">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() );</programlisting>
    </example>

    <para>Using <methodname>getConstrainedDescriptors()</methodname>, you can
    retrieve a set of <classname>ConstraintDescriptor</classname>s providing
    more information on the individual constraints of a given property. The
    method <methodname>isCascaded()</methodname> returns
    <literal>true</literal>, if the property is marked for cascaded validation
    (either using the <classname>@Valid</classname> annotation or via XML),
    <literal>false</literal> otherwise. Any configured group conversions are
    returned by <methodname>getGroupConversions()</methodname>. See <xref
    linkend="section-group-conversion-descriptor"/> for more details on
    <classname>GroupConversionDescriptor</classname>.</para>
  </section>

  <section>
    <title><classname>MethodDescriptor</classname> and
    <classname>ConstructorDescriptor</classname></title>

    <para>Constrained methods and constructors are represented by the
    interfaces <ulink
    url="http://docs.jboss.org/hibernate/beanvalidation/spec/1.1/api/index.html?javax/validation/metadata/MethodDescriptor.html"><classname>MethodDescriptor</classname></ulink>
    and <ulink
    url="http://docs.jboss.org/hibernate/beanvalidation/spec/1.1/api/index.html?javax/validation/metadata/ConstructorDescriptor.html"><classname>ConstructorDescriptor</classname></ulink>,
    respectively. <xref
    linkend="metadata-example-using-methodandconstructordescriptor"/>
    demonstrates how to work with these descriptors.</para>

    <example id="metadata-example-using-methodandconstructordescriptor">
      <title>Using <classname>MethodDescriptor</classname> and
      <classname>ConstructorDescriptor</classname></title>

      <programlisting language="JAVA" role="JAVA">//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( "arg0", 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&lt;Person&gt;, List&lt;PieceOfLuggage&gt;) 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()
);</programlisting>
    </example>

    <para><methodname>getName()</methodname> returns the name of the given
    method or constructor. The methods
    <methodname>hasConstrainedParameters()</methodname> and
    <methodname>hasConstrainedReturnValue()</methodname> 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.</para>

    <para>Note that any constraints are not directly exposed on
    <classname>MethodDescriptor</classname> and
    <classname>ConstructorDescriptor</classname>, 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 <methodname>getParameterDescriptors()</methodname>,
    <methodname>getReturnValueDescriptor()</methodname> or
    <methodname>getCrossParameterDescriptor()</methodname>,
    respectively.</para>

    <para>These descriptors provide access to the element's constraints
    (<methodname>getConstraintDescriptors()</methodname>) and, in case of
    parameters and return value, to its configuration for cascaded validation
    (<methodname>isValid()</methodname> and
    <methodname>getGroupConversions()</methodname>). For parameters, you also
    can retrieve the index and the name, as returned by the currently used
    parameter name provider (see <xref
    linkend="section-parameter-name-provider"/>) via
    <methodname>getName()</methodname> and
    <methodname>getIndex()</methodname>.</para>

    <tip>
      <para>Getter methods following the JavaBeans naming conventions are
      considered as bean properties but also as constrained methods.</para>

      <para>That means you can retrieve the related metadata either by
      obtaining a <classname>PropertyDescriptor</classname> (e.g.
      <code>BeanDescriptor.getConstraintsForProperty("foo")</code>) or by
      examining the return value descriptor of the getter's
      <classname>MethodDescriptor</classname> (e.g.
      <code>BeanDescriptor.getConstraintsForMethod("getFoo").getReturnValueDescriptor()</code>).</para>
    </tip>
  </section>

  <section id="validator-metadata-api-elementdescriptor">
    <title><classname>ElementDescriptor</classname></title>

    <para>The <ulink
    url="http://docs.jboss.org/hibernate/beanvalidation/spec/1.1/api/index.html?javax/validation/metadata/ElementDescriptor.html"><classname>ElementDiscriptor</classname></ulink>
    interface is the common base class for the individual descriptor types
    such as <classname>BeanDescriptor</classname>,
    <classname>PropertyDescriptor</classname> etc. Besides
    <methodname>getConstraintDescriptors()</methodname> it provides some more
    methods common to all descriptors.</para>

    <para><code>hasConstraints()</code> allows for a quick check whether an
    element has any direct constraints (e.g. class-level constraints in case
    of <classname>BeanDescriptor</classname>).
    <methodname>getElementClass()</methodname> returns the Java type of the
    element represented by a given descriptor. More specifically, the method
    returns</para>

    <itemizedlist>
      <listitem>
        <para>the object type when invoked on
        <classname>BeanDescriptor</classname>,</para>
      </listitem>

      <listitem>
        <para>the type of a property or parameter when invoked on
        <classname>PropertyDescriptor</classname> or
        <classname>ParameterDescriptor</classname> respectively,</para>
      </listitem>

      <listitem>
        <para><classname>Object[].class</classname> when invoked on
        <classname>CrossParameterDescriptor</classname>,</para>
      </listitem>

      <listitem>
        <para>the return type when invoked on
        <classname>ConstructorDescriptor</classname>,
        <classname>MethodDescriptor</classname> or
        <classname>ReturnValueDescriptor</classname>.
        <classname>void.class</classname> will be returned for methods which
        don't have a return value.</para>
      </listitem>
    </itemizedlist>

    <para><xref linkend="metadata-example-using-elementdescriptor"/> shows how
    these methods are used.</para>

    <example id="metadata-example-using-elementdescriptor">
      <title>Using <classname>ElementDescriptor</classname> methods</title>

      <programlisting language="JAVA" role="JAVA">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() );</programlisting>
    </example>

    <para>Finally, <classname>ElementDescriptor</classname> offers access to
    the <classname>ConstraintFinder</classname> API which allows you to query
    for constraint metadata in a fine grained way. <xref
    linkend="example-constraint-finder"/> shows how to retrieve a
    <classname>ConstraintFinder</classname> instance via
    <methodname>findConstraints()</methodname> and use the API to query for
    constraint metadata.</para>

    <example id="example-constraint-finder">
      <title>Usage of ConstraintFinder</title>

      <programlisting language="JAVA" role="JAVA">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()
);</programlisting>
    </example>

    <para>Via <methodname>declaredOn()</methodname> you can search for
    <classname>ConstraintDescriptor</classname>s declared on certain element
    types. This is useful to find property constraints declared on either
    fields or getter methods.</para>

    <para><methodname>unorderedAndMatchingGroups()</methodname> restricts the
    resulting constraints to those matching the given validation
    group(s).</para>

    <para><methodname>lookingAt()</methodname> allows to distinguish between
    constraints directly specified on the element
    (<constant>Scope.LOCAL_ELEMENT</constant>) or constraints belonging to the
    element but hosted anywhere in the class hierarchy
    (<constant>Scope.HIERARCHY</constant>).</para>

    <para>You can also combine the different options as shown in the last
    example.</para>

    <para><warning>
        <para>Order is not respected by
        <methodname>unorderedAndMatchingGroups()</methodname>, but group
        inheritance and inheritance via sequence are.</para>
      </warning></para>
  </section>

  <section id="section-group-conversion-descriptor">
    <title><classname>GroupConversionDescriptor</classname></title>

    <para>All those descriptor types that represent elements which can be
    subject of cascaded validation (i.e.,
    <classname>PropertyDescriptor</classname>,
    <classname>ParameterDescriptor</classname> and
    <classname>ReturnValueDescriptor</classname>) provide access to the
    element's group conversions via
    <methodname>getGroupConversions()</methodname>. The returned set contains
    a <ulink
    url="http://docs.jboss.org/hibernate/beanvalidation/spec/1.1/api/index.html?javax/validation/metadata/GroupConversionDescriptor.html"><classname>GroupConversionDescriptor</classname></ulink>
    for each configured conversion, allowing to retrieve source and target
    groups of the conversion. <xref
    linkend="metadata-example-using-groupconversiondescriptor"/> shows an
    example.</para>

    <example id="metadata-example-using-groupconversiondescriptor">
      <title>Using <classname>GroupConversionDescriptor</classname></title>

      <programlisting language="JAVA" role="JAVA">PropertyDescriptor driverDescriptor = carDescriptor.getConstraintsForProperty( "driver" );

Set&lt;GroupConversionDescriptor&gt; groupConversions = driverDescriptor.getGroupConversions();
assertEquals( 1, groupConversions.size() );

GroupConversionDescriptor groupConversionDescriptor = groupConversions.iterator()
		.next();
assertEquals( Default.class, groupConversionDescriptor.getFrom() );
assertEquals( Person.Basic.class, groupConversionDescriptor.getTo() );</programlisting>
    </example>
  </section>

  <section id="section-constraint-descriptor">
    <title><classname>ConstraintDescriptor</classname></title>

    <para>Last but not least, the <ulink
    url="http://docs.jboss.org/hibernate/beanvalidation/spec/1.1/api/index.html?javax/validation/metadata/ConstraintDescriptor.html"><classname>ConstraintDescriptor</classname></ulink>
    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.</para>

    <para><xref linkend="metadata-example-using-constraintdescriptor"/> shows
    how to retrieve default constraint attributes (such as message template,
    groups etc.) as well as custom constraint attributes
    (<varname>piecesOfLuggagePerPassenger</varname>) and other metadata such
    as the constraint's annotation type and its validators from a
    <classname>ConstraintDescriptor</classname>.</para>

    <example id="metadata-example-using-constraintdescriptor">
      <title>Using <classname>ConstraintDescriptor</classname></title>

      <programlisting language="JAVA" role="JAVA">//descriptor for the @LuggageCountMatchesPassengerCount constraint on the
//load(List&lt;Person&gt;, List&lt;PieceOfLuggage&gt;) method
ConstraintDescriptor&lt;?&gt; 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.&lt;Class&lt;?&gt;&gt;asList( LuggageCountMatchesPassengerCount.Validator.class ),
		constraintDescriptor.getConstraintValidatorClasses()
);</programlisting>
    </example>
  </section>
</chapter>
