Skip to content

Commit

Permalink
Merge pull request #70 from SentryMan/doc
Browse files Browse the repository at this point in the history
Start on Javadocs
  • Loading branch information
rob-bygrave authored Jul 10, 2023
2 parents e04978a + 6a9f257 commit 2298fab
Show file tree
Hide file tree
Showing 20 changed files with 217 additions and 88 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public class AOPMethodValidator implements AspectProvider<ValidateMethod> {
private final Map<Method, MethodAdapterProvider> paramAdapters;

public AOPMethodValidator(Validator validator, List<MethodAdapterProvider> adapterProviders) {
this.ctx = (ValidationContext) validator;
this.ctx = validator.getContext();
this.paramAdapters =
adapterProviders.stream().collect(toMap(MethodAdapterProvider::provide, p -> p));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package io.avaje.validation;

/**
* Specify types to generate Valid Adapters for. Use if you can't place a @Valid annotation on an
* external type.
* Specify external types for which to generate Valid Adapters. Use when you can't place a @Valid
* annotation on an external type (such as a mvn/gradle dependency).
*/
public @interface ImportValidPojo {

Expand Down
21 changes: 11 additions & 10 deletions validator/src/main/java/io/avaje/validation/Validator.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ public interface Validator {
void validate(Object any, @Nullable Locale locale, @Nullable Class<?>... groups)
throws ConstraintViolationException;

/** Get the validation context used to create adapters */
ValidationContext getContext();

static Builder builder() {
final var bootstrapService = ServiceLoader.load(Bootstrap.class).iterator();
if (bootstrapService.hasNext()) {
Expand All @@ -48,17 +51,13 @@ interface Builder {
/** Add a AnnotationValidationAdapter to use for the given type. */
<T> Builder add(Class<? extends Annotation> type, ValidationAdapter<T> adapter);

/**
* Lookup ResourceBundles with the given name and for error message interpolation
*
* @param bundleName the name of the bundleFiles
*/
/** Lookup ResourceBundles with the given names for error message interpolation */
Builder addResourceBundles(String... bundleName);

/** Add ResourceBundle for error message interpolation */
/** Add ResourceBundles for error message interpolation */
Builder addResourceBundles(ResourceBundle... bundle);

/** Set Default Locale for this validator, if not set, will use Locale.getDefault() */
/** Set Default Locale for this validator. If not set, will use Locale.getDefault() */
Builder setDefaultLocale(Locale defaultLocale);

/** Adds additional Locales for this validator */
Expand All @@ -74,15 +73,17 @@ interface Builder {
Builder temporalTolerance(Duration temporalTolerance);

/**
* En- or disables the fail fast mode. When fail fast is enabled the validation will stop on the
* Enable/Disable fail fast mode. When fail fast is enabled the validation will stop on the
* first constraint violation detected.
*/
Builder failFast(boolean failFast);

/** Add a AdapterBuilder which provides a ValidationAdapter to use for the given type. */
Builder add(Type type, AdapterBuilder builder);

/** Add a AdapterBuilder which provides a ValidationAdapter to use for the given type. */
/**
* Add a AdapterBuilder which provides a Annotation ValidationAdapter to use for the given type.
*/
Builder add(Class<? extends Annotation> type, AnnotationAdapterBuilder builder);

/** Add a Component which can provide multiple ValidationAdapters and or configuration. */
Expand All @@ -100,7 +101,7 @@ interface Builder {
Validator build();
}

/** Function to build a ValidationAdapter that needs Validator. */
/** Function to build a ValidationAdapter from a Validation Context */
@FunctionalInterface
interface AdapterBuilder {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,33 @@
package io.avaje.validation.adapter;

/**
* Adapter that validates container types.
*
* @param <T> the type we are validating
*/
public abstract class AbstractContainerAdapter<T> implements ValidationAdapter<T> {

protected final ValidationAdapter<T> starterAdapter;
private ValidationAdapter<Object> adapters;
protected final ValidationAdapter<T> initalAdapter;

private ValidationAdapter<Object> multiAdapter;

protected AbstractContainerAdapter(ValidationAdapter<T> starterAdapter) {
this.starterAdapter = starterAdapter;
/** @param initialAdapter initial adapter that can be used to validate the container itself */
protected AbstractContainerAdapter(ValidationAdapter<T> initalAdapter) {
this.initalAdapter = initalAdapter;
}

/**
* Compose the given adapter with the multiAdapter of this AbstractContainerAdapter for validating
* multiple items.
*/
public AbstractContainerAdapter<T> andThenMulti(ValidationAdapter<?> adapter) {
this.adapters =
this.adapters != null
? adapters.andThen((ValidationAdapter<Object>) adapter)
this.multiAdapter =
this.multiAdapter != null
? multiAdapter.andThen((ValidationAdapter<Object>) adapter)
: (ValidationAdapter<Object>) adapter;
return this;
}

/** Execute validations for all items in the given iterable */
protected boolean validateAll(
Iterable<Object> value, ValidationRequest req, String propertyName) {
if (value == null) {
Expand All @@ -28,14 +39,15 @@ protected boolean validateAll(
int index = -1;
for (final var element : value) {
index++;
adapters.validate(element, req, String.valueOf(index));
multiAdapter.validate(element, req, String.valueOf(index));
}
if (propertyName != null) {
req.popPath();
}
return true;
}

/** Execute validations for all items in the given array */
protected boolean validateArray(Object[] value, ValidationRequest req, String propertyName) {
if (value == null) {
return true;
Expand All @@ -46,7 +58,7 @@ protected boolean validateArray(Object[] value, ValidationRequest req, String pr
int index = -1;
for (final Object element : value) {
index++;
adapters.validate(element, req, String.valueOf(index));
multiAdapter.validate(element, req, String.valueOf(index));
}
if (propertyName != null) {
req.popPath();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class ArrayValidationAdapter<T> extends AbstractContainerAdapter<T> {

@Override
public boolean validate(T value, ValidationRequest req, String propertyName) {
if (starterAdapter.validate(value, req, propertyName)) {
if (initalAdapter.validate(value, req, propertyName)) {

return validateArray((Object[]) value, req, propertyName);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class IterableValidationAdapter<T> extends AbstractContainerAdapter<T> {
@Override
@SuppressWarnings("unchecked")
public boolean validate(T value, ValidationRequest req, String propertyName) {
if (starterAdapter.validate(value, req, propertyName)) {
if (initalAdapter.validate(value, req, propertyName)) {
return validateAll((Iterable<Object>) value, req, propertyName);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class MapValidationAdapter<T> extends AbstractContainerAdapter<T> {
public boolean validate(T value, ValidationRequest req, String propertyName) {
final var map = (Map<Object, Object>) value;

if (starterAdapter.validate(value, req, propertyName)) {
if (initalAdapter.validate(value, req, propertyName)) {
if (keys) {
return validateAll(map.keySet(), req, propertyName);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ public boolean validate(T value, ValidationRequest req, String propertyName) {
if (value == null) {
return true;
} else if (value instanceof final Optional o) {
o.ifPresent(v -> starterAdapter.validate((T) v, req, propertyName));
o.ifPresent(v -> initalAdapter.validate((T) v, req, propertyName));
} else if (value instanceof final OptionalInt i) {
i.ifPresent(v -> starterAdapter.validate(((T) (Object) v), req, propertyName));
i.ifPresent(v -> initalAdapter.validate(((T) (Object) v), req, propertyName));
} else if (value instanceof final OptionalLong l) {
l.ifPresent(v -> starterAdapter.validate(((T) (Object) v), req, propertyName));
l.ifPresent(v -> initalAdapter.validate(((T) (Object) v), req, propertyName));
} else if (value instanceof final OptionalDouble d) {
d.ifPresent(v -> starterAdapter.validate(((T) (Object) v), req, propertyName));
d.ifPresent(v -> initalAdapter.validate(((T) (Object) v), req, propertyName));
}
return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,40 +2,90 @@

import java.util.Objects;
import java.util.Set;

@FunctionalInterface
/**
* This interface defines a set of validation methods for validating a value based on specific
* rules. The methods in this interface allow for executing validations, composing validation
* adapters, and checking validation groups.
*
* @param <T> The type of value to be validated
*/
public interface ValidationAdapter<T> {

/** Return true if validation should recurse */
/**
* Execute validations for the given value.
*
* @param value The value to be validated
* @param req The validation request containing group/locale/violation information
* @param propertyName The name of the property being validated
* @return {@code true} if validation should continue, {@code false} otherwise
*/
boolean validate(T value, ValidationRequest req, String propertyName);

/**
* Execute validations for the given value
*
* @param value The value to be validated
* @param req The validation request containing group/locale/violation information
* @return {@code true} if validation should continue, {@code false} otherwise
*/
default boolean validate(T value, ValidationRequest req) {
return validate(value, req, null);
}

/**
* Create an adapter for validating a list of values.
*
* @return The adapter for list validation
*/
default AbstractContainerAdapter<T> list() {

return new IterableValidationAdapter<>(this);
}

/**
* Create an adapter for validating map keys.
*
* @return The adapter for map key validation
*/
default AbstractContainerAdapter<T> mapKeys() {
return new MapValidationAdapter<>(this, true);
}

/**
* Create an adapter for validating map values.
*
* @return The adapter for map value validation
*/
default AbstractContainerAdapter<T> mapValues() {
return new MapValidationAdapter<>(this, false);
}

/**
* Create an adapter for validating an array.
*
* @return The adapter for array validation
*/
default AbstractContainerAdapter<T> array() {
return new ArrayValidationAdapter<>(this);
}

/**
* Create an adapter for validating an optional value.
*
* @return The adapter for optional value validation
*/
default AbstractContainerAdapter<T> optional() {
return new OptionalValidationAdapter<>(this);
}

/**
* Compose this validation adapter with another adapter by applying the validations in sequence.
*
* @param after The validation adapter to be applied after this adapter
* @return The composed validation adapter
* @throws NullPointerException if {@code after} is null
*/
default ValidationAdapter<T> andThen(ValidationAdapter<? super T> after) {
Objects.requireNonNull(after);
Objects.requireNonNull(after, "after cannot be null");
return (value, req, propertyName) -> {
if (validate(value, req, propertyName)) {
return after.validate(value, req, propertyName);
Expand All @@ -45,8 +95,13 @@ default ValidationAdapter<T> andThen(ValidationAdapter<? super T> after) {
}

/**
* Returns true if the validation request groups is empty or matches any of the adapter's
* configured groups
* Check if the validation request groups are empty or match any of the adapter's configured
* groups.
*
* @param adapterGroups The groups configured for this adapter
* @param request The validation request containing the groups to be checked
* @return {@code true} if the groups match or if the validation request groups are empty, {@code
* false} otherwise
*/
default boolean checkGroups(Set<Class<?>> adapterGroups, ValidationRequest request) {
final var requestGroups = request.groups();
Expand Down
Loading

0 comments on commit 2298fab

Please sign in to comment.