diff --git a/validator-inject-plugin/src/main/java/io/avaje/validation/inject/aspect/AOPMethodValidator.java b/validator-inject-plugin/src/main/java/io/avaje/validation/inject/aspect/AOPMethodValidator.java index 97a1c6ee..e6d3d2f0 100644 --- a/validator-inject-plugin/src/main/java/io/avaje/validation/inject/aspect/AOPMethodValidator.java +++ b/validator-inject-plugin/src/main/java/io/avaje/validation/inject/aspect/AOPMethodValidator.java @@ -19,7 +19,7 @@ public class AOPMethodValidator implements AspectProvider { private final Map paramAdapters; public AOPMethodValidator(Validator validator, List adapterProviders) { - this.ctx = (ValidationContext) validator; + this.ctx = validator.getContext(); this.paramAdapters = adapterProviders.stream().collect(toMap(MethodAdapterProvider::provide, p -> p)); } diff --git a/validator/src/main/java/io/avaje/validation/ImportValidPojo.java b/validator/src/main/java/io/avaje/validation/ImportValidPojo.java index c999a3d0..bed721cf 100644 --- a/validator/src/main/java/io/avaje/validation/ImportValidPojo.java +++ b/validator/src/main/java/io/avaje/validation/ImportValidPojo.java @@ -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 { diff --git a/validator/src/main/java/io/avaje/validation/Validator.java b/validator/src/main/java/io/avaje/validation/Validator.java index a01f1c4f..7970b845 100644 --- a/validator/src/main/java/io/avaje/validation/Validator.java +++ b/validator/src/main/java/io/avaje/validation/Validator.java @@ -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()) { @@ -48,17 +51,13 @@ interface Builder { /** Add a AnnotationValidationAdapter to use for the given type. */ Builder add(Class type, ValidationAdapter 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 */ @@ -74,7 +73,7 @@ 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); @@ -82,7 +81,9 @@ interface Builder { /** 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 type, AnnotationAdapterBuilder builder); /** Add a Component which can provide multiple ValidationAdapters and or configuration. */ @@ -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 { diff --git a/validator/src/main/java/io/avaje/validation/adapter/AbstractContainerAdapter.java b/validator/src/main/java/io/avaje/validation/adapter/AbstractContainerAdapter.java index 908eca04..30d4ba51 100644 --- a/validator/src/main/java/io/avaje/validation/adapter/AbstractContainerAdapter.java +++ b/validator/src/main/java/io/avaje/validation/adapter/AbstractContainerAdapter.java @@ -1,22 +1,33 @@ package io.avaje.validation.adapter; - +/** + * Adapter that validates container types. + * + * @param the type we are validating + */ public abstract class AbstractContainerAdapter implements ValidationAdapter { - protected final ValidationAdapter starterAdapter; - private ValidationAdapter adapters; + protected final ValidationAdapter initalAdapter; + + private ValidationAdapter multiAdapter; - protected AbstractContainerAdapter(ValidationAdapter starterAdapter) { - this.starterAdapter = starterAdapter; + /** @param initialAdapter initial adapter that can be used to validate the container itself */ + protected AbstractContainerAdapter(ValidationAdapter initalAdapter) { + this.initalAdapter = initalAdapter; } + /** + * Compose the given adapter with the multiAdapter of this AbstractContainerAdapter for validating + * multiple items. + */ public AbstractContainerAdapter andThenMulti(ValidationAdapter adapter) { - this.adapters = - this.adapters != null - ? adapters.andThen((ValidationAdapter) adapter) + this.multiAdapter = + this.multiAdapter != null + ? multiAdapter.andThen((ValidationAdapter) adapter) : (ValidationAdapter) adapter; return this; } + /** Execute validations for all items in the given iterable */ protected boolean validateAll( Iterable value, ValidationRequest req, String propertyName) { if (value == null) { @@ -28,7 +39,7 @@ 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(); @@ -36,6 +47,7 @@ protected boolean validateAll( 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; @@ -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(); diff --git a/validator/src/main/java/io/avaje/validation/adapter/ArrayValidationAdapter.java b/validator/src/main/java/io/avaje/validation/adapter/ArrayValidationAdapter.java index 73823697..ee5bfb5b 100644 --- a/validator/src/main/java/io/avaje/validation/adapter/ArrayValidationAdapter.java +++ b/validator/src/main/java/io/avaje/validation/adapter/ArrayValidationAdapter.java @@ -8,7 +8,7 @@ class ArrayValidationAdapter extends AbstractContainerAdapter { @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); } diff --git a/validator/src/main/java/io/avaje/validation/adapter/IterableValidationAdapter.java b/validator/src/main/java/io/avaje/validation/adapter/IterableValidationAdapter.java index e8ec8190..17464a8c 100644 --- a/validator/src/main/java/io/avaje/validation/adapter/IterableValidationAdapter.java +++ b/validator/src/main/java/io/avaje/validation/adapter/IterableValidationAdapter.java @@ -9,7 +9,7 @@ class IterableValidationAdapter extends AbstractContainerAdapter { @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) value, req, propertyName); } diff --git a/validator/src/main/java/io/avaje/validation/adapter/MapValidationAdapter.java b/validator/src/main/java/io/avaje/validation/adapter/MapValidationAdapter.java index 14619154..0bef5a43 100644 --- a/validator/src/main/java/io/avaje/validation/adapter/MapValidationAdapter.java +++ b/validator/src/main/java/io/avaje/validation/adapter/MapValidationAdapter.java @@ -16,7 +16,7 @@ class MapValidationAdapter extends AbstractContainerAdapter { public boolean validate(T value, ValidationRequest req, String propertyName) { final var map = (Map) value; - if (starterAdapter.validate(value, req, propertyName)) { + if (initalAdapter.validate(value, req, propertyName)) { if (keys) { return validateAll(map.keySet(), req, propertyName); } diff --git a/validator/src/main/java/io/avaje/validation/adapter/OptionalValidationAdapter.java b/validator/src/main/java/io/avaje/validation/adapter/OptionalValidationAdapter.java index cda8e7b0..3327d9ae 100644 --- a/validator/src/main/java/io/avaje/validation/adapter/OptionalValidationAdapter.java +++ b/validator/src/main/java/io/avaje/validation/adapter/OptionalValidationAdapter.java @@ -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; } diff --git a/validator/src/main/java/io/avaje/validation/adapter/ValidationAdapter.java b/validator/src/main/java/io/avaje/validation/adapter/ValidationAdapter.java index 257b7eeb..11613770 100644 --- a/validator/src/main/java/io/avaje/validation/adapter/ValidationAdapter.java +++ b/validator/src/main/java/io/avaje/validation/adapter/ValidationAdapter.java @@ -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 The type of value to be validated + */ public interface ValidationAdapter { - /** 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 list() { - return new IterableValidationAdapter<>(this); } + /** + * Create an adapter for validating map keys. + * + * @return The adapter for map key validation + */ default AbstractContainerAdapter mapKeys() { return new MapValidationAdapter<>(this, true); } + /** + * Create an adapter for validating map values. + * + * @return The adapter for map value validation + */ default AbstractContainerAdapter mapValues() { return new MapValidationAdapter<>(this, false); } + /** + * Create an adapter for validating an array. + * + * @return The adapter for array validation + */ default AbstractContainerAdapter array() { return new ArrayValidationAdapter<>(this); } + /** + * Create an adapter for validating an optional value. + * + * @return The adapter for optional value validation + */ default AbstractContainerAdapter 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 andThen(ValidationAdapter 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); @@ -45,8 +95,13 @@ default ValidationAdapter andThen(ValidationAdapter 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> adapterGroups, ValidationRequest request) { final var requestGroups = request.groups(); diff --git a/validator/src/main/java/io/avaje/validation/adapter/ValidationContext.java b/validator/src/main/java/io/avaje/validation/adapter/ValidationContext.java index 6c5ec717..49d4b250 100644 --- a/validator/src/main/java/io/avaje/validation/adapter/ValidationContext.java +++ b/validator/src/main/java/io/avaje/validation/adapter/ValidationContext.java @@ -9,29 +9,47 @@ import io.avaje.lang.Nullable; -/** - * Context available when validation adapters are being created. - */ +/** Context used to lookup validation adapters and create validation requests. */ public interface ValidationContext { /** * Return the adapter for the given type. + * + * @param cls The class for which the adapter is requested + * @param The type this adapter validates + * @return The validation adapter for the given type */ ValidationAdapter adapter(Class cls); /** * Return the adapter for the given type. + * + * @param type The type for which the adapter is requested + * @param The type this adapter validates + * @return The validation adapter for the given type */ ValidationAdapter adapter(Type type); /** - * Return the adapter for the given annotation with attributes. + * Return the annotation adapter for the given annotation with attributes. + * + * @param cls The annotation class + * @param attributes The attributes associated with the annotation + * @param The type this adapter validates + * @return The validation adapter for the given annotation with attributes */ ValidationAdapter adapter(Class cls, Map attributes); /** * Return the adapter for the given annotation with attributes. Used for adapters that combine - * multiple annotation adapters + * multiple annotation adapters. + * + * @param cls The class representing the annotation type + * @param groups The validation groups associated with the annotation + * @param message The error message associated with the annotation + * @param attributes The attributes associated with the annotation + * @param The type this adapter validates + * @return The validation adapter for the given annotation with attributes */ ValidationAdapter adapter( Class cls, @@ -40,56 +58,98 @@ ValidationAdapter adapter( Map attributes); /** - * Return A no-op adapter + * Return a no-op adapter. + * + * @param The type this adapter validates + * @return The no-op validation adapter */ ValidationAdapter noop(); /** - * Create a message object using the annotation attribute "message"; + * Create a message object using the annotation attribute "message". + * + * @param attributes The attributes associated with the annotation + * @return The message object */ Message message(Map attributes); - /** Create a message object using the given string and annotation attributes */ + /** + * Create a message object using the given string. + * + * @param message The error message + * @param attributes The attributes associated with the annotation + * @return The message object created using the given string and annotation attributes + */ Message message(String message, Map attributes); + /** + * Create a validation request with the specified locale and groups. + * + * @param locale The locale for the validation request + * @param groups The validation groups for the request + * @return The validation request with the specified locale and groups + */ ValidationRequest request(@Nullable Locale locale, List> groups); + /** Represents a message object used in error message interpolation. */ interface Message { + /** + * Get the template for the message. A lookup will be performed on the configured resource + * bundles to interpolate the message + * + * @return The template for the message + */ String template(); + /** + * Get the annotation attributes associated with the message. + * + * @return The annotation attributes associated with the message + */ Map attributes(); + /** + * Get the lookup key for the message. + * + * @return The template for the message + a unique number for deduplication purposes. + */ String lookupkey(); } - /** - * Factory for creating a ValidationAdapter for a given type. - */ + /** Factory for creating a ValidationAdapter for a given type. */ @FunctionalInterface interface AdapterFactory { /** * Create and return a ValidationAdapter given the type and annotations or return null. + * Returning null means that the adapter could be created by another factory. * - *

Returning null means that the adapter could be created by another factory. + * @param type The type for which the adapter is being created + * @param ctx The validation context + * @return The created validation adapter or null if not applicable */ ValidationAdapter create(Type type, ValidationContext ctx); } - /** - * Factory for creating a ValidationAdapter for a given annotation. - */ + /** Factory for creating an Annotation Adapter for a given annotation. */ @FunctionalInterface interface AnnotationFactory { /** * Create and return a ValidationAdapter given the type and annotations or return null. + * Returning null means that the adapter could be created by another factory. * - *

Returning null means that the adapter could be created by another factory. + * @param annotationType The annotation type for which the adapter is being created + * @param ctx The validation context + * @param groups The validation groups associated with the annotation + * @param attributes The attributes associated with the annotation + * @return The created validation adapter or null if not applicable */ ValidationAdapter create( - Class annotationType, ValidationContext ctx, Set> groups, Map attributes); + Class annotationType, + ValidationContext ctx, + Set> groups, + Map attributes); } - } diff --git a/validator/src/main/java/io/avaje/validation/adapter/ValidationRequest.java b/validator/src/main/java/io/avaje/validation/adapter/ValidationRequest.java index e3e12aad..20768f86 100644 --- a/validator/src/main/java/io/avaje/validation/adapter/ValidationRequest.java +++ b/validator/src/main/java/io/avaje/validation/adapter/ValidationRequest.java @@ -2,9 +2,9 @@ import java.util.List; -/** - * A validation request. - */ +import io.avaje.validation.ConstraintViolationException; + +/** A validation request. */ public interface ValidationRequest { /** The groups tied to this ValidationRequest */ @@ -18,19 +18,12 @@ public interface ValidationRequest { */ void addViolation(ValidationContext.Message message, String propertyName); - /** - * Push the nested path. - */ + /** Push the nested property path. */ void pushPath(String path); - /** - * Pop the nested path. - */ + /** Pop the nested property path. */ void popPath(); - /** - * Throw ConstraintViolationException if there are violations for this request. - */ - void throwWithViolations(); - + /** Throw ConstraintViolationException if there are violations in this request. */ + void throwWithViolations() throws ConstraintViolationException; } diff --git a/validator/src/main/java/io/avaje/validation/core/BasicMessageInterpolator.java b/validator/src/main/java/io/avaje/validation/core/BasicMessageInterpolator.java index f2c78930..ec165214 100644 --- a/validator/src/main/java/io/avaje/validation/core/BasicMessageInterpolator.java +++ b/validator/src/main/java/io/avaje/validation/core/BasicMessageInterpolator.java @@ -10,8 +10,6 @@ final class BasicMessageInterpolator implements MessageInterpolator { public String interpolate(String template, Map attributes) { String result = template; for (final Map.Entry entry : attributes.entrySet()) { - // needs work here to improve functionality, support local specific value formatting eg - // Duration Max result = result.replace('{' + entry.getKey() + '}', String.valueOf(entry.getValue())); } // return the message diff --git a/validator/src/main/java/io/avaje/validation/core/CoreAdapterBuilder.java b/validator/src/main/java/io/avaje/validation/core/CoreAdapterBuilder.java index 482c213a..ad169777 100644 --- a/validator/src/main/java/io/avaje/validation/core/CoreAdapterBuilder.java +++ b/validator/src/main/java/io/avaje/validation/core/CoreAdapterBuilder.java @@ -1,7 +1,5 @@ package io.avaje.validation.core; -import static java.util.stream.Collectors.toUnmodifiableSet; - import java.lang.annotation.Annotation; import java.lang.reflect.Type; import java.time.Clock; diff --git a/validator/src/main/java/io/avaje/validation/core/DValidator.java b/validator/src/main/java/io/avaje/validation/core/DValidator.java index e15d7c30..c35c054f 100644 --- a/validator/src/main/java/io/avaje/validation/core/DValidator.java +++ b/validator/src/main/java/io/avaje/validation/core/DValidator.java @@ -37,7 +37,7 @@ final class DValidator implements Validator, ValidationContext { private final Map> typeCache = new ConcurrentHashMap<>(); private final MessageInterpolator interpolator; private final LocaleResolver localeResolver; - private final DTemplateLookup templateLookup; + private final TemplateLookup templateLookup; private final Map messageCache = new ConcurrentHashMap<>(); private final boolean failfast; @@ -53,8 +53,8 @@ final class DValidator implements Validator, ValidationContext { boolean failfast) { this.localeResolver = localeResolver; final var defaultResourceBundle = - new DResourceBundleManager(bundleNames, bundles, localeResolver); - this.templateLookup = new DTemplateLookup(defaultResourceBundle); + new ResourceBundleManager(bundleNames, bundles, localeResolver); + this.templateLookup = new TemplateLookup(defaultResourceBundle); this.interpolator = interpolator; this.builder = new CoreAdapterBuilder( @@ -78,6 +78,11 @@ public void validate(Object any, @Nullable Locale locale, @Nullable Class... type.validate(any, locale, List.of(groups)); } + @Override + public ValidationContext getContext() { + return this; + } + private ValidationType type(Class cls) { return typeWithCache(cls); } diff --git a/validator/src/main/java/io/avaje/validation/core/LocaleResolver.java b/validator/src/main/java/io/avaje/validation/core/LocaleResolver.java index f58fa5bd..e71abca4 100644 --- a/validator/src/main/java/io/avaje/validation/core/LocaleResolver.java +++ b/validator/src/main/java/io/avaje/validation/core/LocaleResolver.java @@ -5,7 +5,7 @@ import java.util.Locale; import java.util.Set; -public interface LocaleResolver { +interface LocaleResolver { Locale resolve(@Nullable Locale requestLocale); Locale defaultLocale(); diff --git a/validator/src/main/java/io/avaje/validation/core/DResourceBundleManager.java b/validator/src/main/java/io/avaje/validation/core/ResourceBundleManager.java similarity index 90% rename from validator/src/main/java/io/avaje/validation/core/DResourceBundleManager.java rename to validator/src/main/java/io/avaje/validation/core/ResourceBundleManager.java index 6371a187..7180fc1b 100644 --- a/validator/src/main/java/io/avaje/validation/core/DResourceBundleManager.java +++ b/validator/src/main/java/io/avaje/validation/core/ResourceBundleManager.java @@ -11,13 +11,13 @@ import io.avaje.lang.Nullable; -final class DResourceBundleManager { +final class ResourceBundleManager { private final Map> map = new HashMap<>(); private static final List EMPTY = List.of(); private static final String DEFAULT_BUNDLE = "io.avaje.validation.Messages"; - DResourceBundleManager(List names, List providedBundles, LocaleResolver localeResolver) { + ResourceBundleManager(List names, List providedBundles, LocaleResolver localeResolver) { for (final var name : names) { addBundle(name, localeResolver.defaultLocale()); for (final Locale locale : localeResolver.otherLocales()) { diff --git a/validator/src/main/java/io/avaje/validation/core/DTemplateLookup.java b/validator/src/main/java/io/avaje/validation/core/TemplateLookup.java similarity index 83% rename from validator/src/main/java/io/avaje/validation/core/DTemplateLookup.java rename to validator/src/main/java/io/avaje/validation/core/TemplateLookup.java index 5cf3e92c..6a4d2c7e 100644 --- a/validator/src/main/java/io/avaje/validation/core/DTemplateLookup.java +++ b/validator/src/main/java/io/avaje/validation/core/TemplateLookup.java @@ -2,10 +2,10 @@ import java.util.Locale; -final class DTemplateLookup { - private final DResourceBundleManager bundleManager; +final class TemplateLookup { + private final ResourceBundleManager bundleManager; - DTemplateLookup(DResourceBundleManager defaultBundle) { + TemplateLookup(ResourceBundleManager defaultBundle) { this.bundleManager = defaultBundle; } diff --git a/validator/src/main/java/io/avaje/validation/spi/Bootstrap.java b/validator/src/main/java/io/avaje/validation/spi/Bootstrap.java index bf09b18e..16dbbf81 100644 --- a/validator/src/main/java/io/avaje/validation/spi/Bootstrap.java +++ b/validator/src/main/java/io/avaje/validation/spi/Bootstrap.java @@ -10,7 +10,6 @@ public interface Bootstrap { /** * Create and return a Builder (with an underling SPI implementation). *

- * The default implementation uses Jackson Core. */ Validator.Builder builder(); } diff --git a/validator/src/main/java/io/avaje/validation/spi/MessageInterpolator.java b/validator/src/main/java/io/avaje/validation/spi/MessageInterpolator.java index 93061e01..42b66785 100644 --- a/validator/src/main/java/io/avaje/validation/spi/MessageInterpolator.java +++ b/validator/src/main/java/io/avaje/validation/spi/MessageInterpolator.java @@ -2,7 +2,15 @@ import java.util.Map; +/** Reads an Annotation's attributes and the message template and interpolates the message */ public interface MessageInterpolator { + /** + * Interpolate the given message with the annotation attributes + * + * @param template template + * @param attributes + * @return the interpolated validation error message + */ String interpolate(String template, Map attributes); } diff --git a/validator/src/test/java/io/avaje/validation/core/DTemplateLookupTest.java b/validator/src/test/java/io/avaje/validation/core/TemplateLookupTest.java similarity index 77% rename from validator/src/test/java/io/avaje/validation/core/DTemplateLookupTest.java rename to validator/src/test/java/io/avaje/validation/core/TemplateLookupTest.java index a87bb19e..916b8652 100644 --- a/validator/src/test/java/io/avaje/validation/core/DTemplateLookupTest.java +++ b/validator/src/test/java/io/avaje/validation/core/TemplateLookupTest.java @@ -7,15 +7,15 @@ import org.junit.jupiter.api.Test; -class DTemplateLookupTest { +class TemplateLookupTest { - private final DTemplateLookup lookup; + private final TemplateLookup lookup; - DTemplateLookupTest() { + TemplateLookupTest() { final var localeResolver = new DLocaleResolver(Locale.ENGLISH, List.of(Locale.GERMAN)); final var defaultResourceBundle = - new DResourceBundleManager(List.of(), List.of(), localeResolver); - this.lookup = new DTemplateLookup(defaultResourceBundle); + new ResourceBundleManager(List.of(), List.of(), localeResolver); + this.lookup = new TemplateLookup(defaultResourceBundle); } @Test