Hibernate Validator is the reference implementation of Jakarta Validation 3.1 providing annotation-based validation for JavaBeans and method parameters
Define constraints programmatically without annotations using a fluent API. This approach supports all constraint types including properties, methods, constructors, parameters, return values, cross-parameter constraints, and container elements with full feature parity to annotation-based configuration.
Create and configure constraint mappings to define validation rules programmatically.
package org.hibernate.validator.cfg;
import java.lang.annotation.Annotation;
import org.hibernate.validator.cfg.context.ConstraintDefinitionContext;
import org.hibernate.validator.cfg.context.TypeConstraintMappingContext;
/**
* Represents a constraint mapping configured via programmatic API.
* Create via BaseHibernateValidatorConfiguration.createConstraintMapping().
*/
interface ConstraintMapping {
/**
* Start defining constraints on specified bean class.
* Each bean class may only be configured once within all constraint mappings.
*
* @param <C> type to be configured
* @param beanClass bean class on which to define constraints
* @return context for defining constraints on the class
*/
<C> TypeConstraintMappingContext<C> type(Class<C> beanClass);
/**
* Start defining ConstraintValidators for specified constraint annotation.
* Each constraint may only be configured once within all constraint mappings.
*
* @param <A> annotation type to be configured
* @param annotationClass constraint annotation class
* @return context for defining validators for the constraint
* @since 5.3
*/
<A extends Annotation> ConstraintDefinitionContext<A> constraintDefinition(Class<A> annotationClass);
}Usage Example:
import jakarta.validation.Validation;
import org.hibernate.validator.HibernateValidator;
import org.hibernate.validator.HibernateValidatorConfiguration;
import org.hibernate.validator.cfg.ConstraintMapping;
HibernateValidatorConfiguration configuration = Validation
.byProvider(HibernateValidator.class)
.configure();
// Create constraint mapping
ConstraintMapping mapping = configuration.createConstraintMapping();
// Configure constraints (see examples below)
// Add mapping to configuration
configuration.addMapping(mapping);
ValidatorFactory factory = configuration.buildValidatorFactory();Configure constraints at the class level including class-level constraints, property constraints, method constraints, and constructor constraints.
package org.hibernate.validator.cfg.context;
import org.hibernate.validator.cfg.ConstraintDef;
/**
* Context for defining constraints at type level.
*
* @param <C> configured bean type
*/
interface TypeConstraintMappingContext<C> extends Constrainable<TypeConstraintMappingContext<C>>,
Cascadable<TypeConstraintMappingContext<C>>,
AnnotationIgnoreOptions<TypeConstraintMappingContext<C>>,
PropertyTarget {
/**
* Start defining constraints on a method.
*
* @param methodName method name
* @param parameterTypes method parameter types
* @return context for defining method constraints
*/
MethodConstraintMappingContext method(String methodName, Class<?>... parameterTypes);
/**
* Start defining constraints on a constructor.
*
* @param parameterTypes constructor parameter types
* @return context for defining constructor constraints
*/
ConstructorConstraintMappingContext constructor(Class<?>... parameterTypes);
}
/**
* Provides methods for configuring property-level constraints.
*/
interface PropertyTarget {
/**
* Start defining constraints on a property via field access.
*
* @param property property name
* @return context for defining property constraints
*/
PropertyConstraintMappingContext field(String property);
/**
* Start defining constraints on a property via getter method access.
*
* @param property property name
* @return context for defining property constraints
*/
PropertyConstraintMappingContext getter(String property);
}Important Note: The PropertyTarget interface provides two distinct methods for property constraint configuration:
field(String property) to apply constraints at the field levelgetter(String property) to apply constraints at the getter method levelThere is no single property() method. The term "property" in method parameters refers to the JavaBean property name, while the method itself (field or getter) specifies how to access it.
Usage Example:
import org.hibernate.validator.cfg.ConstraintMapping;
import org.hibernate.validator.cfg.defs.*;
ConstraintMapping mapping = configuration.createConstraintMapping();
// Configure type-level constraints
mapping.type(User.class)
// Add class-level constraint
.constraint(new ScriptAssertDef()
.lang("javascript")
.script("_this.password == _this.confirmPassword")
.message("Passwords must match"))
// Mark type for cascaded validation
.valid()
// Configure property constraints via field access
.field("email")
.constraint(new NotNullDef())
.constraint(new EmailDef())
.field("age")
.constraint(new MinDef().value(18))
.constraint(new MaxDef().value(120));Configure constraints on bean properties (fields or getter methods).
package org.hibernate.validator.cfg.context;
/**
* Context for defining constraints on properties.
*/
interface PropertyConstraintMappingContext extends Constrainable<PropertyConstraintMappingContext>,
Cascadable<PropertyConstraintMappingContext>,
ContainerElementTarget,
AnnotationIgnoreOptions<PropertyConstraintMappingContext>,
PropertyTarget {
/**
* Move to method configuration.
*
* @param methodName method name
* @param parameterTypes parameter types
* @return method-level context
*/
MethodConstraintMappingContext method(String methodName, Class<?>... parameterTypes);
/**
* Move to constructor configuration.
*
* @param parameterTypes parameter types
* @return constructor-level context
*/
ConstructorConstraintMappingContext constructor(Class<?>... parameterTypes);
}Usage Example:
mapping.type(Order.class)
.field("items")
.constraint(new NotEmptyDef())
.constraint(new SizeDef().min(1).max(100))
// Configure container elements (List items)
.containerElementType()
.valid() // Cascade validation to each item
.field("totalAmount")
.constraint(new DecimalMinDef().value("0.00"))
.constraint(new DigitsDef().integer(10).fraction(2));Configure constraints on method parameters, return values, and constructors.
package org.hibernate.validator.cfg.context;
/**
* Context for defining constraints on methods.
*/
interface MethodConstraintMappingContext extends Cascadable<MethodConstraintMappingContext>,
AnnotationIgnoreOptions<MethodConstraintMappingContext> {
/**
* Configure parameter constraints.
*
* @param index parameter index (0-based)
* @return parameter constraint context
*/
ParameterConstraintMappingContext parameter(int index);
/**
* Configure cross-parameter constraints.
*
* @return cross-parameter constraint context
*/
CrossParameterConstraintMappingContext crossParameter();
/**
* Configure return value constraints.
*
* @return return value constraint context
*/
ReturnValueConstraintMappingContext returnValue();
/**
* Move to another method.
*
* @param methodName method name
* @param parameterTypes parameter types
* @return method constraint context
*/
MethodConstraintMappingContext method(String methodName, Class<?>... parameterTypes);
/**
* Move to constructor configuration.
*
* @param parameterTypes parameter types
* @return constructor constraint context
*/
ConstructorConstraintMappingContext constructor(Class<?>... parameterTypes);
}
/**
* Context for defining constraints on constructors.
*/
interface ConstructorConstraintMappingContext extends Cascadable<ConstructorConstraintMappingContext>,
AnnotationIgnoreOptions<ConstructorConstraintMappingContext> {
/**
* Configure parameter constraints.
*
* @param index parameter index (0-based)
* @return parameter constraint context
*/
ParameterConstraintMappingContext parameter(int index);
/**
* Configure cross-parameter constraints.
*
* @return cross-parameter constraint context
*/
CrossParameterConstraintMappingContext crossParameter();
/**
* Configure return value constraints (constructor validation).
*
* @return return value constraint context
*/
ReturnValueConstraintMappingContext returnValue();
/**
* Move to another constructor.
*
* @param parameterTypes parameter types
* @return constructor constraint context
*/
ConstructorConstraintMappingContext constructor(Class<?>... parameterTypes);
/**
* Move to method configuration.
*
* @param methodName method name
* @param parameterTypes parameter types
* @return method constraint context
*/
MethodConstraintMappingContext method(String methodName, Class<?>... parameterTypes);
}Usage Example:
mapping.type(UserService.class)
// Configure method parameter constraints
.method("createUser", String.class, String.class, int.class)
.parameter(0) // username parameter
.constraint(new NotNullDef())
.constraint(new SizeDef().min(3).max(50))
.parameter(1) // email parameter
.constraint(new NotNullDef())
.constraint(new EmailDef())
.parameter(2) // age parameter
.constraint(new MinDef().value(18))
.returnValue() // return value constraints
.constraint(new NotNullDef())
.valid() // cascade validation
// Configure constructor constraints
.constructor(String.class)
.parameter(0)
.constraint(new NotBlankDef())
.returnValue()
.valid();Configure constraints on method/constructor parameters and return values.
package org.hibernate.validator.cfg.context;
/**
* Context for defining constraints on parameters.
*/
interface ParameterConstraintMappingContext extends Constrainable<ParameterConstraintMappingContext>,
Cascadable<ParameterConstraintMappingContext>,
ContainerElementTarget,
AnnotationIgnoreOptions<ParameterConstraintMappingContext> {
/**
* Move to another parameter.
*
* @param index parameter index
* @return parameter constraint context
*/
ParameterConstraintMappingContext parameter(int index);
/**
* Move to cross-parameter constraints.
*
* @return cross-parameter constraint context
*/
CrossParameterConstraintMappingContext crossParameter();
/**
* Move to return value constraints.
*
* @return return value constraint context
*/
ReturnValueConstraintMappingContext returnValue();
}
/**
* Context for defining constraints on return values.
*/
interface ReturnValueConstraintMappingContext extends Constrainable<ReturnValueConstraintMappingContext>,
Cascadable<ReturnValueConstraintMappingContext>,
ContainerElementTarget,
AnnotationIgnoreOptions<ReturnValueConstraintMappingContext> {
/**
* Move to parameter constraints.
*
* @param index parameter index
* @return parameter constraint context
*/
ParameterConstraintMappingContext parameter(int index);
/**
* Move to cross-parameter constraints.
*
* @return cross-parameter constraint context
*/
CrossParameterConstraintMappingContext crossParameter();
}
/**
* Context for defining cross-parameter constraints.
*/
interface CrossParameterConstraintMappingContext
extends Constrainable<CrossParameterConstraintMappingContext> {
/**
* Move to parameter constraints.
*
* @param index parameter index
* @return parameter constraint context
*/
ParameterConstraintMappingContext parameter(int index);
/**
* Move to return value constraints.
*
* @return return value constraint context
*/
ReturnValueConstraintMappingContext returnValue();
}Usage Example:
mapping.type(Calculator.class)
.method("divide", double.class, double.class)
.parameter(0)
.constraint(new NotNullDef())
.parameter(1)
.constraint(new NotNullDef())
.constraint(new DecimalMinDef().value("0.01"))
.crossParameter()
.constraint(new ParameterScriptAssertDef()
.lang("javascript")
.script("_args[0] > _args[1]")
.message("Dividend must be greater than divisor"))
.returnValue()
.constraint(new NotNullDef());Configure constraints on container elements (generic type arguments).
package org.hibernate.validator.cfg.context;
/**
* Context for defining constraints on container elements.
*/
interface ContainerElementConstraintMappingContext extends Constrainable<ContainerElementConstraintMappingContext>,
Cascadable<ContainerElementConstraintMappingContext>,
ContainerElementTarget,
AnnotationIgnoreOptions<ContainerElementConstraintMappingContext> {
/**
* Move to another container element.
*
* @return container element constraint context
*/
ContainerElementConstraintMappingContext containerElementType();
/**
* Specify type argument index for nested generics.
*
* @param index type argument index
* @param typeArgumentIndex nested type argument index
* @return container element constraint context
*/
ContainerElementConstraintMappingContext containerElementType(int index, int... typeArgumentIndex);
}
/**
* Marker interface for targets that can have container element constraints.
*/
interface ContainerElementTarget {
/**
* Start configuring container element constraints.
*
* @return container element constraint context
*/
ContainerElementConstraintMappingContext containerElementType();
/**
* Start configuring container element constraints with type argument indices.
*
* @param index type argument index
* @param typeArgumentIndex nested type argument indices
* @return container element constraint context
*/
ContainerElementConstraintMappingContext containerElementType(int index, int... typeArgumentIndex);
}Usage Example:
import java.util.List;
import java.util.Map;
mapping.type(ShoppingCart.class)
// Configure constraints on List<Product> items
.field("items")
.containerElementType() // Constrain List elements
.constraint(new NotNullDef())
.valid() // Cascade to Product
// Configure constraints on Map<String, Order> values
.field("orders")
.containerElementType(0) // Map key (String)
.constraint(new NotBlankDef())
.containerElementType(1) // Map value (Order)
.constraint(new NotNullDef())
.valid() // Cascade to Order
// Configure nested generics: Map<String, List<Item>>
.field("itemsByCategory")
.containerElementType(1, 0) // Map value's List elements
.valid();Core interfaces for adding constraints and configuring cascaded validation.
package org.hibernate.validator.cfg.context;
import jakarta.validation.groups.Default;
import org.hibernate.validator.cfg.ConstraintDef;
/**
* Interface for elements that can have constraints applied.
*
* @param <C> context type for method chaining
*/
interface Constrainable<C extends Constrainable<C>> {
/**
* Add a constraint to this element.
*
* @param <A> constraint definition type
* @param definition constraint definition
* @return this context for method chaining
*/
<A extends ConstraintDef<?, ?>> C constraint(A definition);
}
/**
* Interface for elements that can be marked for cascaded validation.
*
* @param <C> context type for method chaining
*/
interface Cascadable<C extends Cascadable<C>> {
/**
* Mark this element for cascaded validation.
* Equivalent to @Valid annotation.
*
* @return this context for method chaining
*/
C valid();
/**
* Define group conversion for cascaded validation.
* When validating with fromGroup, validate cascaded object with toGroup.
*
* @param fromGroup source group
* @param toGroup target group
* @return this context for method chaining
*/
GroupConversionTargetContext<C> convertGroup(Class<?> fromGroup);
}
/**
* Context for defining group conversion target.
*
* @param <C> context type for method chaining
*/
interface GroupConversionTargetContext<C> {
/**
* Specify target group for group conversion.
*
* @param toGroup target group
* @return parent context
*/
C to(Class<?> toGroup);
}
/**
* Interface for controlling which annotations to ignore.
*
* @param <C> context type for method chaining
*/
interface AnnotationIgnoreOptions<C extends AnnotationIgnoreOptions<C>> {
/**
* Ignore all constraint annotations on this element.
*
* @return this context for method chaining
*/
C ignoreAnnotations();
/**
* Ignore specific annotations on this element.
*
* @param ignoreAnnotations true to ignore annotations
* @return this context for method chaining
*/
C ignoreAnnotations(boolean ignoreAnnotations);
}Usage Example:
// Group conversion example
interface PurchaseGroup {}
interface OrderGroup {}
mapping.type(Order.class)
.field("customer")
.valid()
.convertGroup(Default.class).to(PurchaseGroup.class)
.convertGroup(PurchaseGroup.class).to(OrderGroup.class);
// Ignoring annotations example
mapping.type(LegacyEntity.class)
.field("oldField")
.ignoreAnnotations() // Ignore any @NotNull, @Size, etc. on this field
.constraint(new LengthDef().min(10).max(100)); // Use programmatic constraint insteadType-safe constraint definition classes for programmatic configuration.
package org.hibernate.validator.cfg;
import jakarta.validation.Payload;
import java.lang.annotation.Annotation;
/**
* Base class for annotation definitions in programmatic API.
*
* @param <C> concrete subtype (self-referencing generic)
* @param <A> annotation type being defined
*/
abstract class AnnotationDef<C extends AnnotationDef<C, A>, A extends Annotation> {
// Base annotation definition functionality
}
/**
* Base class for all constraint definition types.
*
* @param <C> concrete constraint definition type
* @param <A> constraint annotation type
*/
abstract class ConstraintDef<C extends ConstraintDef<C, A>, A extends Annotation>
extends AnnotationDef<C, A> {
/**
* Set constraint message.
*
* @param message constraint message
* @return this definition for method chaining
*/
C message(String message);
/**
* Set validation groups.
*
* @param groups validation groups
* @return this definition for method chaining
*/
C groups(Class<?>... groups);
/**
* Set payload.
*
* @param payload payload classes
* @return this definition for method chaining
*/
C payload(Class<? extends Payload>... payload);
}
/**
* Generic constraint definition for constraints without specific type-safe class.
* Allows configuring any constraint annotation type.
*
* @param <A> constraint annotation type
*/
class GenericConstraintDef<A extends Annotation> extends ConstraintDef<GenericConstraintDef<A>, A> {
/**
* Set any annotation parameter.
*
* @param name parameter name
* @param value parameter value
* @return this definition for method chaining
*/
GenericConstraintDef<A> param(String name, Object value);
}Type-safe Constraint Definition Classes:
All standard Jakarta Validation and Hibernate Validator constraints have corresponding type-safe definition classes in org.hibernate.validator.cfg.defs package. The following table shows the mapping between constraint annotations and their programmatic definition classes:
Jakarta Validation Constraints:
@AssertFalse → AssertFalseDef@AssertTrue → AssertTrueDef@DecimalMax → DecimalMaxDef@DecimalMin → DecimalMinDef@Digits → DigitsDef@Email → EmailDef@Future → FutureDef@FutureOrPresent → FutureOrPresentDef@Max → MaxDef@Min → MinDef@Negative → NegativeDef@NegativeOrZero → NegativeOrZeroDef@NotBlank → NotBlankDef@NotEmpty → NotEmptyDef@NotNull → NotNullDef@Null → NullDef@Past → PastDef@PastOrPresent → PastOrPresentDef@Pattern → PatternDef@Positive → PositiveDef@PositiveOrZero → PositiveOrZeroDef@Size → SizeDefHibernate Validator Constraints:
@BitcoinAddress → BitcoinAddressDef@CodePointLength → CodePointLengthDef@ConstraintComposition → ConstraintCompositionDef@CreditCardNumber → CreditCardNumberDef@Currency → CurrencyDef@EAN → EANDef@ISBN → ISBNDef@Length → LengthDef@LuhnCheck → LuhnCheckDef@Mod10Check → Mod10CheckDef@Mod11Check → Mod11CheckDef@Normalized → NormalizedDef@ParameterScriptAssert → ParameterScriptAssertDef@Range → RangeDef@ScriptAssert → ScriptAssertDef@UniqueElements → UniqueElementsDef@URL → URLDef@UUID → UUIDDef@DurationMax → DurationMaxDef (time package)@DurationMin → DurationMinDef (time package)Country-Specific Constraints:
@CPF → org.hibernate.validator.cfg.defs.br.CPFDef (Brazil)@CNPJ → org.hibernate.validator.cfg.defs.br.CNPJDef (Brazil)@TituloEleitoral → org.hibernate.validator.cfg.defs.br.TituloEleitoralDef (Brazil)@KorRRN → org.hibernate.validator.cfg.defs.kor.KorRRNDef (Korea)@NIP → org.hibernate.validator.cfg.defs.pl.NIPDef (Poland)@PESEL → org.hibernate.validator.cfg.defs.pl.PESELDef (Poland)@REGON → org.hibernate.validator.cfg.defs.pl.REGONDef (Poland)@INN → org.hibernate.validator.cfg.defs.ru.INNDef (Russia)Usage Example:
import org.hibernate.validator.cfg.defs.*;
import org.hibernate.validator.cfg.GenericConstraintDef;
// Using type-safe definition classes
mapping.type(Product.class)
.field("name")
.constraint(new NotBlankDef()
.message("Product name is required")
.groups(BasicGroup.class))
.constraint(new LengthDef()
.min(3)
.max(100));
// Using GenericConstraintDef for custom constraints
mapping.type(CustomEntity.class)
.field("code")
.constraint(new GenericConstraintDef<MyCustomConstraint>(MyCustomConstraint.class)
.param("pattern", "[A-Z]{3}-[0-9]{4}")
.param("allowEmpty", false)
.message("Invalid code format"));Define custom constraint validators programmatically.
package org.hibernate.validator.cfg.context;
import jakarta.validation.ConstraintValidator;
import java.lang.annotation.Annotation;
/**
* Context for defining constraint validators for a constraint annotation.
*
* @param <A> constraint annotation type
*/
interface ConstraintDefinitionContext<A extends Annotation> {
/**
* Register a constraint validator for this constraint.
*
* @param <T> validated type
* @param type type this validator validates
* @param validatorType validator class
* @return this context for method chaining
*/
<T> ConstraintDefinitionContext<A> validatedBy(Class<T> type,
Class<? extends ConstraintValidator<A, ? super T>> validatorType);
/**
* Register a constraint validator for this constraint (auto-detect validated type).
*
* @param validatorType validator class
* @return this context for method chaining
*/
ConstraintDefinitionContext<A> validatedBy(
Class<? extends ConstraintValidator<A, ?>> validatorType);
/**
* Include existing validators from annotation's @Constraint meta-annotation.
*
* @param includeExistingValidators true to include existing validators
* @return this context for method chaining
*/
ConstraintDefinitionContext<A> includeExistingValidators(boolean includeExistingValidators);
}Usage Example:
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
// Define custom constraint annotation
@interface MyCustomConstraint {
String message() default "Invalid value";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
// Define custom validator
class MyCustomValidator implements ConstraintValidator<MyCustomConstraint, String> {
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
return value != null && value.matches("[A-Z]{3}-[0-9]{4}");
}
}
// Register validator programmatically
ConstraintMapping mapping = configuration.createConstraintMapping();
mapping.constraintDefinition(MyCustomConstraint.class)
.includeExistingValidators(false) // Don't use validators from @Constraint annotation
.validatedBy(String.class, MyCustomValidator.class);
// Apply constraint
mapping.type(Product.class)
.field("code")
.constraint(new GenericConstraintDef<>(MyCustomConstraint.class));import jakarta.validation.*;
import org.hibernate.validator.HibernateValidator;
import org.hibernate.validator.HibernateValidatorConfiguration;
import org.hibernate.validator.cfg.ConstraintMapping;
import org.hibernate.validator.cfg.defs.*;
// Bootstrap configuration
HibernateValidatorConfiguration configuration = Validation
.byProvider(HibernateValidator.class)
.configure();
// Create constraint mapping
ConstraintMapping mapping = configuration.createConstraintMapping();
// Configure comprehensive constraints
mapping.type(User.class)
// Class-level constraint
.constraint(new ScriptAssertDef()
.lang("javascript")
.script("_this.password == _this.confirmPassword")
.reportOn("confirmPassword")
.message("Passwords must match"))
// Property constraints via field access
.field("username")
.constraint(new NotNullDef())
.constraint(new LengthDef().min(3).max(50))
.field("email")
.constraint(new NotNullDef())
.constraint(new EmailDef())
.field("age")
.constraint(new MinDef().value(18))
.constraint(new MaxDef().value(120))
.field("creditCard")
.constraint(new CreditCardNumberDef().ignoreNonDigitCharacters(true))
.field("address")
.valid() // Cascade validation
// Method parameter and return value constraints
.method("updateEmail", String.class)
.parameter(0)
.constraint(new NotNullDef())
.constraint(new EmailDef())
.returnValue()
.constraint(new NotNullDef())
// Constructor constraints
.constructor(String.class, String.class)
.parameter(0)
.constraint(new NotBlankDef())
.parameter(1)
.constraint(new NotBlankDef());
// Configure collection constraints
mapping.type(Order.class)
.field("items")
.constraint(new NotEmptyDef())
.constraint(new SizeDef().min(1).max(100))
.containerElementType() // Constrain list elements
.constraint(new NotNullDef())
.valid();
// Add mapping and build factory
configuration.addMapping(mapping);
ValidatorFactory factory = configuration.buildValidatorFactory();
Validator validator = factory.getValidator();
// Use validator
User user = new User();
Set<ConstraintViolation<User>> violations = validator.validate(user);Install with Tessl CLI
npx tessl i tessl/maven-org-hibernate-validator--hibernate-validator