Skip to content

Metadata

Jin Kwon edited this page Nov 13, 2026 · 1 revision

Metadata

The Jakarta Validation metadata API describes what is constrained, without validating anything. Its root is Validator.getConstraintsForClass(Class), a BeanDescriptor. Every descriptor type has an entry point and an assertion, and the assertions navigate from one descriptor to the next.

Descriptor Entry point Assertion
BeanDescriptor assertThatBeanDescriptor AbstractBeanDescriptorAssert<?>
PropertyDescriptor assertThatPropertyDescriptor AbstractPropertyDescriptorAssert<?>
MethodDescriptor assertThatMethodDescriptor AbstractMethodDescriptorAssert<?>
ConstructorDescriptor assertThatConstructorDescriptor AbstractConstructorDescriptorAssert<?>
ParameterDescriptor assertThatParameterDescriptor AbstractParameterDescriptorAssert<?>
ReturnValueDescriptor assertThatReturnValueDescriptor AbstractReturnValueDescriptorAssert<?>
CrossParameterDescriptor assertThatCrossParameterDescriptor AbstractCrossParameterDescriptorAssert<?>
ContainerElementTypeDescriptor assertThatContainerElementTypeDescriptor AbstractContainerElementTypeDescriptorAssert<?>
GroupConversionDescriptor assertThatGroupConversionDescriptor AbstractGroupConversionDescriptorAssert<?>
ConstraintDescriptor<T> assertThatConstraintDescriptor AbstractConstraintDescriptorAssert<?, ?, T>

The hierarchy

The assertion classes follow the descriptor interfaces:

AbstractElementDescriptorAssert                    hasConstraints, elementClass, constraintDescriptors
├── AbstractBeanDescriptorAssert
├── AbstractExecutableDescriptorAssert             name, parameters, cross parameter, return value
│   ├── AbstractMethodDescriptorAssert
│   └── AbstractConstructorDescriptorAssert
├── AbstractCrossParameterDescriptorAssert
└── AbstractCascadableContainerDescriptorAssert    cascaded, group conversions, container element types
    ├── AbstractPropertyDescriptorAssert
    ├── AbstractParameterDescriptorAssert
    ├── AbstractReturnValueDescriptorAssert
    └── AbstractContainerElementTypeDescriptorAssert

AbstractGroupConversionDescriptorAssert            (not an ElementDescriptor)
AbstractConstraintDescriptorAssert                 (not an ElementDescriptor)

ElementDescriptor, CascadableDescriptor and ContainerDescriptor always occur together on property, parameter, return-value and container-element-type descriptors, so one intersection-bounded class covers them.

Common to every element descriptor

Method
hasConstraints(), doesNotHaveConstraints(), extractingHasConstraints() ElementDescriptor.hasConstraints()
hasElementClass(Class), extractingElementClass() getElementClass()
extractingConstraintDescriptors() getConstraintDescriptors(), as a CollectionAssert<ConstraintDescriptor<?>>
extractingConstraintDescriptors(UnaryOperator<ConstraintFinder>) findConstraints(), configured by the operator, then getConstraintDescriptors()

Bean

Method
isBeanConstrained(), isNotBeanConstrained(), extractingBeanConstrained() isBeanConstrained()
extractingConstraintsForProperty(String) a property-descriptor assertion; its actual is null when the property is neither constrained nor cascaded
hasConstraintsForProperty(String) the above is not null
extractingConstrainedProperties() CollectionAssert<PropertyDescriptor>
extractingConstraintsForMethod(String name, Class<?>... parameterTypes) a method-descriptor assertion; actual is null when the method is unconstrained
extractingConstrainedMethods(MethodType, MethodType...) CollectionAssert<MethodDescriptor>
extractingConstraintsForConstructor(Class<?>... parameterTypes) a constructor-descriptor assertion
extractingConstrainedConstructors() CollectionAssert<ConstructorDescriptor>

The extractingConstraintsFor… methods also have overloads taking an AssertFactory — first for the method and constructor forms, after the name for the property form.

assertThatBeanDescriptor(validator.getConstraintsForClass(Greeter.class))
        .isBeanConstrained()
        .hasElementClass(Greeter.class)
        .hasConstraintsForProperty("name")
        .extractingConstraintsForProperty("name")
        .hasPropertyName("name")
        .hasConstraints()
        .isNotCascaded();

assertThatBeanDescriptor(validator.getConstraintsForClass(Greeter.class))
        .extractingConstraintsForProperty("nosuch")
        .isNull();

Methods and constructors

AbstractExecutableDescriptorAssert, shared by the method and constructor descriptor assertions:

Method
hasName(String), extractingName() getName()
extractingParameterDescriptors() ListAssert<ParameterDescriptor>
extractingParameterDescriptor(int), extractingParameterDescriptor(int, AssertFactory) the parameter at an index; see the index contract below
hasConstrainedParameters(), doesNotHaveConstrainedParameters(), extractingHasConstrainedParameters()
hasConstrainedReturnValue(), doesNotHaveConstrainedReturnValue(), extractingHasConstrainedReturnValue()
extractingCrossParameterDescriptor(), extractingCrossParameterDescriptor(AssertFactory)
extractingReturnValueDescriptor(), extractingReturnValueDescriptor(AssertFactory)

