0
# Method Validation
1
2
Validation support for method parameters, return values, and constructor parameters with cross-parameter constraint capabilities and executable validation configuration.
3
4
## Capabilities
5
6
### Executable Validator
7
8
Interface for validating method and constructor parameters and return values.
9
10
```java { .api }
11
/**
12
* Validates parameters and return values of methods and constructors
13
* Obtained from Validator.forExecutables()
14
*/
15
interface ExecutableValidator {
16
/**
17
* Validate method parameters
18
* @param object instance on which the method is invoked (null for static methods)
19
* @param method method to validate parameters for
20
* @param parameterValues parameter values to validate
21
* @param groups validation groups to apply
22
* @return set of constraint violations
23
*/
24
<T> Set<ConstraintViolation<T>> validateParameters(
25
T object, Method method, Object[] parameterValues, Class<?>... groups);
26
27
/**
28
* Validate method return value
29
* @param object instance on which the method was invoked (null for static methods)
30
* @param method method to validate return value for
31
* @param returnValue return value to validate
32
* @param groups validation groups to apply
33
* @return set of constraint violations
34
*/
35
<T> Set<ConstraintViolation<T>> validateReturnValue(
36
T object, Method method, Object returnValue, Class<?>... groups);
37
38
/**
39
* Validate constructor parameters
40
* @param constructor constructor to validate parameters for
41
* @param parameterValues parameter values to validate
42
* @param groups validation groups to apply
43
* @return set of constraint violations
44
*/
45
<T> Set<ConstraintViolation<T>> validateConstructorParameters(
46
Constructor<? extends T> constructor, Object[] parameterValues, Class<?>... groups);
47
48
/**
49
* Validate constructor return value (the created object)
50
* @param constructor constructor that created the object
51
* @param createdObject the created object to validate
52
* @param groups validation groups to apply
53
* @return set of constraint violations
54
*/
55
<T> Set<ConstraintViolation<T>> validateConstructorReturnValue(
56
Constructor<? extends T> constructor, T createdObject, Class<?>... groups);
57
}
58
```
59
60
### Executable Validation Configuration
61
62
Enums and annotations for configuring when executable validation occurs.
63
64
```java { .api }
65
/**
66
* Defines the types of executables targeted by an operation
67
*/
68
enum ExecutableType {
69
/** No executable validation */
70
NONE,
71
72
/** Implicit configuration (provider-specific) */
73
IMPLICIT,
74
75
/** All constructors */
76
CONSTRUCTORS,
77
78
/** All methods except getters */
79
NON_GETTER_METHODS,
80
81
/** Getter methods only */
82
GETTER_METHODS,
83
84
/** All executables (constructors and methods) */
85
ALL
86
}
87
88
/**
89
* Controls executable validation on methods and constructors
90
* Can be applied to types, methods, and constructors
91
*/
92
@Target({TYPE, METHOD, CONSTRUCTOR})
93
@Retention(RUNTIME)
94
@interface ValidateOnExecution {
95
/**
96
* Define the type of executables to validate
97
* @return array of ExecutableType values
98
*/
99
ExecutableType[] type() default {ExecutableType.IMPLICIT};
100
}
101
```
102
103
### Cross-Parameter Validation
104
105
Support for constraints that validate multiple parameters together.
106
107
```java { .api }
108
/**
109
* Validation target enum for constraint validators
110
*/
111
enum ValidationTarget {
112
/** Validate the annotated element */
113
ANNOTATED_ELEMENT,
114
115
/** Validate the array of parameters (cross-parameter validation) */
116
PARAMETERS
117
}
118
119
/**
120
* Defines targets a ConstraintValidator can validate
121
* Applied to ConstraintValidator implementations
122
*/
123
@Target({TYPE})
124
@Retention(RUNTIME)
125
@interface SupportedValidationTarget {
126
/**
127
* Supported validation targets
128
* @return array of ValidationTarget values
129
*/
130
ValidationTarget[] value();
131
}
132
133
/**
134
* Defines constraint target (parameters vs return value)
135
*/
136
enum ConstraintTarget {
137
/** Let the validation engine determine the target */
138
IMPLICIT,
139
140
/** Target the method/constructor parameters */
141
PARAMETERS,
142
143
/** Target the method return value */
144
RETURN_VALUE
145
}
146
```
147
148
**Usage Examples:**
149
150
```java
151
import jakarta.validation.*;
152
import jakarta.validation.constraints.*;
153
import jakarta.validation.executable.*;
154
import java.lang.reflect.Method;
155
156
// 1. Method parameter validation
157
@ValidateOnExecution(type = ExecutableType.NON_GETTER_METHODS)
158
public class UserService {
159
160
public User createUser(
161
@NotNull @Size(min = 2, max = 50) String name,
162
@Min(18) int age,
163
@Email String email) {
164
return new User(name, age, email);
165
}
166
167
@NotNull
168
@Valid
169
public User updateUser(@NotNull @Valid User user) {
170
// Update logic
171
return user;
172
}
173
174
// Getter - validation controlled by ExecutableType.GETTER_METHODS
175
@Size(min = 1)
176
public List<User> getUsers() {
177
return userRepository.findAll();
178
}
179
}
180
181
// 2. Constructor validation
182
public class Product {
183
private String name;
184
private BigDecimal price;
185
186
public Product(
187
@NotBlank String name,
188
@DecimalMin("0.01") BigDecimal price) {
189
this.name = name;
190
this.price = price;
191
}
192
}
193
194
// 3. Cross-parameter validation
195
@Target({METHOD, CONSTRUCTOR})
196
@Retention(RUNTIME)
197
@Constraint(validatedBy = {DateRangeValidator.class})
198
public @interface ValidDateRange {
199
String message() default "End date must be after start date";
200
Class<?>[] groups() default {};
201
Class<? extends Payload>[] payload() default {};
202
}
203
204
@SupportedValidationTarget(ValidationTarget.PARAMETERS)
205
public class DateRangeValidator implements ConstraintValidator<ValidDateRange, Object[]> {
206
@Override
207
public boolean isValid(Object[] parameters, ConstraintValidatorContext context) {
208
if (parameters.length != 2) {
209
return false;
210
}
211
212
LocalDate startDate = (LocalDate) parameters[0];
213
LocalDate endDate = (LocalDate) parameters[1];
214
215
if (startDate == null || endDate == null) {
216
return true; // Let @NotNull handle null values
217
}
218
219
return endDate.isAfter(startDate);
220
}
221
}
222
223
// Usage of cross-parameter validation
224
public class BookingService {
225
@ValidDateRange
226
public Booking createBooking(
227
@NotNull LocalDate startDate,
228
@NotNull LocalDate endDate,
229
@NotNull String guestName) {
230
return new Booking(startDate, endDate, guestName);
231
}
232
}
233
234
// 4. Manual validation using ExecutableValidator
235
public class ValidationExample {
236
private Validator validator;
237
private ExecutableValidator executableValidator;
238
239
public ValidationExample() {
240
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
241
this.validator = factory.getValidator();
242
this.executableValidator = validator.forExecutables();
243
}
244
245
public void validateMethodCall() throws Exception {
246
UserService userService = new UserService();
247
Method createUserMethod = UserService.class.getMethod(
248
"createUser", String.class, int.class, String.class);
249
250
// Validate parameters before method call
251
Object[] parameters = {"", 15, "invalid-email"};
252
Set<ConstraintViolation<UserService>> parameterViolations =
253
executableValidator.validateParameters(
254
userService, createUserMethod, parameters);
255
256
if (!parameterViolations.isEmpty()) {
257
System.out.println("Parameter validation failed:");
258
for (ConstraintViolation<UserService> violation : parameterViolations) {
259
System.out.println(" " + violation.getPropertyPath() + ": " +
260
violation.getMessage());
261
}
262
return;
263
}
264
265
// Call method
266
User result = userService.createUser("Alice", 25, "alice@example.com");
267
268
// Validate return value
269
Set<ConstraintViolation<UserService>> returnValueViolations =
270
executableValidator.validateReturnValue(
271
userService, createUserMethod, result);
272
273
if (!returnValueViolations.isEmpty()) {
274
System.out.println("Return value validation failed:");
275
for (ConstraintViolation<UserService> violation : returnValueViolations) {
276
System.out.println(" " + violation.getMessage());
277
}
278
}
279
}
280
281
public void validateConstructor() throws Exception {
282
Constructor<Product> constructor = Product.class.getConstructor(
283
String.class, BigDecimal.class);
284
285
// Validate constructor parameters
286
Object[] parameters = {"", new BigDecimal("-1.00")};
287
Set<ConstraintViolation<Product>> violations =
288
executableValidator.validateConstructorParameters(constructor, parameters);
289
290
if (!violations.isEmpty()) {
291
System.out.println("Constructor parameter validation failed:");
292
for (ConstraintViolation<Product> violation : violations) {
293
System.out.println(" " + violation.getPropertyPath() + ": " +
294
violation.getMessage());
295
}
296
return;
297
}
298
299
// Create object
300
Product product = constructor.newInstance("Valid Product", new BigDecimal("29.99"));
301
302
// Validate created object
303
Set<ConstraintViolation<Product>> objectViolations =
304
executableValidator.validateConstructorReturnValue(constructor, product);
305
306
if (objectViolations.isEmpty()) {
307
System.out.println("Product created successfully");
308
}
309
}
310
}
311
312
// 5. Configuration at class and method level
313
@ValidateOnExecution(type = {ExecutableType.CONSTRUCTORS, ExecutableType.NON_GETTER_METHODS})
314
public class OrderService {
315
316
// This constructor will be validated (due to class-level annotation)
317
public OrderService(@NotNull String serviceName) {
318
// Constructor logic
319
}
320
321
// This method will be validated (due to class-level annotation)
322
public Order processOrder(@NotNull @Valid Order order) {
323
return order;
324
}
325
326
// Override class-level setting - no validation for this method
327
@ValidateOnExecution(type = ExecutableType.NONE)
328
public void internalMethod(String param) {
329
// Internal method with no validation
330
}
331
332
// This getter will NOT be validated (not included in class-level annotation)
333
public String getServiceName() {
334
return "OrderService";
335
}
336
}
337
```