0
# Validation
1
2
Bean validation and data binding providing comprehensive validation capabilities for method parameters, return values, and data binding scenarios. This includes Validator interfaces, @Validated annotations, JSR-303/349 Bean Validation integration, and error handling for robust data validation.
3
4
## Capabilities
5
6
### Validator Interfaces
7
8
Core interfaces for application-specific object validation.
9
10
```java { .api }
11
/**
12
* A validator for application-specific objects.
13
*/
14
public interface Validator {
15
/**
16
* Can this Validator validate instances of the supplied clazz?
17
* @param clazz the Class that this Validator is being asked if it can validate
18
* @return true if this Validator can indeed validate instances of the supplied clazz
19
*/
20
boolean supports(Class<?> clazz);
21
22
/**
23
* Validate the supplied target object, which must be of a Class for which the supports(Class) method typically has returned (or would return) true.
24
* @param target the object that is to be validated
25
* @param errors contextual state about the validation process
26
*/
27
void validate(Object target, Errors errors);
28
}
29
30
/**
31
* Extended variant of the Validator interface, adding support for validation 'hints'.
32
*/
33
public interface SmartValidator extends Validator {
34
/**
35
* Validate the supplied target object, which must be of a Class for which the supports(Class) method typically has returned (or would return) true.
36
* @param target the object that is to be validated
37
* @param errors contextual state about the validation process
38
* @param validationHints one or more hint objects to be passed to the validation engine
39
*/
40
void validate(Object target, Errors errors, Object... validationHints);
41
42
/**
43
* Validate the supplied value for the specified field on the target type.
44
* @param targetType the target type
45
* @param fieldName the name of the field
46
* @param value the candidate value
47
* @param errors contextual state about the validation process
48
* @param validationHints one or more hint objects to be passed to the validation engine
49
*/
50
default void validateValue(Class<?> targetType, String fieldName, Object value, Errors errors, Object... validationHints) {
51
throw new IllegalArgumentException("Cannot validate individual value for " + targetType);
52
}
53
}
54
```
55
56
### Validation Annotations
57
58
Annotations for declarative validation control.
59
60
```java { .api }
61
/**
62
* Variant of JSR-303's Valid, supporting the specification of validation groups.
63
*/
64
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER})
65
@Retention(RetentionPolicy.RUNTIME)
66
public @interface Validated {
67
/**
68
* Specify one or more validation groups to apply to the validation step kicked off by this annotation.
69
* @return the validation groups
70
*/
71
Class<?>[] value() default {};
72
}
73
```
74
75
### Error Handling
76
77
Interfaces for storing and exposing validation errors.
78
79
```java { .api }
80
/**
81
* Stores and exposes information about data-binding and validation errors for a specific object.
82
*/
83
public interface Errors {
84
/** The nested path separator */
85
String NESTED_PATH_SEPARATOR = ".";
86
87
/**
88
* Return the name of the bound root object.
89
* @return the name of the bound root object
90
*/
91
String getObjectName();
92
93
/**
94
* Allow context to be changed so that standard validators can validate subtrees.
95
* @param nestedPath nested path within this object
96
*/
97
void setNestedPath(String nestedPath);
98
99
/**
100
* Return the current nested path of this Errors object.
101
* @return the current nested path
102
*/
103
String getNestedPath();
104
105
/**
106
* Push the given sub path onto the nested path stack.
107
* @param subPath the sub path to push onto the nested path stack
108
*/
109
void pushNestedPath(String subPath);
110
111
/**
112
* Pop the former nested path from the nested path stack.
113
* @throws IllegalStateException if there is no former nested path on the stack
114
*/
115
void popNestedPath() throws IllegalStateException;
116
117
/**
118
* Register a global error for the entire target object.
119
* @param errorCode error code, interpretable as a message key
120
*/
121
void reject(String errorCode);
122
123
/**
124
* Register a global error for the entire target object.
125
* @param errorCode error code, interpretable as a message key
126
* @param defaultMessage fallback default message
127
*/
128
void reject(String errorCode, String defaultMessage);
129
130
/**
131
* Register a global error for the entire target object.
132
* @param errorCode error code, interpretable as a message key
133
* @param errorArgs error arguments, for argument binding via MessageFormat
134
* @param defaultMessage fallback default message
135
*/
136
void reject(String errorCode, Object[] errorArgs, String defaultMessage);
137
138
/**
139
* Register a field error for the specified field of the current object.
140
* @param field the field name (may be null or empty String)
141
* @param errorCode error code, interpretable as a message key
142
*/
143
void rejectValue(String field, String errorCode);
144
145
/**
146
* Register a field error for the specified field of the current object.
147
* @param field the field name (may be null or empty String)
148
* @param errorCode error code, interpretable as a message key
149
* @param defaultMessage fallback default message
150
*/
151
void rejectValue(String field, String errorCode, String defaultMessage);
152
153
/**
154
* Register a field error for the specified field of the current object.
155
* @param field the field name (may be null or empty String)
156
* @param errorCode error code, interpretable as a message key
157
* @param errorArgs error arguments, for argument binding via MessageFormat
158
* @param defaultMessage fallback default message
159
*/
160
void rejectValue(String field, String errorCode, Object[] errorArgs, String defaultMessage);
161
162
/**
163
* Add all errors from the given Errors instance to this Errors instance.
164
* @param errors the Errors instance to merge in
165
*/
166
void addAllErrors(Errors errors);
167
168
/**
169
* Return if there were any errors.
170
* @return true if there were any errors
171
*/
172
boolean hasErrors();
173
174
/**
175
* Return the total number of errors.
176
* @return the total number of errors
177
*/
178
int getErrorCount();
179
180
/**
181
* Get all errors, both global and field ones.
182
* @return a list of ObjectError instances
183
*/
184
List<ObjectError> getAllErrors();
185
186
/**
187
* Are there any global errors?
188
* @return true if there are any global errors
189
*/
190
boolean hasGlobalErrors();
191
192
/**
193
* Return the number of global errors.
194
* @return the number of global errors
195
*/
196
int getGlobalErrorCount();
197
198
/**
199
* Get all global errors.
200
* @return a list of ObjectError instances, or an empty list if none
201
*/
202
List<ObjectError> getGlobalErrors();
203
204
/**
205
* Get the first global error, if any.
206
* @return the global error, or null
207
*/
208
ObjectError getGlobalError();
209
210
/**
211
* Are there any field errors?
212
* @return true if there are any field errors
213
*/
214
boolean hasFieldErrors();
215
216
/**
217
* Return the number of errors associated with a field.
218
* @return the number of errors associated with a field
219
*/
220
int getFieldErrorCount();
221
222
/**
223
* Get all errors associated with a field.
224
* @return a List of FieldError instances
225
*/
226
List<FieldError> getFieldErrors();
227
228
/**
229
* Get the first error associated with a field, if any.
230
* @return the field-specific error, or null
231
*/
232
FieldError getFieldError();
233
234
/**
235
* Are there any errors associated with the given field?
236
* @param field the field name
237
* @return true if there were any errors associated with the given field
238
*/
239
boolean hasFieldErrors(String field);
240
241
/**
242
* Return the number of errors associated with the given field.
243
* @param field the field name
244
* @return the number of errors associated with the given field
245
*/
246
int getFieldErrorCount(String field);
247
248
/**
249
* Get all errors associated with the given field.
250
* @param field the field name
251
* @return a List of FieldError instances
252
*/
253
List<FieldError> getFieldErrors(String field);
254
255
/**
256
* Get the first error associated with the given field, if any.
257
* @param field the field name
258
* @return the field-specific error, or null
259
*/
260
FieldError getFieldError(String field);
261
262
/**
263
* Return the current value of the given field.
264
* @param field the field name
265
* @return the current value of the given field
266
*/
267
Object getFieldValue(String field);
268
269
/**
270
* Return the type of a given field.
271
* @param field the field name
272
* @return the type of the field, or null if not determinable
273
*/
274
Class<?> getFieldType(String field);
275
}
276
277
/**
278
* Subinterface of Errors that supports getting and setting the target object.
279
*/
280
public interface BindingResult extends Errors {
281
/**
282
* Return the wrapped target object, which may be null.
283
* @return the wrapped target object
284
*/
285
Object getTarget();
286
287
/**
288
* Return a model Map for the obtained state.
289
* @return the model Map
290
*/
291
Map<String, Object> getModel();
292
293
/**
294
* Extract the raw field value for the given field.
295
* @param field the field to check
296
* @return the raw value of the field
297
*/
298
Object getRawFieldValue(String field);
299
300
/**
301
* Find a custom property editor for the given type and property.
302
* @param field the path of the property (name or nested path)
303
* @param valueType the type of the value (can be null if not known)
304
* @return the custom PropertyEditor, or null if none specific for this property
305
*/
306
PropertyEditor findEditor(String field, Class<?> valueType);
307
308
/**
309
* Return the underlying PropertyEditorRegistry.
310
* @return the underlying PropertyEditorRegistry
311
*/
312
PropertyEditorRegistry getPropertyEditorRegistry();
313
314
/**
315
* Resolve the given error code into message codes.
316
* @param errorCode the error code to resolve into message codes
317
* @return the resolved message codes
318
*/
319
String[] resolveMessageCodes(String errorCode);
320
321
/**
322
* Resolve the given error code into message codes for the given field.
323
* @param errorCode the error code to resolve into message codes
324
* @param field the field to resolve message codes for
325
* @return the resolved message codes
326
*/
327
String[] resolveMessageCodes(String errorCode, String field);
328
329
/**
330
* Add a custom ObjectError or FieldError to the errors list.
331
* @param error the custom error
332
*/
333
void addError(ObjectError error);
334
335
/**
336
* Return the list of fields that were suppressed during binding.
337
* @return the list of suppressed fields
338
*/
339
String[] getSuppressedFields();
340
341
/**
342
* Mark the specified disallowed field as suppressed.
343
* @param field the field name
344
*/
345
void recordSuppressedField(String field);
346
}
347
```
348
349
### Data Binding Support
350
351
Classes for binding property values to target objects with validation.
352
353
```java { .api }
354
/**
355
* Binder that allows for setting property values onto a target object.
356
*/
357
public class DataBinder implements PropertyEditorRegistry, TypeConverter {
358
/** Default object name used for binding */
359
public static final String DEFAULT_OBJECT_NAME = "target";
360
361
/** Default limit for array and collection growing */
362
public static final int DEFAULT_AUTO_GROW_COLLECTION_LIMIT = 256;
363
364
/**
365
* Create a new DataBinder instance, with default object name.
366
* @param target the target object to bind onto (or null if the binder is just used to convert a plain parameter value)
367
*/
368
public DataBinder(Object target) {}
369
370
/**
371
* Create a new DataBinder instance.
372
* @param target the target object to bind onto (or null if the binder is just used to convert a plain parameter value)
373
* @param objectName the name of the target object
374
*/
375
public DataBinder(Object target, String objectName) {}
376
377
/**
378
* Return the wrapped target object.
379
* @return the wrapped target object, or null if none
380
*/
381
public Object getTarget() {}
382
383
/**
384
* Return the name of the bound object.
385
* @return the name of the bound object
386
*/
387
public String getObjectName() {}
388
389
/**
390
* Set the name of the bound object.
391
* @param objectName the name of the bound object
392
*/
393
public void setObjectName(String objectName) {}
394
395
/**
396
* Set whether this binder should attempt to "auto-grow" a nested path that contains a null value.
397
* @param autoGrowNestedPaths whether to "auto-grow" a nested path
398
*/
399
public void setAutoGrowNestedPaths(boolean autoGrowNestedPaths) {}
400
401
/**
402
* Specify the limit for array and collection auto-growing.
403
* @param autoGrowCollectionLimit the limit for array and collection auto-growing
404
*/
405
public void setAutoGrowCollectionLimit(int autoGrowCollectionLimit) {}
406
407
/**
408
* Set the fields that are allowed for binding.
409
* @param allowedFields array of field names
410
*/
411
public void setAllowedFields(String... allowedFields) {}
412
413
/**
414
* Set the fields that are not allowed for binding.
415
* @param disallowedFields array of field names
416
*/
417
public void setDisallowedFields(String... disallowedFields) {}
418
419
/**
420
* Set the required fields for this binder.
421
* @param requiredFields array of field names
422
*/
423
public void setRequiredFields(String... requiredFields) {}
424
425
/**
426
* Set the prefix that this data binder should apply for non-matching boolean and empty fields.
427
* @param fieldMarkerPrefix the field marker prefix to apply
428
*/
429
public void setFieldMarkerPrefix(String fieldMarkerPrefix) {}
430
431
/**
432
* Set the prefix that this data binder should apply for default fields.
433
* @param fieldDefaultPrefix the field default prefix to apply
434
*/
435
public void setFieldDefaultPrefix(String fieldDefaultPrefix) {}
436
437
/**
438
* Set a custom BindingErrorProcessor to apply to this DataBinder.
439
* @param bindingErrorProcessor the custom BindingErrorProcessor
440
*/
441
public void setBindingErrorProcessor(BindingErrorProcessor bindingErrorProcessor) {}
442
443
/**
444
* Set the Validator to apply after each binding step.
445
* @param validator the Validator to apply
446
*/
447
public void setValidator(Validator validator) {}
448
449
/**
450
* Add Validators to apply after each binding step.
451
* @param validators the Validators to apply
452
*/
453
public void addValidators(Validator... validators) {}
454
455
/**
456
* Replace the Validators to apply after each binding step.
457
* @param validators the Validators to apply
458
*/
459
public void replaceValidators(Validator... validators) {}
460
461
/**
462
* Return the primary Validator to apply after each binding step, if any.
463
* @return the primary Validator, or null if none
464
*/
465
public Validator getValidator() {}
466
467
/**
468
* Return the Validators to apply after data binding.
469
* @return the Validators, or an empty List if none
470
*/
471
public List<Validator> getValidators() {}
472
473
/**
474
* Set the ConversionService to be used for type conversion.
475
* @param conversionService the ConversionService to be used for type conversion
476
*/
477
public void setConversionService(ConversionService conversionService) {}
478
479
/**
480
* Bind the given property values to this binder's target.
481
* @param pvs property values to bind
482
*/
483
public void bind(PropertyValues pvs) {}
484
485
/**
486
* Validate the target object using its Validator.
487
*/
488
public void validate() {}
489
490
/**
491
* Validate the target object using its Validator.
492
* @param validationHints one or more hint objects to be passed to the validation engine
493
*/
494
public void validate(Object... validationHints) {}
495
496
/**
497
* Return the BindingResult instance created by this DataBinder.
498
* @return the BindingResult instance, never null
499
*/
500
public BindingResult getBindingResult() {}
501
}
502
```
503
504
### Bean Validation Integration
505
506
Classes integrating JSR-303/349 Bean Validation with Spring validation.
507
508
```java { .api }
509
/**
510
* Configurable bean class that exposes a specific JSR-303 Validator through the Spring Validator interface.
511
*/
512
public class LocalValidatorFactoryBean extends SpringValidatorAdapter implements ValidatorFactory, ApplicationContextAware, InitializingBean, DisposableBean {
513
/**
514
* Set the MessageSource that this validator should use to resolve default messages.
515
* @param messageSource the MessageSource to resolve default messages
516
*/
517
public void setValidationMessageSource(MessageSource messageSource) {}
518
519
/**
520
* Set a custom ParameterNameDiscoverer to use for resolving method and constructor parameter names if needed for message interpolation.
521
* @param parameterNameDiscoverer the ParameterNameDiscoverer to use
522
*/
523
public void setParameterNameDiscoverer(ParameterNameDiscoverer parameterNameDiscoverer) {}
524
525
/**
526
* Specify whether this Validator's supports(Class) method should return true for the specified class.
527
* @param clazz the class to check
528
* @return true if this Validator can validate instances of the supplied clazz
529
*/
530
public boolean supports(Class<?> clazz) {}
531
532
/**
533
* Validate the supplied target object, which must be of a Class for which the supports(Class) method returned true.
534
* @param target the object that is to be validated
535
* @param errors contextual state about the validation process
536
* @param validationHints one or more hint objects to be passed to a JSR-303 validator
537
*/
538
public void validate(Object target, Errors errors, Object... validationHints) {}
539
540
/**
541
* Validate the supplied value for the specified field on the target type.
542
* @param targetType the target type
543
* @param fieldName the name of the field
544
* @param value the candidate value
545
* @param errors contextual state about the validation process
546
* @param validationHints one or more hint objects to be passed to a JSR-303 validator
547
*/
548
public void validateValue(Class<?> targetType, String fieldName, Object value, Errors errors, Object... validationHints) {}
549
}
550
551
/**
552
* Adapter that takes a JSR-303 javax.validation.Validator and exposes it as a Spring Validator.
553
*/
554
public class SpringValidatorAdapter implements SmartValidator, InitializingBean {
555
private javax.validation.Validator targetValidator;
556
557
/**
558
* Create a new SpringValidatorAdapter for the given JSR-303 Validator.
559
* @param targetValidator the JSR-303 Validator to wrap
560
*/
561
public SpringValidatorAdapter(javax.validation.Validator targetValidator) {}
562
563
/**
564
* Specify whether this Validator's supports(Class) method should return true for the specified class.
565
* @param clazz the class to check
566
* @return true if this Validator can validate instances of the supplied clazz
567
*/
568
public boolean supports(Class<?> clazz) {}
569
570
/**
571
* Validate the supplied target object, which must be of a Class for which the supports(Class) method returned true.
572
* @param target the object that is to be validated
573
* @param errors contextual state about the validation process
574
*/
575
public void validate(Object target, Errors errors) {}
576
577
/**
578
* Validate the supplied target object, which must be of a Class for which the supports(Class) method returned true.
579
* @param target the object that is to be validated
580
* @param errors contextual state about the validation process
581
* @param validationHints one or more hint objects to be passed to a JSR-303 validator
582
*/
583
public void validate(Object target, Errors errors, Object... validationHints) {}
584
}
585
586
/**
587
* A convenient BeanPostProcessor implementation that delegates to a JSR-303 provider for performing method-level validation on annotated methods.
588
*/
589
public class MethodValidationPostProcessor extends AbstractBeanFactoryAwareAdvisingPostProcessor implements InitializingBean {
590
/**
591
* Set the JSR-303 Validator to delegate to for validating methods.
592
* @param validator the JSR-303 Validator to use
593
*/
594
public void setValidator(Validator validator) {}
595
596
/**
597
* Set the JSR-303 ValidatorFactory to delegate to for validating methods.
598
* @param validatorFactory the JSR-303 ValidatorFactory to use
599
*/
600
public void setValidatorFactory(ValidatorFactory validatorFactory) {}
601
602
/**
603
* Set the 'validated' annotation type.
604
* @param validated the desired annotation type
605
*/
606
public void setValidated(Class<? extends Annotation> validated) {}
607
}
608
```
609
610
### Usage Examples
611
612
**Basic Validation Usage:**
613
614
```java
615
import org.springframework.validation.annotation.Validated;
616
import javax.validation.Valid;
617
import javax.validation.constraints.*;
618
619
@Service
620
@Validated
621
public class UserService {
622
623
public User createUser(@Valid User user) {
624
// Method parameter validation automatically applied
625
return userRepository.save(user);
626
}
627
628
public void updateUserEmail(@Email String email, @Min(1) Long userId) {
629
// Individual parameter validation
630
User user = userRepository.findById(userId);
631
user.setEmail(email);
632
userRepository.save(user);
633
}
634
635
@Valid
636
public User findUserById(@NotNull @Min(1) Long id) {
637
// Return value validation
638
return userRepository.findById(id);
639
}
640
}
641
642
// Domain object with validation annotations
643
@Entity
644
public class User {
645
@Id
646
@GeneratedValue
647
private Long id;
648
649
@NotBlank(message = "Name is required")
650
@Size(min = 2, max = 100, message = "Name must be between 2 and 100 characters")
651
private String name;
652
653
@Email(message = "Email must be valid")
654
@NotBlank(message = "Email is required")
655
private String email;
656
657
@Min(value = 18, message = "Age must be at least 18")
658
@Max(value = 120, message = "Age must be less than 120")
659
private Integer age;
660
661
@Pattern(regexp = "^\\+?[1-9]\\d{1,14}$", message = "Phone number is invalid")
662
private String phoneNumber;
663
664
// Getters and setters
665
}
666
```