Skip to content

Commit 75bf461

Browse files
committed
chore: update documentation
Signed-off-by: Marcos Tischer Vallim <tischer@gmail.com>
1 parent 5d900a4 commit 75bf461

21 files changed

+824
-177
lines changed

src/main/java/br/com/fluentvalidator/AbstractValidator.java

Lines changed: 217 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -35,31 +35,97 @@
3535
import br.com.fluentvalidator.rule.RuleProcessorStrategy;
3636
import br.com.fluentvalidator.transform.ValidationResultTransform;
3737

38+
/**
39+
* Abstract base class for implementing fluent validators.
40+
* <p>
41+
* This class provides the core functionality for building and executing validation rules
42+
* in a fluent, chainable manner. It supports both single object and collection validation,
43+
* with configurable processing strategies including fail-fast behavior.
44+
* </p>
45+
* <p>
46+
* Subclasses should implement the {@link Validator#rules()} method to define
47+
* validation rules using the fluent API provided by {@link #ruleFor(Function)} and
48+
* {@link #ruleForEach(Function)} methods.
49+
* </p>
50+
* <p>
51+
* Thread Safety: This class is thread-safe for validation operations. Rule initialization
52+
* is performed using double-checked locking with atomic references to prevent race conditions.
53+
* </p>
54+
*
55+
* @param <T> the type of object being validated
56+
*/
3857
public abstract class AbstractValidator<T> implements Validator<T> {
3958

59+
/**
60+
* List of validation rules to be applied to instances of type T.
61+
* Rules are executed in the order they were added.
62+
*/
4063
private final List<Rule<T>> rules = new LinkedList<>();
4164

65+
/**
66+
* Initializer responsible for thread-safe rule initialization.
67+
*/
4268
private final Initializer<T> initialize;
4369

70+
/**
71+
* Property name to be set in the validation context during validation.
72+
*/
4473
private String property;
4574

75+
/**
76+
* Strategy for processing validation rules. Defaults to standard processing,
77+
* but can be changed to fail-fast mode.
78+
*/
4679
private RuleProcessorStrategy ruleProcessor = RuleProcessorStrategy.getDefault();
4780

81+
/**
82+
* Thread-safe initializer for validation rules.
83+
* <p>
84+
* This inner class ensures that validation rules are initialized exactly once
85+
* per validator instance, even in multi-threaded environments. It uses
86+
* Compare-And-Swap (CAS) operations with double-checked locking to prevent
87+
* race conditions during initialization.
88+
* </p>
89+
*
90+
* @param <T> the type of object being validated
91+
*/
4892
private static class Initializer<T> {
49-
93+
/**
94+
* Atomic reference to track initialization state.
95+
* FALSE indicates not initialized, TRUE indicates initialized.
96+
*/
5097
private final AtomicReference<Boolean> atomicReference = new AtomicReference<>(Boolean.FALSE);
5198

99+
/**
100+
* Reference to the validator instance being initialized.
101+
*/
52102
private final Validator<T> validator;
53103

104+
/**
105+
* Constructs a new initializer for the given validator.
106+
*
107+
* @param validator the validator instance to initialize
108+
*/
54109
Initializer(final Validator<T> validator) {
55110
this.validator = validator;
56111
}
57112

58113
/**
59-
* This method cause Race Condition. We are using Compare And Swap (CAS)
114+
* Initializes the validator rules in a thread-safe manner.
115+
* <p>
116+
* This method uses double-checked locking with atomic operations to ensure
117+
* that the validator's rules are initialized exactly once, even when called
118+
* concurrently from multiple threads. This prevents race conditions that
119+
* could occur during rule initialization.
120+
* </p>
60121
* <p>
61-
* {@link https://en.wikipedia.org/wiki/Race_condition}
62-
* {@link https://en.wikipedia.org/wiki/Compare-and-swap}
122+
* The implementation follows the Compare-And-Swap (CAS) pattern for
123+
* lock-free programming where possible, falling back to synchronized
124+
* blocks only when necessary.
125+
* </p>
126+
*
127+
* @see <a href="https://en.wikipedia.org/wiki/Race_condition">Race Condition</a>
128+
* @see <a href="https://en.wikipedia.org/wiki/Compare-and-swap">Compare-and-swap</a>
63129
*/
64130
public void init() {
65131
if (isNotInitialized()) {
@@ -74,50 +140,102 @@ public void init() {
74140
}
75141
}
76142

143+
/**
144+
* Checks if the validator has not been initialized yet.
145+
*
146+
* @return true if the validator is not initialized, false otherwise
147+
*/
77148
private boolean isNotInitialized() {
78149
return Boolean.FALSE.equals(atomicReference.get());
79150
}
80151

81152
}
82153

154+
/**
155+
* Constructs a new AbstractValidator instance.
156+
* <p>
157+
* Initializes the validator with default settings and creates
158+
* the thread-safe initializer for rule setup.
159+
* </p>
160+
*/
83161
protected AbstractValidator() {
84162
this.initialize = new Initializer<>(this);
85163
}
86164

87165
/**
88-
* {@link #failFastRule() AbstractValidator}
166+
* Configures the validator to use fail-fast rule processing.
167+
* <p>
168+
* When fail-fast mode is enabled, validation will stop at the first
169+
* rule failure instead of continuing to evaluate all rules. This can
170+
* improve performance when early validation failure is acceptable.
171+
* </p>
172+
*
173+
* @see RuleProcessorStrategy#getFailFast()
89174
*/
90175
@Override
91176
public void failFastRule() {
92177
this.ruleProcessor = RuleProcessorStrategy.getFailFast();
93178
}
94179

95180
/**
96-
* {@link #getCounter() AbstractValidator}
181+
* Gets the current validation counter from the processor context.
182+
* <p>
183+
* The counter tracks the number of validation operations or rules
184+
* that have been processed. This can be useful for debugging,
185+
* monitoring, or performance analysis.
186+
* </p>
187+
*
188+
* @return the current counter value, or null if no counter is available
97189
*/
98190
@Override
99191
public Integer getCounter() {
100192
return ProcessorContext.get().get();
101193
}
102194

103195
/**
104-
* {@link #setPropertyOnContext(String) AbstractValidator }
196+
* Sets a property name to be used in the validation context.
197+
* <p>
198+
* This property name will be associated with the validated object
199+
* in the validation context, allowing rules to access contextual
200+
* information during validation.
201+
* </p>
202+
*
203+
* @param property the property name to set in the validation context
105204
*/
106205
@Override
107206
public void setPropertyOnContext(final String property) {
108207
this.property = property;
109208
}
110209

111210
/**
112-
* {@link #getPropertyOnContext(String, Class) AbstractValidator }
211+
* Retrieves a property value from the validation context.
212+
* <p>
213+
* This method allows access to contextual information that was
214+
* previously stored in the validation context, enabling rules
215+
* to make decisions based on broader validation state.
216+
* </p>
217+
*
218+
* @param <P> the type of the property value
219+
* @param property the name of the property to retrieve
220+
* @param clazz the class type of the property value
221+
* @return the property value cast to the specified type, or null if not found
113222
*/
114223
@Override
115224
public <P> P getPropertyOnContext(final String property, final Class<P> clazz) {
116225
return ValidationContext.get().getProperty(property, clazz);
117226
}
118227

119228
/**
120-
* {@link #validate(Object) AbstractValidator }
229+
* Validates a single instance and returns the validation result.
230+
* <p>
231+
* This method processes the given instance through all configured
232+
* validation rules and returns a comprehensive result containing
233+
* any validation errors or success indicators.
234+
* </p>
235+
*
236+
* @param instance the object instance to validate
237+
* @return a ValidationResult containing the outcome of validation
238+
* @throws IllegalArgumentException if the instance is null and null values are not supported
121239
*/
122240
@Override
123241
public ValidationResult validate(final T instance) {
@@ -126,31 +244,69 @@ public ValidationResult validate(final T instance) {
126244
}
127245

128246
/**
129-
* {@link #validate(Object, ValidationResultTransform) AbstractValidator}
247+
* Validates a single instance and transforms the result using the provided transformer.
248+
* <p>
249+
* This method combines validation with result transformation in a single operation,
250+
* allowing for custom result formats or processing without intermediate objects.
251+
* </p>
252+
*
253+
* @param <E> the type of the transformed result
254+
* @param instance the object instance to validate
255+
* @param resultTransform the transformer to apply to the validation result
256+
* @return the transformed validation result
257+
* @throws IllegalArgumentException if the instance is null and null values are not supported
258+
* @throws NullPointerException if resultTransform is null
130259
*/
131260
@Override
132261
public <E> E validate(final T instance, final ValidationResultTransform<E> resultTransform) {
133262
return resultTransform.transform(validate(instance));
134263
}
135264

136265
/**
137-
* {@link #validate(Collection) AbstractValidator}
266+
* Validates a collection of instances and returns a list of validation results.
267+
* <p>
268+
* Each instance in the collection is validated independently, and the results
269+
* are collected into an unmodifiable list. The order of results corresponds
270+
* to the order of instances in the input collection.
271+
* </p>
272+
*
273+
* @param instances the collection of instances to validate
274+
* @return an unmodifiable list of ValidationResult objects, one for each input instance
275+
* @throws NullPointerException if the instances collection is null
138276
*/
139277
@Override
140278
public List<ValidationResult> validate(final Collection<T> instances) {
141279
return Collections.unmodifiableList(instances.stream().map(this::validate).collect(Collectors.toList()));
142280
}
143281

144282
/**
145-
* {@link #validate(Collection, ValidationResultTransform) AbstractValidator}
283+
* Validates a collection of instances and transforms each result using the provided transformer.
284+
* <p>
285+
* This method combines collection validation with result transformation,
286+
* applying the transformer to each individual validation result.
287+
* </p>
288+
*
289+
* @param <E> the type of the transformed results
290+
* @param instances the collection of instances to validate
291+
* @param resultTransform the transformer to apply to each validation result
292+
* @return an unmodifiable list of transformed validation results
293+
* @throws NullPointerException if instances or resultTransform is null
146294
*/
147295
@Override
148296
public <E> List<E> validate(final Collection<T> instances, final ValidationResultTransform<E> resultTransform) {
149297
return Collections.unmodifiableList(instances.stream().map(instance -> this.validate(instance, resultTransform)).collect(Collectors.toList()));
150298
}
151299

152300
/**
153-
* {@link #apply(Object) AbstractValidator}
301+
* Applies validation rules to an instance and returns a boolean result.
302+
* <p>
303+
* This method is typically called internally during the validation process.
304+
* It ensures rules are initialized, sets up the validation context, and
305+
* processes all rules against the given instance.
306+
* </p>
307+
*
308+
* @param instance the object instance to validate
309+
* @return true if all validation rules pass, false if any rule fails
154310
*/
155311
@Override
156312
public boolean apply(final T instance) {
@@ -160,7 +316,17 @@ public boolean apply(final T instance) {
160316
}
161317

162318
/**
163-
* {@link #ruleFor(Function) AbstractValidator}
319+
* Creates a validation rule for a specific property of the validated object.
320+
* <p>
321+
* This method starts a fluent chain for defining validation rules that apply
322+
* to a property extracted from the validated object using the provided function.
323+
* The property name will be automatically derived from the function if possible.
324+
* </p>
325+
*
326+
* @param <P> the type of the property being validated
327+
* @param function a function that extracts the property value from the validated object
328+
* @return a RuleBuilderProperty for chaining additional validation constraints
329+
* @throws NullPointerException if function is null
164330
*/
165331
@Override
166332
public <P> RuleBuilderProperty<T, P> ruleFor(final Function<T, P> function) {
@@ -170,7 +336,19 @@ public <P> RuleBuilderProperty<T, P> ruleFor(final Function<T, P> function) {
170336
}
171337

172338
/**
173-
* {@link #ruleFor(String, Function) AbstractValidator}
339+
* Creates a validation rule for a named property of the validated object.
340+
* <p>
341+
* This method starts a fluent chain for defining validation rules that apply
342+
* to a property extracted from the validated object. The field name is explicitly
343+
* provided and will be used in error messages and validation context.
344+
* </p>
345+
*
346+
* @param <P> the type of the property being validated
347+
* @param fieldName the name of the field being validated (used in error messages)
348+
* @param function a function that extracts the property value from the validated object
349+
* @return a RuleBuilderProperty for chaining additional validation constraints
350+
* @throws NullPointerException if fieldName or function is null
351+
* @throws IllegalArgumentException if fieldName is empty
174352
*/
175353
@Override
176354
public <P> RuleBuilderProperty<T, P> ruleFor(final String fieldName, final Function<T, P> function) {
@@ -180,7 +358,19 @@ public <P> RuleBuilderProperty<T, P> ruleFor(final String fieldName, final Funct
180358
}
181359

182360
/**
183-
* {@link #ruleForEach(String, Function) AbstractValidator}
361+
* Creates validation rules for each element in a collection property.
362+
* <p>
363+
* This method starts a fluent chain for defining validation rules that apply
364+
* to each element of a collection extracted from the validated object.
365+
* The field name is explicitly provided for error reporting.
366+
* </p>
367+
*
368+
* @param <P> the type of elements in the collection being validated
369+
* @param fieldName the name of the collection field being validated
370+
* @param function a function that extracts the collection from the validated object
371+
* @return a RuleBuilderCollection for chaining additional validation constraints
372+
* @throws NullPointerException if fieldName or function is null
373+
* @throws IllegalArgumentException if fieldName is empty
184374
*/
185375
@Override
186376
public <P> RuleBuilderCollection<T, P> ruleForEach(final String fieldName, final Function<T, Collection<P>> function) {
@@ -190,7 +380,17 @@ public <P> RuleBuilderCollection<T, P> ruleForEach(final String fieldName, final
190380
}
191381

192382
/**
193-
* {@link #ruleForEach(Function) AbstractValidator}
383+
* Creates validation rules for each element in a collection property.
384+
* <p>
385+
* This method starts a fluent chain for defining validation rules that apply
386+
* to each element of a collection extracted from the validated object.
387+
* The field name will be automatically derived from the function if possible.
388+
* </p>
389+
*
390+
* @param <P> the type of elements in the collection being validated
391+
* @param function a function that extracts the collection from the validated object
392+
* @return a RuleBuilderCollection for chaining additional validation constraints
393+
* @throws NullPointerException if function is null
194394
*/
195395
@Override
196396
public <P> RuleBuilderCollection<T, P> ruleForEach(final Function<T, Collection<P>> function) {

0 commit comments

Comments
 (0)