CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-jakarta-validation--jakarta-validation-api

Jakarta Validation API defines a metadata model and API for JavaBean and method validation

Pending
Overview
Eval results
Files

method-validation.mddocs/

Method Validation

Validation support for method parameters, return values, and constructor parameters with cross-parameter constraint capabilities and executable validation configuration.

Capabilities

Executable Validator

Interface for validating method and constructor parameters and return values.

/**
 * Validates parameters and return values of methods and constructors
 * Obtained from Validator.forExecutables()
 */
interface ExecutableValidator {
    /**
     * Validate method parameters
     * @param object instance on which the method is invoked (null for static methods)
     * @param method method to validate parameters for
     * @param parameterValues parameter values to validate
     * @param groups validation groups to apply
     * @return set of constraint violations
     */
    <T> Set<ConstraintViolation<T>> validateParameters(
        T object, Method method, Object[] parameterValues, Class<?>... groups);
    
    /**
     * Validate method return value
     * @param object instance on which the method was invoked (null for static methods)
     * @param method method to validate return value for
     * @param returnValue return value to validate
     * @param groups validation groups to apply
     * @return set of constraint violations
     */
    <T> Set<ConstraintViolation<T>> validateReturnValue(
        T object, Method method, Object returnValue, Class<?>... groups);
    
    /**
     * Validate constructor parameters
     * @param constructor constructor to validate parameters for
     * @param parameterValues parameter values to validate
     * @param groups validation groups to apply
     * @return set of constraint violations
     */
    <T> Set<ConstraintViolation<T>> validateConstructorParameters(
        Constructor<? extends T> constructor, Object[] parameterValues, Class<?>... groups);
    
    /**
     * Validate constructor return value (the created object)
     * @param constructor constructor that created the object
     * @param createdObject the created object to validate
     * @param groups validation groups to apply
     * @return set of constraint violations
     */
    <T> Set<ConstraintViolation<T>> validateConstructorReturnValue(
        Constructor<? extends T> constructor, T createdObject, Class<?>... groups);
}

Executable Validation Configuration

Enums and annotations for configuring when executable validation occurs.

/**
 * Defines the types of executables targeted by an operation
 */
enum ExecutableType {
    /** No executable validation */
    NONE,
    
    /** Implicit configuration (provider-specific) */
    IMPLICIT,
    
    /** All constructors */
    CONSTRUCTORS,
    
    /** All methods except getters */
    NON_GETTER_METHODS,
    
    /** Getter methods only */
    GETTER_METHODS,
    
    /** All executables (constructors and methods) */
    ALL
}

/**
 * Controls executable validation on methods and constructors
 * Can be applied to types, methods, and constructors
 */
@Target({TYPE, METHOD, CONSTRUCTOR})
@Retention(RUNTIME)
@interface ValidateOnExecution {
    /**
     * Define the type of executables to validate
     * @return array of ExecutableType values
     */
    ExecutableType[] type() default {ExecutableType.IMPLICIT};
}

Cross-Parameter Validation

Support for constraints that validate multiple parameters together.

/**
 * Validation target enum for constraint validators
 */
enum ValidationTarget {
    /** Validate the annotated element */
    ANNOTATED_ELEMENT,
    
    /** Validate the array of parameters (cross-parameter validation) */
    PARAMETERS
}

/**
 * Defines targets a ConstraintValidator can validate
 * Applied to ConstraintValidator implementations
 */
@Target({TYPE})
@Retention(RUNTIME)
@interface SupportedValidationTarget {
    /**
     * Supported validation targets
     * @return array of ValidationTarget values
     */
    ValidationTarget[] value();
}

/**
 * Defines constraint target (parameters vs return value)
 */
enum ConstraintTarget {
    /** Let the validation engine determine the target */
    IMPLICIT,
    
    /** Target the method/constructor parameters */
    PARAMETERS,
    
    /** Target the method return value */
    RETURN_VALUE
}

Usage Examples:

import jakarta.validation.*;
import jakarta.validation.constraints.*;
import jakarta.validation.executable.*;
import java.lang.reflect.Method;

// 1. Method parameter validation
@ValidateOnExecution(type = ExecutableType.NON_GETTER_METHODS)
public class UserService {
    
    public User createUser(
        @NotNull @Size(min = 2, max = 50) String name,
        @Min(18) int age,
        @Email String email) {
        return new User(name, age, email);
    }
    
    @NotNull
    @Valid
    public User updateUser(@NotNull @Valid User user) {
        // Update logic
        return user;
    }
    
    // Getter - validation controlled by ExecutableType.GETTER_METHODS
    @Size(min = 1)
    public List<User> getUsers() {
        return userRepository.findAll();
    }
}

// 2. Constructor validation
public class Product {
    private String name;
    private BigDecimal price;
    
