Java
Fluent Validation
While Bean Validation works well for simple constraints, complex business rules often need programmatic validation. Fluent validation provides a readable, composable approach for complex validation scenarios with better error accumulation and conditional logic.
📋 At a Glance
| Aspect | Details |
|---|---|
| Approach | Programmatic, builder-style validation |
| Benefits | Readable, composable, conditional logic |
| Best For | Complex business rules, cross-entity validation |
| Libraries | Custom, or inspired by FluentValidation (.NET) |
🎯 What You'll Learn
- Fluent validator implementation
- Composable rules with chaining
- Conditional validation based on context
- Error accumulation vs fail-fast
- Integration with Bean Validation
Production Story: The Complex Validation Rules
An insurance application had validation rules too complex for annotations:
JAVA(5 lines)CodeLoading syntax highlighter...
The fix: Fluent validation:
JAVA(16 lines)CodeLoading syntax highlighter...
🔬 Deep Dive
Pattern 1: Basic Fluent Validator
JAVA(154 lines)CodeLoading syntax highlighter...
Pattern 2: Domain-Specific Validator
JAVA(46 lines)CodeLoading syntax highlighter...
Pattern 3: Order Validator with Business Rules
JAVA(97 lines)CodeLoading syntax highlighter...
Pattern 4: Validation Rules Builder
JAVA(101 lines)CodeLoading syntax highlighter...
Pattern 5: Async Validation
JAVA(73 lines)CodeLoading syntax highlighter...
Pattern 6: Integration with Bean Validation
JAVA(54 lines)CodeLoading syntax highlighter...
⚠️ Common Mistakes
Mistake 1: Not Accumulating All Errors
JAVA(13 lines)CodeLoading syntax highlighter...
Mistake 2: Validation with Side Effects
JAVA(10 lines)CodeLoading syntax highlighter...
🐛 Debug This: The Premature Exit
A developer reports: "Our fluent validator only returns the first error even though we're supposed to accumulate all of them!"
JAVA(31 lines)CodeLoading syntax highlighter...
Why does only one error get returned?
✅ Solution:
The bug is the multiple
return errors; statements that exit early after each validation check. This is a fail-fast approach, but the intent was error accumulation.The fix - remove early returns:
JAVA(26 lines)CodeLoading syntax highlighter...
Even better - use fluent validator:
JAVA(9 lines)CodeLoading syntax highlighter...
The lesson: Error accumulation requires checking all rules without early exits. Fluent validation naturally handles this pattern.
💻 Exercises
Exercise 1: Basic Fluent Validator
⭐ Difficulty: Easy | ⏱️ Time: 15 minutes
Task: Create a simple fluent validator with basic methods.
JAVA(5 lines)CodeLoading syntax highlighter...
✅ Solution:
JAVA(60 lines)CodeLoading syntax highlighter...
Exercise 2: Conditional Validation
⭐⭐ Difficulty: Medium | ⏱️ Time: 20 minutes
Task: Add conditional validation to the fluent validator.
JAVA(9 lines)CodeLoading syntax highlighter...
✅ Solution:
JAVA(33 lines)CodeLoading syntax highlighter...
Exercise 3: Nested Object Validation
⭐⭐ Difficulty: Medium | ⏱️ Time: 20 minutes
Task: Add support for validating nested objects and collections.
JAVA(3 lines)CodeLoading syntax highlighter...
✅ Solution:
JAVA(63 lines)CodeLoading syntax highlighter...
Exercise 4: Reusable Validation Rules
⭐⭐⭐ Difficulty: Medium-Hard | ⏱️ Time: 20 minutes
Task: Create composable, reusable validation rules.
JAVA(3 lines)CodeLoading syntax highlighter...
✅ Solution:
JAVA(72 lines)CodeLoading syntax highlighter...
Exercise 5: Validation with Result Type
⭐⭐⭐⭐ Difficulty: Hard | ⏱️ Time: 25 minutes
Task: Integrate fluent validation with the Result pattern.
JAVA(4 lines)CodeLoading syntax highlighter...
✅ Solution:
JAVA(108 lines)CodeLoading syntax highlighter...
📝 Summary
| Approach | Use When |
|---|---|
| Bean Validation | Simple constraints, standard validation |
| Fluent Validation | Complex rules, conditional logic, readability |
| Combined | Bean for simple, fluent for business rules |
| Async Validation | Database checks, external service validation |
📅 Review Schedule for This Article
| Day | Task | Time |
|---|---|---|
| Day 1 | Review fluent vs bean validation decision table | 5 min |
| Day 3 | Redo Exercise 1 (Basic Fluent Validator) | 15 min |
| Day 7 | Redo Exercise 3 (Nested Object Validation) | 20 min |
| Day 14 | Redo Debug This (Premature Exit) | 15 min |
| Day 30 | Identify complex validation in your codebase to refactor | 20 min |
Next: [Part 19: Understanding Legacy Code]