A flexible Java 17 validation framework using Spring AOP that allows custom validation logic through configurable handler classes.
Value Checker is an advanced validation library that extends beyond simple parameter checks. It provides a flexible framework where you can define custom validation handlers and chain multiple validation checks together using Spring Expression Language (SpEL) for parameter extraction. This is the Java 17 version with updated dependencies and modern Java features.
- Custom validation handlers: Define your own validation logic by implementing
IValueCheckerHandler - SpEL integration: Use Spring Expression Language to extract and pass parameters to validators
- Multiple validation chains: Apply multiple validators to a single method
- Thread-safe context:
ValueCheckerReentrantThreadLocalfor maintaining validation state - Method reflection caching: Efficient method lookup and caching for performance
- Spring Boot 3.x integration: Seamless integration with latest Spring Boot applications
- Java 17 performance: Leverages modern JVM optimizations and language features
- Java 17
- Spring Boot 3.5.5 (AOP)
- Apache Commons Lang3 & Collections
- Lombok
<dependency>
<groupId>com.goody.utils</groupId>
<artifactId>value-checker-java-17</artifactId>
<version>1.0.0</version>
</dependency>@SpringBootApplication
@EnableAspectJAutoProxy
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}@Service
public class UserValidationHandler implements IValueCheckerHandler {
public void validateUser(Long userId, String username) {
if (userId == null || userId <= 0) {
throw new ValueIllegalException("Invalid user ID");
}
if (username == null || username.trim().isEmpty()) {
throw new ValueIllegalException("Invalid username");
}
// Custom validation logic here
}
public void validateAge(Integer age) {
if (age == null || age < 0 || age > 150) {
throw new ValueIllegalException("Invalid age");
}
}
}@Service
public class UserService {
@ValueCheckers(checkers = {
@ValueCheckers.ValueChecker(
method = "validateUser",
keys = {"#userId", "#username"},
handler = UserValidationHandler.class
),
@ValueCheckers.ValueChecker(
method = "validateAge",
keys = "#user.age",
handler = UserValidationHandler.class
)
})
public void createUser(Long userId, String username, User user) {
// Method implementation
// Validation happens automatically before execution
}
}The main annotation that enables validation for a method:
@ValueCheckers(checkers = {
@ValueCheckers.ValueChecker(
method = "validationMethodName", // Method name in handler
keys = {"#param1", "#param2"}, // SpEL expressions for parameters
handler = YourHandlerClass.class // Handler class
)
})Each @ValueChecker supports:
- handler: Class implementing
IValueCheckerHandler - method: Method name to invoke (default: "verify")
- keys: String array of SpEL expressions to extract parameters
Marker interface for validation handlers. All validation handlers must implement this interface:
public interface IValueCheckerHandler {
// Your validation methods
}Extract parameters using Spring Expression Language:
"#paramName"- Direct parameter"#object.property"- Object property"#object.method()"- Method call result{"#param1", "#param2"}- Multiple parameters
@ValueCheckers(checkers = {
@ValueCheckers.ValueChecker(
method = "validateId",
keys = "#id",
handler = ValidationHandler.class
)
})
public void processUser(Long id, String name) {
// Validation happens before method execution
}@ValueCheckers(checkers = {
@ValueCheckers.ValueChecker(
method = "validateUserData",
keys = {"#user.id", "#user.name"},
handler = UserValidationHandler.class
)
})
public void updateUser(User user) {
// Validates user.getId() and user.getName()
}@ValueCheckers(checkers = {
@ValueCheckers.ValueChecker(method = "validateId", keys = "#id", handler = IdValidator.class),
@ValueCheckers.ValueChecker(method = "validateName", keys = "#name", handler = NameValidator.class),
@ValueCheckers.ValueChecker(method = "validateBusiness", keys = {"#id", "#name"}, handler = BusinessValidator.class)
})
public void complexValidation(Long id, String name) {
// Multiple validators run in sequence
}@Service
public class ContextAwareValidator implements IValueCheckerHandler {
public void validateWithContext(String value) {
// Store value in thread-local context
ValueCheckerReentrantThreadLocal.getOrDefault(String.class, value);
// Use context in validation logic
String contextValue = ValueCheckerReentrantThreadLocal.getOrDefault(String.class, "");
if (!contextValue.equals(value)) {
throw new ValueIllegalException("Context validation failed");
}
}
}All validation failures should throw ValueIllegalException:
public void validateUser(String username) {
if (username == null || username.trim().isEmpty()) {
throw new ValueIllegalException("Username cannot be empty");
}
}- Method caching: Reflection results are cached for improved performance
- Bean lookup optimization: Handler instances are cached by Spring
- Thread-local context: Reentrant thread-local storage for complex validations
- Java 17 optimizations: Benefits from modern JVM performance improvements
Handlers are automatically registered with uncapitalized class names:
UserValidationHandler→ bean name:userValidationHandlerOrderValidator→ bean name:orderValidator
The framework supports nested validation calls through ValueCheckerReentrantThreadLocal, allowing complex validation
scenarios where one validator may call another method with validation.
This version takes advantage of:
- Performance improvements in Java 17 JVM
- Updated Spring Boot 3.x with modern Spring features
- Enhanced reflection performance for method caching
- Improved garbage collection for better application performance
- Modern language features for cleaner, more maintainable code
# Compile the project
mvn clean compile
# Run tests
mvn test
# Package the jar
mvn package
# Install to local repository
mvn installIf migrating from the Java 8 version:
- Update Java version to 17+
- Update Spring Boot to 3.x
- Verify SpEL expressions work with new Spring version
- Update dependency versions as shown in pom.xml
- No code changes required - the API remains the same
- Keep handlers focused: Each handler should have a single responsibility
- Use meaningful method names: Method names should clearly indicate what they validate
- Leverage SpEL: Use SpEL expressions to extract exactly what you need
- Handle exceptions properly: Always throw
ValueIllegalExceptionfor validation failures - Consider performance: Complex SpEL expressions may impact performance
- Utilize Java 17 features: Take advantage of records, pattern matching, and other modern features in your handlers
This project is licensed under the MIT License.
- Goody - Initial work - Version 1.0, 2022/05/05