    public Product(
        @NotBlank String name,
        @DecimalMin("0.01") BigDecimal price) {
        this.name = name;
        this.price = price;
    }
}

// 3. Cross-parameter validation
@Target({METHOD, CONSTRUCTOR})
@Retention(RUNTIME)
@Constraint(validatedBy = {DateRangeValidator.class})
public @interface ValidDateRange {
    String message() default "End date must be after start date";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

@SupportedValidationTarget(ValidationTarget.PARAMETERS)
public class DateRangeValidator implements ConstraintValidator<ValidDateRange, Object[]> {
    @Override
    public boolean isValid(Object[] parameters, ConstraintValidatorContext context) {
        if (parameters.length != 2) {
            return false;
        }
        
        LocalDate startDate = (LocalDate) parameters[0];
        LocalDate endDate = (LocalDate) parameters[1];
        
        if (startDate == null || endDate == null) {
            return true; // Let @NotNull handle null values
        }
        
        return endDate.isAfter(startDate);
    }
}

// Usage of cross-parameter validation
public class BookingService {
    @ValidDateRange
    public Booking createBooking(
        @NotNull LocalDate startDate,
        @NotNull LocalDate endDate,
        @NotNull String guestName) {
        return new Booking(startDate, endDate, guestName);
    }
}

// 4. Manual validation using ExecutableValidator
public class ValidationExample {
    private Validator validator;
    private ExecutableValidator executableValidator;
    
    public ValidationExample() {
        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        this.validator = factory.getValidator();
        this.executableValidator = validator.forExecutables();
    }
    
    public void validateMethodCall() throws Exception {
        UserService userService = new UserService();
        Method createUserMethod = UserService.class.getMethod(
            "createUser", String.class, int.class, String.class);
        
        // Validate parameters before method call
        Object[] parameters = {"", 15, "invalid-email"};
        Set<ConstraintViolation<UserService>> parameterViolations = 
            executableValidator.validateParameters(
                userService, createUserMethod, parameters);
        
        if (!parameterViolations.isEmpty()) {
            System.out.println("Parameter validation failed:");
            for (ConstraintViolation<UserService> violation : parameterViolations) {
                System.out.println("  " + violation.getPropertyPath() + ": " + 
                                 violation.getMessage());
            }
            return;
        }
        
        // Call method
        User result = userService.createUser("Alice", 25, "alice@example.com");
        
        // Validate return value
        Set<ConstraintViolation<UserService>> returnValueViolations = 
            executableValidator.validateReturnValue(
                userService, createUserMethod, result);
        
        if (!returnValueViolations.isEmpty()) {
            System.out.println("Return value validation failed:");
            for (ConstraintViolation<UserService> violation : returnValueViolations) {
                System.out.println("  " + violation.getMessage());
            }
        }
    }
    
    public void validateConstructor() throws Exception {
        Constructor<Product> constructor = Product.class.getConstructor(
            String.class, BigDecimal.class);
        
        // Validate constructor parameters
        Object[] parameters = {"", new BigDecimal("-1.00")};
        Set<ConstraintViolation<Product>> violations = 
            executableValidator.validateConstructorParameters(constructor, parameters);
        
        if (!violations.isEmpty()) {
            System.out.println("Constructor parameter validation failed:");
            for (ConstraintViolation<Product> violation : violations) {
                System.out.println("  " + violation.getPropertyPath() + ": " + 
                                 violation.getMessage());
            }
            return;
        }
        
        // Create object
        Product product = constructor.newInstance("Valid Product", new BigDecimal("29.99"));
        
        // Validate created object
        Set<ConstraintViolation<Product>> objectViolations = 
            executableValidator.validateConstructorReturnValue(constructor, product);
        
        if (objectViolations.isEmpty()) {
            System.out.println("Product created successfully");
        }
    }
}

// 5. Configuration at class and method level
@ValidateOnExecution(type = {ExecutableType.CONSTRUCTORS, ExecutableType.NON_GETTER_METHODS})
public class OrderService {
    
    // This constructor will be validated (due to class-level annotation)
    public OrderService(@NotNull String serviceName) {
        // Constructor logic
    }
    
    // This method will be validated (due to class-level annotation)
    public Order processOrder(@NotNull @Valid Order order) {
        return order;
    }
    
    // Override class-level setting - no validation for this method
    @ValidateOnExecution(type = ExecutableType.NONE)
    public void internalMethod(String param) {
        // Internal method with no validation
    }
    
    // This getter will NOT be validated (not included in class-level annotation)
    public String getServiceName() {
        return "OrderService";
    }
}

Install with Tessl CLI

npx tessl i tessl/maven-jakarta-validation--jakarta-validation-api

docs

bean-validation.md

bootstrap-configuration.md

constraints.md

container-validation.md

custom-constraints.md

index.md

metadata.md

method-validation.md

validation-groups.md

tile.json