The method and constructor descriptor assertions add nothing of their own; neither do the return-value and cross-parameter ones beyond their base classes.

final var greet = assertThatBeanDescriptor(validator.getConstraintsForClass(Greeter.class))
        .extractingConstraintsForMethod("greet", String.class, int.class);

greet.hasName("greet").hasConstrainedParameters().hasConstrainedReturnValue();

greet.extractingParameterDescriptor(0)
        .hasIndex(0)
        .hasElementClass(String.class)
        .hasConstraints();

greet.extractingReturnValueDescriptor()
        .hasConstraints()
        .hasElementClass(String.class);

greet.extractingCrossParameterDescriptor()
        .doesNotHaveConstraints();

assertThatBeanDescriptor(validator.getConstraintsForClass(Greeter.class))
        .extractingConstraintsForConstructor(String.class)
        .hasConstrainedParameters()
        .hasConstrainedReturnValue();

Index contract. extractingParameterDescriptor(int) throws IllegalArgumentException for a negative index, and fails as an AssertionError — Expecting a parameter at index 2 of <greet> but it has 2 parameter(s) — for an index the executable does not have. The failure goes through the assertion, so a description set with as(…) is kept.

Parameters

Method
hasIndex(int), extractingIndex() ParameterDescriptor.getIndex()
hasName(String), extractingName() getName()

plus the cascadable/container methods below.

Cascading, group conversion, container elements

AbstractCascadableContainerDescriptorAssert, for property, parameter, return-value and container-element-type descriptors:

Method
isCascaded(), isNotCascaded(), extractingCascaded() CascadableDescriptor.isCascaded()
extractingGroupConversions(), doesNotHaveAnyGroupConversion() getGroupConversions()
extractingConstrainedContainerElementTypes(), doesNotHaveAnyConstrainedContainerElementType() ContainerDescriptor.getConstrainedContainerElementTypes()

The property-descriptor assertion adds hasPropertyName(String) / extractingPropertyName().

Container element type

Method
hasContainerClass(Class), extractingContainerClass() getContainerClass()
hasTypeArgumentIndex(Integer), extractingTypeArgumentIndex() getTypeArgumentIndex()
// public final List<@NotBlank String> tags
assertThatBeanDescriptor(validator.getConstraintsForClass(Bagged.class))
        .extractingConstraintsForProperty("tags")
        .extractingConstrainedContainerElementTypes()
        .singleElement(CONTAINER_ELEMENT_TYPE_DESCRIPTOR)
        .hasContainerClass(List.class)
        .hasTypeArgumentIndex(0)
        .hasElementClass(String.class)
        .hasConstraints()
        .isNotCascaded();

Group conversion

Method
convertsGroup(Class from, Class to) both ends at once
extractingFrom(), extractingTo() getFrom(), getTo()
public static class Parent {
    @Valid
    @ConvertGroup(from = Default.class, to = Detailed.class)
    public Child child;
}

assertThatBeanDescriptor(validator.getConstraintsForClass(Parent.class))
        .extractingConstraintsForProperty("child")
        .isCascaded()
        .extractingGroupConversions()
        .singleElement(GROUP_CONVERSION_DESCRIPTOR)
        .convertsGroup(Default.class, Detailed.class);

The collection-valued extractions return plain AssertJ CollectionAsserts; singleElement(…), first(…) or element(int, …) with a factory from InstanceOf Factories continues with a typed assertion.

Constraint descriptors

assertThatConstraintDescriptor(ConstraintDescriptor<T>), also reached from a violation with extractingConstraintDescriptor():

Method
extractingAnnotation(), extractingAnnotation(Function, AssertFactory) getAnnotation()
extractingAttributes(), hasAttribute(String, Object) getAttributes(), as a MapAssert<String, Object>
extractingComposingConstraints(), doesNotHaveComposingConstraints() getComposingConstraints()
extractingConstraintValidatorClasses(), hasConstraintValidatorClass(Class) getConstraintValidatorClasses()
extractingGroups() getGroups()
extractingMessageTemplate(), hasMessageTemplate(String) getMessageTemplate()
extractingPayload(), hasPayload(Class), doesNotHaveAnyPayload() getPayload()
hostsConstraintTarget(ConstraintTarget), doesNotHostAnyConstraintTarget() getValidationAppliesTo()
extractingValueUnwrapping(), hasValueUnwrapping(ValidateUnwrappedValue) getValueUnwrapping()
isReportedAsSingleViolation(), isNotReportedAsSingleViolation(), extractingReportAsSingleViolation() isReportAsSingleViolation()
extractingAsUnwrapped(Class, AssertFactory), isEqualToWhenUnwrappedAs(Class, Object) unwrap(Class)
assertThatConstraintViolation(violation)
        .extractingConstraintDescriptor()
        .extractingAnnotation()
        .isInstanceOf(NotBlank.class);

Clone this wiki locally