0
# Programmatic Constraint Configuration
1
2
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.
3
4
## Capabilities
5
6
### Constraint Mapping Entry Point
7
8
Create and configure constraint mappings to define validation rules programmatically.
9
10
```java { .api }
11
package org.hibernate.validator.cfg;
12
13
import java.lang.annotation.Annotation;
14
import org.hibernate.validator.cfg.context.ConstraintDefinitionContext;
15
import org.hibernate.validator.cfg.context.TypeConstraintMappingContext;
16
17
/**
18
* Represents a constraint mapping configured via programmatic API.
19
* Create via BaseHibernateValidatorConfiguration.createConstraintMapping().
20
*/
21
interface ConstraintMapping {
22
/**
23
* Start defining constraints on specified bean class.
24
* Each bean class may only be configured once within all constraint mappings.
25
*
26
* @param <C> type to be configured
27
* @param beanClass bean class on which to define constraints
28
* @return context for defining constraints on the class
29
*/
30
<C> TypeConstraintMappingContext<C> type(Class<C> beanClass);
31
32
/**
33
* Start defining ConstraintValidators for specified constraint annotation.
34
* Each constraint may only be configured once within all constraint mappings.
35
*
36
* @param <A> annotation type to be configured
37
* @param annotationClass constraint annotation class
38
* @return context for defining validators for the constraint
39
* @since 5.3
40
*/
41
<A extends Annotation> ConstraintDefinitionContext<A> constraintDefinition(Class<A> annotationClass);
42
}
43
```
44
45
**Usage Example:**
46
47
```java
48
import jakarta.validation.Validation;
49
import org.hibernate.validator.HibernateValidator;
50
import org.hibernate.validator.HibernateValidatorConfiguration;
51
import org.hibernate.validator.cfg.ConstraintMapping;
52
53
HibernateValidatorConfiguration configuration = Validation
54
.byProvider(HibernateValidator.class)
55
.configure();
56
57
// Create constraint mapping
58
ConstraintMapping mapping = configuration.createConstraintMapping();
59
60
// Configure constraints (see examples below)
61
62
// Add mapping to configuration
63
configuration.addMapping(mapping);
64
65
ValidatorFactory factory = configuration.buildValidatorFactory();
66
```
67
68
### Type-Level Configuration
69
70
Configure constraints at the class level including class-level constraints, property constraints, method constraints, and constructor constraints.
71
72
```java { .api }
73
package org.hibernate.validator.cfg.context;
74
75
import org.hibernate.validator.cfg.ConstraintDef;
76
77
/**
78
* Context for defining constraints at type level.
79
*
80
* @param <C> configured bean type
81
*/
82
interface TypeConstraintMappingContext<C> extends Constrainable<TypeConstraintMappingContext<C>>,
83
Cascadable<TypeConstraintMappingContext<C>>,
84
AnnotationIgnoreOptions<TypeConstraintMappingContext<C>>,
85
PropertyTarget {
86
87
/**
88
* Start defining constraints on a method.
89
*
90
* @param methodName method name
91
* @param parameterTypes method parameter types
92
* @return context for defining method constraints
93
*/
94
MethodConstraintMappingContext method(String methodName, Class<?>... parameterTypes);
95
96
/**
97
* Start defining constraints on a constructor.
98
*
99
* @param parameterTypes constructor parameter types
100
* @return context for defining constructor constraints
101
*/
102
ConstructorConstraintMappingContext constructor(Class<?>... parameterTypes);
103
}
104
105
/**
106
* Provides methods for configuring property-level constraints.
107
*/
108
interface PropertyTarget {
109
/**
110
* Start defining constraints on a property via field access.
111
*
112
* @param property property name
113
* @return context for defining property constraints
114
*/
115
PropertyConstraintMappingContext field(String property);
116
117
/**
118
* Start defining constraints on a property via getter method access.
119
*
120
* @param property property name
121
* @return context for defining property constraints
122
*/
123
PropertyConstraintMappingContext getter(String property);
124
}
125
```
126
127
**Important Note:** The `PropertyTarget` interface provides two distinct methods for property constraint configuration:
128
- Use `field(String property)` to apply constraints at the field level
129
- Use `getter(String property)` to apply constraints at the getter method level
130
131
There 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.
132
133
**Usage Example:**
134
135
```java
136
import org.hibernate.validator.cfg.ConstraintMapping;
137
import org.hibernate.validator.cfg.defs.*;
138
139
ConstraintMapping mapping = configuration.createConstraintMapping();
140
141
// Configure type-level constraints
142
mapping.type(User.class)
143
// Add class-level constraint
144
.constraint(new ScriptAssertDef()
145
.lang("javascript")
146
.script("_this.password == _this.confirmPassword")
147
.message("Passwords must match"))
148
// Mark type for cascaded validation
149
.valid()
150
// Configure property constraints via field access
151
.field("email")
152
.constraint(new NotNullDef())
153
.constraint(new EmailDef())
154
.field("age")
155
.constraint(new MinDef().value(18))
156
.constraint(new MaxDef().value(120));
157
```
158
159
### Property-Level Configuration
160
161
Configure constraints on bean properties (fields or getter methods).
162
163
```java { .api }
164
package org.hibernate.validator.cfg.context;
165
166
/**
167
* Context for defining constraints on properties.
168
*/
169
interface PropertyConstraintMappingContext extends Constrainable<PropertyConstraintMappingContext>,
170
Cascadable<PropertyConstraintMappingContext>,
171
ContainerElementTarget,
172
AnnotationIgnoreOptions<PropertyConstraintMappingContext>,
173
PropertyTarget {
174
175
/**
176
* Move to method configuration.
177
*
178
* @param methodName method name
179
* @param parameterTypes parameter types
180
* @return method-level context
181
*/
182
MethodConstraintMappingContext method(String methodName, Class<?>... parameterTypes);
183
184
/**
185
* Move to constructor configuration.
186
*
187
* @param parameterTypes parameter types
188
* @return constructor-level context
189
*/
190
ConstructorConstraintMappingContext constructor(Class<?>... parameterTypes);
191
}
192
```
193
194
**Usage Example:**
195
196
```java
197
mapping.type(Order.class)
198
.field("items")
199
.constraint(new NotEmptyDef())
200
.constraint(new SizeDef().min(1).max(100))
201
// Configure container elements (List items)
202
.containerElementType()
203
.valid() // Cascade validation to each item
204
.field("totalAmount")
205
.constraint(new DecimalMinDef().value("0.00"))
206
.constraint(new DigitsDef().integer(10).fraction(2));
207
```
208
209
### Method and Constructor Configuration
210
211
Configure constraints on method parameters, return values, and constructors.
212
213
```java { .api }
214
package org.hibernate.validator.cfg.context;
215
216
/**
217
* Context for defining constraints on methods.
218
*/
219
interface MethodConstraintMappingContext extends Cascadable<MethodConstraintMappingContext>,
220
AnnotationIgnoreOptions<MethodConstraintMappingContext> {
221
222
/**
223
* Configure parameter constraints.
224
*
225
* @param index parameter index (0-based)
226
* @return parameter constraint context
227
*/
228
ParameterConstraintMappingContext parameter(int index);
229
230
/**
231
* Configure cross-parameter constraints.
232
*
233
* @return cross-parameter constraint context
234
*/
235
CrossParameterConstraintMappingContext crossParameter();
236
237
/**
238
* Configure return value constraints.
239
*
240
* @return return value constraint context
241
*/
242
ReturnValueConstraintMappingContext returnValue();
243
244
/**
245
* Move to another method.
246
*
247
* @param methodName method name
248
* @param parameterTypes parameter types
249
* @return method constraint context
250
*/
251
MethodConstraintMappingContext method(String methodName, Class<?>... parameterTypes);
252
253
/**
254
* Move to constructor configuration.
255
*
256
* @param parameterTypes parameter types
257
* @return constructor constraint context
258
*/
259
ConstructorConstraintMappingContext constructor(Class<?>... parameterTypes);
260
}
261
262
/**
263
* Context for defining constraints on constructors.
264
*/
265
interface ConstructorConstraintMappingContext extends Cascadable<ConstructorConstraintMappingContext>,
266
AnnotationIgnoreOptions<ConstructorConstraintMappingContext> {
267
268
/**
269
* Configure parameter constraints.
270
*
271
* @param index parameter index (0-based)
272
* @return parameter constraint context
273
*/
274
ParameterConstraintMappingContext parameter(int index);
275
276
/**
277
* Configure cross-parameter constraints.
278
*
279
* @return cross-parameter constraint context
280
*/
281
CrossParameterConstraintMappingContext crossParameter();
282
283
/**
284
* Configure return value constraints (constructor validation).
285
*
286
* @return return value constraint context
287
*/
288
ReturnValueConstraintMappingContext returnValue();
289
290
/**
291
* Move to another constructor.
292
*
293
* @param parameterTypes parameter types
294
* @return constructor constraint context
295
*/
296
ConstructorConstraintMappingContext constructor(Class<?>... parameterTypes);
297
298
/**
299
* Move to method configuration.
300
*
301
* @param methodName method name
302
* @param parameterTypes parameter types
303
* @return method constraint context
304
*/
305
MethodConstraintMappingContext method(String methodName, Class<?>... parameterTypes);
306
}
307
```
308
309
**Usage Example:**
310
311
```java
312
mapping.type(UserService.class)
313
// Configure method parameter constraints
314
.method("createUser", String.class, String.class, int.class)
315
.parameter(0) // username parameter
316
.constraint(new NotNullDef())
317
.constraint(new SizeDef().min(3).max(50))
318
.parameter(1) // email parameter
319
.constraint(new NotNullDef())
320
.constraint(new EmailDef())
321
.parameter(2) // age parameter
322
.constraint(new MinDef().value(18))
323
.returnValue() // return value constraints
324
.constraint(new NotNullDef())
325
.valid() // cascade validation
326
327
// Configure constructor constraints
328
.constructor(String.class)
329
.parameter(0)
330
.constraint(new NotBlankDef())
331
.returnValue()
332
.valid();
333
```
334
335
### Parameter and Return Value Configuration
336
337
Configure constraints on method/constructor parameters and return values.
338
339
```java { .api }
340
package org.hibernate.validator.cfg.context;
341
342
/**
343
* Context for defining constraints on parameters.
344
*/
345
interface ParameterConstraintMappingContext extends Constrainable<ParameterConstraintMappingContext>,
346
Cascadable<ParameterConstraintMappingContext>,
347
ContainerElementTarget,
348
AnnotationIgnoreOptions<ParameterConstraintMappingContext> {
349
350
/**
351
* Move to another parameter.
352
*
353
* @param index parameter index
354
* @return parameter constraint context
355
*/
356
ParameterConstraintMappingContext parameter(int index);
357
358
/**
359
* Move to cross-parameter constraints.
360
*
361
* @return cross-parameter constraint context
362
*/
363
CrossParameterConstraintMappingContext crossParameter();
364
365
/**
366
* Move to return value constraints.
367
*
368
* @return return value constraint context
369
*/
370
ReturnValueConstraintMappingContext returnValue();
371
}
372
373
/**
374
* Context for defining constraints on return values.
375
*/
376
interface ReturnValueConstraintMappingContext extends Constrainable<ReturnValueConstraintMappingContext>,
377
Cascadable<ReturnValueConstraintMappingContext>,
378
ContainerElementTarget,
379
AnnotationIgnoreOptions<ReturnValueConstraintMappingContext> {
380
381
/**
382
* Move to parameter constraints.
383
*
384
* @param index parameter index
385
* @return parameter constraint context
386
*/
387
ParameterConstraintMappingContext parameter(int index);
388
389
/**
390
* Move to cross-parameter constraints.
391
*
392
* @return cross-parameter constraint context
393
*/
394
CrossParameterConstraintMappingContext crossParameter();
395
}
396
397
/**
398
* Context for defining cross-parameter constraints.
399
*/
400
interface CrossParameterConstraintMappingContext
401
extends Constrainable<CrossParameterConstraintMappingContext> {
402
403
/**
404
* Move to parameter constraints.
405
*
406
* @param index parameter index
407
* @return parameter constraint context
408
*/
409
ParameterConstraintMappingContext parameter(int index);
410
411
/**
412
* Move to return value constraints.
413
*
414
* @return return value constraint context
415
*/
416
ReturnValueConstraintMappingContext returnValue();
417
}
418
```
419
420
**Usage Example:**
421
422
```java
423
mapping.type(Calculator.class)
424
.method("divide", double.class, double.class)
425
.parameter(0)
426
.constraint(new NotNullDef())
427
.parameter(1)
428
.constraint(new NotNullDef())
429
.constraint(new DecimalMinDef().value("0.01"))
430
.crossParameter()
431
.constraint(new ParameterScriptAssertDef()
432
.lang("javascript")
433
.script("_args[0] > _args[1]")
434
.message("Dividend must be greater than divisor"))
435
.returnValue()
436
.constraint(new NotNullDef());
437
```
438
439
### Container Element Configuration
440
441
Configure constraints on container elements (generic type arguments).
442
443
```java { .api }
444
package org.hibernate.validator.cfg.context;
445
446
/**
447
* Context for defining constraints on container elements.
448
*/
449
interface ContainerElementConstraintMappingContext extends Constrainable<ContainerElementConstraintMappingContext>,
450
Cascadable<ContainerElementConstraintMappingContext>,
451
ContainerElementTarget,
452
AnnotationIgnoreOptions<ContainerElementConstraintMappingContext> {
453
454
/**
455
* Move to another container element.
456
*
457
* @return container element constraint context
458
*/
459
ContainerElementConstraintMappingContext containerElementType();
460
461
/**
462
* Specify type argument index for nested generics.
463
*
464
* @param index type argument index
465
* @param typeArgumentIndex nested type argument index
466
* @return container element constraint context
467
*/
468
ContainerElementConstraintMappingContext containerElementType(int index, int... typeArgumentIndex);
469
}
470
471
/**
472
* Marker interface for targets that can have container element constraints.
473
*/
474
interface ContainerElementTarget {
475
/**
476
* Start configuring container element constraints.
477
*
478
* @return container element constraint context
479
*/
480
ContainerElementConstraintMappingContext containerElementType();
481
482
/**
483
* Start configuring container element constraints with type argument indices.
484
*
485
* @param index type argument index
486
* @param typeArgumentIndex nested type argument indices
487
* @return container element constraint context
488
*/
489
ContainerElementConstraintMappingContext containerElementType(int index, int... typeArgumentIndex);
490
}
491
```
492
493
**Usage Example:**
494
495
```java
496
import java.util.List;
497
import java.util.Map;
498
499
mapping.type(ShoppingCart.class)
500
// Configure constraints on List<Product> items
501
.field("items")
502
.containerElementType() // Constrain List elements
503
.constraint(new NotNullDef())
504
.valid() // Cascade to Product
505
506
// Configure constraints on Map<String, Order> values
507
.field("orders")
508
.containerElementType(0) // Map key (String)
509
.constraint(new NotBlankDef())
510
.containerElementType(1) // Map value (Order)
511
.constraint(new NotNullDef())
512
.valid() // Cascade to Order
513
514
// Configure nested generics: Map<String, List<Item>>
515
.field("itemsByCategory")
516
.containerElementType(1, 0) // Map value's List elements
517
.valid();
518
```
519
520
### Constraint and Cascading Configuration
521
522
Core interfaces for adding constraints and configuring cascaded validation.
523
524
```java { .api }
525
package org.hibernate.validator.cfg.context;
526
527
import jakarta.validation.groups.Default;
528
import org.hibernate.validator.cfg.ConstraintDef;
529
530
/**
531
* Interface for elements that can have constraints applied.
532
*
533
* @param <C> context type for method chaining
534
*/
535
interface Constrainable<C extends Constrainable<C>> {
536
/**
537
* Add a constraint to this element.
538
*
539
* @param <A> constraint definition type
540
* @param definition constraint definition
541
* @return this context for method chaining
542
*/
543
<A extends ConstraintDef<?, ?>> C constraint(A definition);
544
}
545
546
/**
547
* Interface for elements that can be marked for cascaded validation.
548
*
549
* @param <C> context type for method chaining
550
*/
551
interface Cascadable<C extends Cascadable<C>> {
552
/**
553
* Mark this element for cascaded validation.
554
* Equivalent to @Valid annotation.
555
*
556
* @return this context for method chaining
557
*/
558
C valid();
559
560
/**
561
* Define group conversion for cascaded validation.
562
* When validating with fromGroup, validate cascaded object with toGroup.
563
*
564
* @param fromGroup source group
565
* @param toGroup target group
566
* @return this context for method chaining
567
*/
568
GroupConversionTargetContext<C> convertGroup(Class<?> fromGroup);
569
}
570
571
/**
572
* Context for defining group conversion target.
573
*
574
* @param <C> context type for method chaining
575
*/
576
interface GroupConversionTargetContext<C> {
577
/**
578
* Specify target group for group conversion.
579
*
580
* @param toGroup target group
581
* @return parent context
582
*/
583
C to(Class<?> toGroup);
584
}
585
586
/**
587
* Interface for controlling which annotations to ignore.
588
*
589
* @param <C> context type for method chaining
590
*/
591
interface AnnotationIgnoreOptions<C extends AnnotationIgnoreOptions<C>> {
592
/**
593
* Ignore all constraint annotations on this element.
594
*
595
* @return this context for method chaining
596
*/
597
C ignoreAnnotations();
598
599
/**
600
* Ignore specific annotations on this element.
601
*
602
* @param ignoreAnnotations true to ignore annotations
603
* @return this context for method chaining
604
*/
605
C ignoreAnnotations(boolean ignoreAnnotations);
606
}
607
```
608
609
**Usage Example:**
610
611
```java
612
// Group conversion example
613
interface PurchaseGroup {}
614
interface OrderGroup {}
615
616
mapping.type(Order.class)
617
.field("customer")
618
.valid()
619
.convertGroup(Default.class).to(PurchaseGroup.class)
620
.convertGroup(PurchaseGroup.class).to(OrderGroup.class);
621
622
// Ignoring annotations example
623
mapping.type(LegacyEntity.class)
624
.field("oldField")
625
.ignoreAnnotations() // Ignore any @NotNull, @Size, etc. on this field
626
.constraint(new LengthDef().min(10).max(100)); // Use programmatic constraint instead
627
```
628
629
### Constraint Definition Types
630
631
Type-safe constraint definition classes for programmatic configuration.
632
633
```java { .api }
634
package org.hibernate.validator.cfg;
635
636
import jakarta.validation.Payload;
637
import java.lang.annotation.Annotation;
638
639
/**
640
* Base class for annotation definitions in programmatic API.
641
*
642
* @param <C> concrete subtype (self-referencing generic)
643
* @param <A> annotation type being defined
644
*/
645
abstract class AnnotationDef<C extends AnnotationDef<C, A>, A extends Annotation> {
646
// Base annotation definition functionality
647
}
648
649
/**
650
* Base class for all constraint definition types.
651
*
652
* @param <C> concrete constraint definition type
653
* @param <A> constraint annotation type
654
*/
655
abstract class ConstraintDef<C extends ConstraintDef<C, A>, A extends Annotation>
656
extends AnnotationDef<C, A> {
657
658
/**
659
* Set constraint message.
660
*
661
* @param message constraint message
662
* @return this definition for method chaining
663
*/
664
C message(String message);
665
666
/**
667
* Set validation groups.
668
*
669
* @param groups validation groups
670
* @return this definition for method chaining
671
*/
672
C groups(Class<?>... groups);
673
674
/**
675
* Set payload.
676
*
677
* @param payload payload classes
678
* @return this definition for method chaining
679
*/
680
C payload(Class<? extends Payload>... payload);
681
}
682
683
/**
684
* Generic constraint definition for constraints without specific type-safe class.
685
* Allows configuring any constraint annotation type.
686
*
687
* @param <A> constraint annotation type
688
*/
689
class GenericConstraintDef<A extends Annotation> extends ConstraintDef<GenericConstraintDef<A>, A> {
690
/**
691
* Set any annotation parameter.
692
*
693
* @param name parameter name
694
* @param value parameter value
695
* @return this definition for method chaining
696
*/
697
GenericConstraintDef<A> param(String name, Object value);
698
}
699
```
700
701
**Type-safe Constraint Definition Classes:**
702
703
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:
704
705
**Jakarta Validation Constraints:**
706
- `@AssertFalse` → `AssertFalseDef`
707
- `@AssertTrue` → `AssertTrueDef`
708
- `@DecimalMax` → `DecimalMaxDef`
709
- `@DecimalMin` → `DecimalMinDef`
710
- `@Digits` → `DigitsDef`
711
- `@Email` → `EmailDef`
712
- `@Future` → `FutureDef`
713
- `@FutureOrPresent` → `FutureOrPresentDef`
714
- `@Max` → `MaxDef`
715
- `@Min` → `MinDef`
716
- `@Negative` → `NegativeDef`
717
- `@NegativeOrZero` → `NegativeOrZeroDef`
718
- `@NotBlank` → `NotBlankDef`
719
- `@NotEmpty` → `NotEmptyDef`
720
- `@NotNull` → `NotNullDef`
721
- `@Null` → `NullDef`
722
- `@Past` → `PastDef`
723
- `@PastOrPresent` → `PastOrPresentDef`
724
- `@Pattern` → `PatternDef`
725
- `@Positive` → `PositiveDef`
726
- `@PositiveOrZero` → `PositiveOrZeroDef`
727
- `@Size` → `SizeDef`
728
729
**Hibernate Validator Constraints:**
730
- `@BitcoinAddress` → `BitcoinAddressDef`
731
- `@CodePointLength` → `CodePointLengthDef`
732
- `@ConstraintComposition` → `ConstraintCompositionDef`
733
- `@CreditCardNumber` → `CreditCardNumberDef`
734
- `@Currency` → `CurrencyDef`
735
- `@EAN` → `EANDef`
736
- `@ISBN` → `ISBNDef`
737
- `@Length` → `LengthDef`
738
- `@LuhnCheck` → `LuhnCheckDef`
739
- `@Mod10Check` → `Mod10CheckDef`
740
- `@Mod11Check` → `Mod11CheckDef`
741
- `@Normalized` → `NormalizedDef`
742
- `@ParameterScriptAssert` → `ParameterScriptAssertDef`
743
- `@Range` → `RangeDef`
744
- `@ScriptAssert` → `ScriptAssertDef`
745
- `@UniqueElements` → `UniqueElementsDef`
746
- `@URL` → `URLDef`
747
- `@UUID` → `UUIDDef`
748
- `@DurationMax` → `DurationMaxDef` (time package)
749
- `@DurationMin` → `DurationMinDef` (time package)
750
751
**Country-Specific Constraints:**
752
- `@CPF` → `org.hibernate.validator.cfg.defs.br.CPFDef` (Brazil)
753
- `@CNPJ` → `org.hibernate.validator.cfg.defs.br.CNPJDef` (Brazil)
754
- `@TituloEleitoral` → `org.hibernate.validator.cfg.defs.br.TituloEleitoralDef` (Brazil)
755
- `@KorRRN` → `org.hibernate.validator.cfg.defs.kor.KorRRNDef` (Korea)
756
- `@NIP` → `org.hibernate.validator.cfg.defs.pl.NIPDef` (Poland)
757
- `@PESEL` → `org.hibernate.validator.cfg.defs.pl.PESELDef` (Poland)
758
- `@REGON` → `org.hibernate.validator.cfg.defs.pl.REGONDef` (Poland)
759
- `@INN` → `org.hibernate.validator.cfg.defs.ru.INNDef` (Russia)
760
761
**Usage Example:**
762
763
```java
764
import org.hibernate.validator.cfg.defs.*;
765
import org.hibernate.validator.cfg.GenericConstraintDef;
766
767
// Using type-safe definition classes
768
mapping.type(Product.class)
769
.field("name")
770
.constraint(new NotBlankDef()
771
.message("Product name is required")
772
.groups(BasicGroup.class))
773
.constraint(new LengthDef()
774
.min(3)
775
.max(100));
776
777
// Using GenericConstraintDef for custom constraints
778
mapping.type(CustomEntity.class)
779
.field("code")
780
.constraint(new GenericConstraintDef<MyCustomConstraint>(MyCustomConstraint.class)
781
.param("pattern", "[A-Z]{3}-[0-9]{4}")
782
.param("allowEmpty", false)
783
.message("Invalid code format"));
784
```
785
786
### Constraint Validator Definition
787
788
Define custom constraint validators programmatically.
789
790
```java { .api }
791
package org.hibernate.validator.cfg.context;
792
793
import jakarta.validation.ConstraintValidator;
794
import java.lang.annotation.Annotation;
795
796
/**
797
* Context for defining constraint validators for a constraint annotation.
798
*
799
* @param <A> constraint annotation type
800
*/
801
interface ConstraintDefinitionContext<A extends Annotation> {
802
/**
803
* Register a constraint validator for this constraint.
804
*
805
* @param <T> validated type
806
* @param type type this validator validates
807
* @param validatorType validator class
808
* @return this context for method chaining
809
*/
810
<T> ConstraintDefinitionContext<A> validatedBy(Class<T> type,
811
Class<? extends ConstraintValidator<A, ? super T>> validatorType);
812
813
/**
814
* Register a constraint validator for this constraint (auto-detect validated type).
815
*
816
* @param validatorType validator class
817
* @return this context for method chaining
818
*/
819
ConstraintDefinitionContext<A> validatedBy(
820
Class<? extends ConstraintValidator<A, ?>> validatorType);
821
822
/**
823
* Include existing validators from annotation's @Constraint meta-annotation.
824
*
825
* @param includeExistingValidators true to include existing validators
826
* @return this context for method chaining
827
*/
828
ConstraintDefinitionContext<A> includeExistingValidators(boolean includeExistingValidators);
829
}
830
```
831
832
**Usage Example:**
833
834
```java
835
import jakarta.validation.ConstraintValidator;
836
import jakarta.validation.ConstraintValidatorContext;
837
838
// Define custom constraint annotation
839
@interface MyCustomConstraint {
840
String message() default "Invalid value";
841
Class<?>[] groups() default {};
842
Class<? extends Payload>[] payload() default {};
843
}
844
845
// Define custom validator
846
class MyCustomValidator implements ConstraintValidator<MyCustomConstraint, String> {
847
@Override
848
public boolean isValid(String value, ConstraintValidatorContext context) {
849
return value != null && value.matches("[A-Z]{3}-[0-9]{4}");
850
}
851
}
852
853
// Register validator programmatically
854
ConstraintMapping mapping = configuration.createConstraintMapping();
855
856
mapping.constraintDefinition(MyCustomConstraint.class)
857
.includeExistingValidators(false) // Don't use validators from @Constraint annotation
858
.validatedBy(String.class, MyCustomValidator.class);
859
860
// Apply constraint
861
mapping.type(Product.class)
862
.field("code")
863
.constraint(new GenericConstraintDef<>(MyCustomConstraint.class));
864
```
865
866
## Complete Usage Example
867
868
```java
869
import jakarta.validation.*;
870
import org.hibernate.validator.HibernateValidator;
871
import org.hibernate.validator.HibernateValidatorConfiguration;
872
import org.hibernate.validator.cfg.ConstraintMapping;
873
import org.hibernate.validator.cfg.defs.*;
874
875
// Bootstrap configuration
876
HibernateValidatorConfiguration configuration = Validation
877
.byProvider(HibernateValidator.class)
878
.configure();
879
880
// Create constraint mapping
881
ConstraintMapping mapping = configuration.createConstraintMapping();
882
883
// Configure comprehensive constraints
884
mapping.type(User.class)
885
// Class-level constraint
886
.constraint(new ScriptAssertDef()
887
.lang("javascript")
888
.script("_this.password == _this.confirmPassword")
889
.reportOn("confirmPassword")
890
.message("Passwords must match"))
891
892
// Property constraints via field access
893
.field("username")
894
.constraint(new NotNullDef())
895
.constraint(new LengthDef().min(3).max(50))
896
.field("email")
897
.constraint(new NotNullDef())
898
.constraint(new EmailDef())
899
.field("age")
900
.constraint(new MinDef().value(18))
901
.constraint(new MaxDef().value(120))
902
.field("creditCard")
903
.constraint(new CreditCardNumberDef().ignoreNonDigitCharacters(true))
904
.field("address")
905
.valid() // Cascade validation
906
907
// Method parameter and return value constraints
908
.method("updateEmail", String.class)
909
.parameter(0)
910
.constraint(new NotNullDef())
911
.constraint(new EmailDef())
912
.returnValue()
913
.constraint(new NotNullDef())
914
915
// Constructor constraints
916
.constructor(String.class, String.class)
917
.parameter(0)
918
.constraint(new NotBlankDef())
919
.parameter(1)
920
.constraint(new NotBlankDef());
921
922
// Configure collection constraints
923
mapping.type(Order.class)
924
.field("items")
925
.constraint(new NotEmptyDef())
926
.constraint(new SizeDef().min(1).max(100))
927
.containerElementType() // Constrain list elements
928
.constraint(new NotNullDef())
929
.valid();
930
931
// Add mapping and build factory
932
configuration.addMapping(mapping);
933
ValidatorFactory factory = configuration.buildValidatorFactory();
934
Validator validator = factory.getValidator();
935
936
// Use validator
937
User user = new User();
938
Set<ConstraintViolation<User>> violations = validator.validate(user);
939
```
940