diff --git a/core/src/main/java/org/everit/json/schema/AbstractFormatValidator.java b/core/src/main/java/org/everit/json/schema/AbstractFormatValidator.java new file mode 100644 index 000000000..8433fd691 --- /dev/null +++ b/core/src/main/java/org/everit/json/schema/AbstractFormatValidator.java @@ -0,0 +1,66 @@ +package org.everit.json.schema; + +import static java.util.Objects.requireNonNull; + +import java.util.Map; +import java.util.Optional; + +import org.everit.json.schema.internal.DateTimeFormatValidator; +import org.everit.json.schema.internal.EmailFormatValidator; +import org.everit.json.schema.internal.HostnameFormatValidator; +import org.everit.json.schema.internal.IPV4Validator; +import org.everit.json.schema.internal.IPV6Validator; +import org.everit.json.schema.internal.URIFormatValidator; + +/** + * Implementations perform the validation against the "format" keyword (see JSON Schema spec section + * 7). + */ +public interface AbstractFormatValidator { + + /** + * Implementation-specific validation of {@code subject}. If a validation error occurs then + * implementations should return a programmer-friendly error message as a String wrapped in an + * Optional. If the validation succeeded then {@link Optional#empty() an empty optional} should be + * returned. + * + * @param subject + * the string to be validated + * + * @return an {@code Optional} wrapping the error message if a validation error occured, otherwise + * {@link Optional#empty() an empty optional}. + */ + Optional validate(String subject); + + /** + * Implementation-specific validation of {@code subject}. If a validation error occurs then + * implementations should return a programmer-friendly error message as a String wrapped in an + * Optional. If the validation succeeded then {@link Optional#empty() an empty optional} should be + * returned. + * + * @param subject + * the string to be validated + * @param unprocessedProperties + * the map of unprocessed properties, which can be useful for some custom complex format + * + * @return an {@code Optional} wrapping the error message if a validation error occured, otherwise + * {@link Optional#empty() an empty optional}. + */ + Optional validate(String subject, Map unprocessedProperties); + + /** + * Provides the name of this format. + *

+ * Unless specified otherwise the {@link org.everit.json.schema.loader.SchemaLoader} will use this + * name to recognize string schemas using this format. + *

+ * The default implementation of this method returns {@code "unnamed-format"}. It is strongly + * recommended for implementations to give a more meaningful name by overriding this method. + * + * @return the format name. + */ + default String formatName() { + return "unnamed-format"; + } + +} diff --git a/core/src/main/java/org/everit/json/schema/ContextualFormatValidator.java b/core/src/main/java/org/everit/json/schema/ContextualFormatValidator.java new file mode 100644 index 000000000..0d772682b --- /dev/null +++ b/core/src/main/java/org/everit/json/schema/ContextualFormatValidator.java @@ -0,0 +1,38 @@ +package org.everit.json.schema; + +import static java.util.Objects.requireNonNull; + +import java.util.Map; +import java.util.Optional; + +import org.everit.json.schema.internal.DateTimeFormatValidator; +import org.everit.json.schema.internal.EmailFormatValidator; +import org.everit.json.schema.internal.HostnameFormatValidator; +import org.everit.json.schema.internal.IPV4Validator; +import org.everit.json.schema.internal.IPV6Validator; +import org.everit.json.schema.internal.URIFormatValidator; + +/** + * Implementations perform the validation against the "format" keyword (see JSON Schema spec section + * 7). + */ +@FunctionalInterface +public interface ContextualFormatValidator extends AbstractFormatValidator { + + /** + * Implementation-specific validation of {@code subject}. If a validation error occurs then + * implementations should return a programmer-friendly error message as a String wrapped in an + * Optional. If the validation succeeded then {@link Optional#empty() an empty optional} should be + * returned. + * + * @param subject + * the string to be validated + * + * @return an {@code Optional} wrapping the error message if a validation error occured, otherwise + * {@link Optional#empty() an empty optional}. + */ + default Optional validate(String subject) { + return validate(subject,null); + } + +} diff --git a/core/src/main/java/org/everit/json/schema/FormatValidator.java b/core/src/main/java/org/everit/json/schema/FormatValidator.java index 718743f7f..e3fd6c3f0 100644 --- a/core/src/main/java/org/everit/json/schema/FormatValidator.java +++ b/core/src/main/java/org/everit/json/schema/FormatValidator.java @@ -2,6 +2,7 @@ import static java.util.Objects.requireNonNull; +import java.util.Map; import java.util.Optional; import org.everit.json.schema.internal.DateTimeFormatValidator; @@ -16,12 +17,12 @@ * 7). */ @FunctionalInterface -public interface FormatValidator { +public interface FormatValidator extends AbstractFormatValidator { /** * No-operation implementation (never throws {always returns {@link Optional#empty()}). */ - FormatValidator NONE = subject -> Optional.empty(); + FormatValidator NONE = (subject) -> Optional.empty(); /** * Static factory method for {@code FormatValidator} implementations supporting the @@ -67,24 +68,14 @@ static FormatValidator forFormat(final String formatName) { * * @param subject * the string to be validated + * @param unprocessedProperties + * the map of unprocessed properties, which can be useful for some custom complex format + * * @return an {@code Optional} wrapping the error message if a validation error occured, otherwise * {@link Optional#empty() an empty optional}. */ - Optional validate(String subject); - - /** - * Provides the name of this format. - *

- * Unless specified otherwise the {@link org.everit.json.schema.loader.SchemaLoader} will use this - * name to recognize string schemas using this format. - *

- * The default implementation of this method returns {@code "unnamed-format"}. It is strongly - * recommended for implementations to give a more meaningful name by overriding this method. - * - * @return the format name. - */ - default String formatName() { - return "unnamed-format"; + default Optional validate(String subject, Map unprocessedProperties) { + return validate(subject); } } diff --git a/core/src/main/java/org/everit/json/schema/StringSchema.java b/core/src/main/java/org/everit/json/schema/StringSchema.java index 68ea7099d..6096a87db 100644 --- a/core/src/main/java/org/everit/json/schema/StringSchema.java +++ b/core/src/main/java/org/everit/json/schema/StringSchema.java @@ -27,7 +27,7 @@ public static class Builder extends Schema.Builder { private boolean requiresString = true; - private FormatValidator formatValidator = NONE; + private AbstractFormatValidator formatValidator = NONE; @Override public StringSchema build() { @@ -43,7 +43,7 @@ public StringSchema build() { * the format validator * @return {@code this} */ - public Builder formatValidator(final FormatValidator formatValidator) { + public Builder formatValidator(final AbstractFormatValidator formatValidator) { this.formatValidator = requireNonNull(formatValidator, "formatValidator cannot be null"); return this; } @@ -86,7 +86,7 @@ public static Builder builder() { private final boolean requiresString; - private final FormatValidator formatValidator; + private final AbstractFormatValidator formatValidator; public StringSchema() { this(builder()); @@ -149,7 +149,7 @@ public boolean equals(Object o) { } } - public FormatValidator getFormatValidator() { + public AbstractFormatValidator getFormatValidator() { return formatValidator; } diff --git a/core/src/main/java/org/everit/json/schema/StringSchemaValidatingVisitor.java b/core/src/main/java/org/everit/json/schema/StringSchemaValidatingVisitor.java index c32ebbe65..7e6adf4e4 100644 --- a/core/src/main/java/org/everit/json/schema/StringSchemaValidatingVisitor.java +++ b/core/src/main/java/org/everit/json/schema/StringSchemaValidatingVisitor.java @@ -51,8 +51,8 @@ public StringSchemaValidatingVisitor(Object subject, ValidatingVisitor owner) { } } - @Override void visitFormat(FormatValidator formatValidator) { - Optional failure = formatValidator.validate(stringSubject); + @Override void visitFormat(AbstractFormatValidator formatValidator, Schema schema) { + Optional failure = formatValidator.validate(stringSubject, schema.getUnprocessedProperties()); if (failure.isPresent()) { owner.failure(failure.get(), "format"); } diff --git a/core/src/main/java/org/everit/json/schema/Visitor.java b/core/src/main/java/org/everit/json/schema/Visitor.java index 18d5d12a9..a9843526a 100644 --- a/core/src/main/java/org/everit/json/schema/Visitor.java +++ b/core/src/main/java/org/everit/json/schema/Visitor.java @@ -167,10 +167,10 @@ void visitStringSchema(StringSchema stringSchema) { visitMinLength(stringSchema.getMinLength()); visitMaxLength(stringSchema.getMaxLength()); visitPattern(stringSchema.getRegexpPattern()); - visitFormat(stringSchema.getFormatValidator()); + visitFormat(stringSchema.getFormatValidator(),stringSchema); } - void visitFormat(FormatValidator formatValidator) { + void visitFormat(AbstractFormatValidator formatValidator, Schema schema) { } void visitPattern(Regexp pattern) { diff --git a/core/src/main/java/org/everit/json/schema/internal/DateTimeFormatValidator.java b/core/src/main/java/org/everit/json/schema/internal/DateTimeFormatValidator.java index db083fd63..ef8519189 100644 --- a/core/src/main/java/org/everit/json/schema/internal/DateTimeFormatValidator.java +++ b/core/src/main/java/org/everit/json/schema/internal/DateTimeFormatValidator.java @@ -6,6 +6,7 @@ import java.time.format.DateTimeFormatterBuilder; import java.util.Arrays; import java.util.List; +import java.util.Map; import java.util.Optional; import static org.everit.json.schema.internal.TemporalFormatValidator.SECONDS_FRACTION_FORMATTER; diff --git a/core/src/main/java/org/everit/json/schema/internal/EmailFormatValidator.java b/core/src/main/java/org/everit/json/schema/internal/EmailFormatValidator.java index edf4fc3fd..ec8d780cd 100644 --- a/core/src/main/java/org/everit/json/schema/internal/EmailFormatValidator.java +++ b/core/src/main/java/org/everit/json/schema/internal/EmailFormatValidator.java @@ -1,5 +1,6 @@ package org.everit.json.schema.internal; +import java.util.Map; import java.util.Optional; import org.apache.commons.validator.routines.EmailValidator; diff --git a/core/src/main/java/org/everit/json/schema/internal/HostnameFormatValidator.java b/core/src/main/java/org/everit/json/schema/internal/HostnameFormatValidator.java index 70ce2853b..0d06d9750 100644 --- a/core/src/main/java/org/everit/json/schema/internal/HostnameFormatValidator.java +++ b/core/src/main/java/org/everit/json/schema/internal/HostnameFormatValidator.java @@ -3,6 +3,7 @@ import org.apache.commons.validator.routines.DomainValidator; import org.everit.json.schema.FormatValidator; +import java.util.Map; import java.util.Optional; /** diff --git a/core/src/main/java/org/everit/json/schema/internal/IPV4Validator.java b/core/src/main/java/org/everit/json/schema/internal/IPV4Validator.java index 7871aaed1..b44ad0108 100644 --- a/core/src/main/java/org/everit/json/schema/internal/IPV4Validator.java +++ b/core/src/main/java/org/everit/json/schema/internal/IPV4Validator.java @@ -3,6 +3,7 @@ import org.apache.commons.validator.routines.InetAddressValidator; import org.everit.json.schema.FormatValidator; +import java.util.Map; import java.util.Optional; /** diff --git a/core/src/main/java/org/everit/json/schema/internal/IPV6Validator.java b/core/src/main/java/org/everit/json/schema/internal/IPV6Validator.java index ad629a1df..034a50500 100644 --- a/core/src/main/java/org/everit/json/schema/internal/IPV6Validator.java +++ b/core/src/main/java/org/everit/json/schema/internal/IPV6Validator.java @@ -3,6 +3,7 @@ import org.apache.commons.validator.routines.InetAddressValidator; import org.everit.json.schema.FormatValidator; +import java.util.Map; import java.util.Optional; /** diff --git a/core/src/main/java/org/everit/json/schema/internal/JsonPointerFormatValidator.java b/core/src/main/java/org/everit/json/schema/internal/JsonPointerFormatValidator.java index 7a862363b..ca9287002 100644 --- a/core/src/main/java/org/everit/json/schema/internal/JsonPointerFormatValidator.java +++ b/core/src/main/java/org/everit/json/schema/internal/JsonPointerFormatValidator.java @@ -2,6 +2,7 @@ import static java.lang.String.format; +import java.util.Map; import java.util.Optional; import org.everit.json.schema.FormatValidator; diff --git a/core/src/main/java/org/everit/json/schema/internal/RegexFormatValidator.java b/core/src/main/java/org/everit/json/schema/internal/RegexFormatValidator.java index 28fac7481..cc9c77085 100644 --- a/core/src/main/java/org/everit/json/schema/internal/RegexFormatValidator.java +++ b/core/src/main/java/org/everit/json/schema/internal/RegexFormatValidator.java @@ -1,5 +1,6 @@ package org.everit.json.schema.internal; +import java.util.Map; import java.util.Optional; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; diff --git a/core/src/main/java/org/everit/json/schema/internal/RelativeJsonPointerFormatValidator.java b/core/src/main/java/org/everit/json/schema/internal/RelativeJsonPointerFormatValidator.java index 8cefbb4a8..d008019a4 100644 --- a/core/src/main/java/org/everit/json/schema/internal/RelativeJsonPointerFormatValidator.java +++ b/core/src/main/java/org/everit/json/schema/internal/RelativeJsonPointerFormatValidator.java @@ -1,5 +1,6 @@ package org.everit.json.schema.internal; +import java.util.Map; import java.util.Optional; import org.everit.json.schema.FormatValidator; diff --git a/core/src/main/java/org/everit/json/schema/internal/TemporalFormatValidator.java b/core/src/main/java/org/everit/json/schema/internal/TemporalFormatValidator.java index 3b679c9c7..be06a126c 100644 --- a/core/src/main/java/org/everit/json/schema/internal/TemporalFormatValidator.java +++ b/core/src/main/java/org/everit/json/schema/internal/TemporalFormatValidator.java @@ -6,6 +6,8 @@ import java.time.format.DateTimeFormatterBuilder; import java.time.format.DateTimeParseException; import java.time.temporal.ChronoField; + +import java.util.Map; import java.util.Optional; import static java.util.Objects.requireNonNull; diff --git a/core/src/main/java/org/everit/json/schema/internal/URIFormatValidator.java b/core/src/main/java/org/everit/json/schema/internal/URIFormatValidator.java index 7adc6c2b3..05b04c61c 100644 --- a/core/src/main/java/org/everit/json/schema/internal/URIFormatValidator.java +++ b/core/src/main/java/org/everit/json/schema/internal/URIFormatValidator.java @@ -2,6 +2,8 @@ import java.net.URI; import java.net.URISyntaxException; + +import java.util.Map; import java.util.Optional; import org.everit.json.schema.FormatValidator; diff --git a/core/src/main/java/org/everit/json/schema/internal/URIReferenceFormatValidator.java b/core/src/main/java/org/everit/json/schema/internal/URIReferenceFormatValidator.java index bee1a13ea..5d0c49bb1 100644 --- a/core/src/main/java/org/everit/json/schema/internal/URIReferenceFormatValidator.java +++ b/core/src/main/java/org/everit/json/schema/internal/URIReferenceFormatValidator.java @@ -4,6 +4,8 @@ import java.net.URI; import java.net.URISyntaxException; + +import java.util.Map; import java.util.Optional; import org.everit.json.schema.FormatValidator; diff --git a/core/src/main/java/org/everit/json/schema/internal/URITemplateFormatValidator.java b/core/src/main/java/org/everit/json/schema/internal/URITemplateFormatValidator.java index e144161b7..6a3033b61 100644 --- a/core/src/main/java/org/everit/json/schema/internal/URITemplateFormatValidator.java +++ b/core/src/main/java/org/everit/json/schema/internal/URITemplateFormatValidator.java @@ -2,6 +2,7 @@ import static java.lang.String.format; +import java.util.Map; import java.util.Optional; import org.everit.json.schema.FormatValidator; diff --git a/core/src/main/java/org/everit/json/schema/internal/URIV4FormatValidator.java b/core/src/main/java/org/everit/json/schema/internal/URIV4FormatValidator.java index 6cca1b4bd..4d0b74f2f 100644 --- a/core/src/main/java/org/everit/json/schema/internal/URIV4FormatValidator.java +++ b/core/src/main/java/org/everit/json/schema/internal/URIV4FormatValidator.java @@ -2,6 +2,7 @@ import java.net.URI; import java.net.URISyntaxException; +import java.util.Map; import java.util.Optional; import org.everit.json.schema.FormatValidator; diff --git a/core/src/main/java/org/everit/json/schema/loader/LoaderConfig.java b/core/src/main/java/org/everit/json/schema/loader/LoaderConfig.java index dba904211..655d437ab 100644 --- a/core/src/main/java/org/everit/json/schema/loader/LoaderConfig.java +++ b/core/src/main/java/org/everit/json/schema/loader/LoaderConfig.java @@ -10,7 +10,7 @@ import java.util.HashMap; import java.util.Map; -import org.everit.json.schema.FormatValidator; +import org.everit.json.schema.AbstractFormatValidator; import org.everit.json.schema.loader.internal.DefaultSchemaClient; import org.everit.json.schema.regexp.JavaUtilRegexpFactory; import org.everit.json.schema.regexp.RegexpFactory; @@ -26,7 +26,7 @@ static LoaderConfig defaultV4Config() { final SchemaClient schemaClient; - final Map formatValidators; + final Map formatValidators; final Map schemasByURI; @@ -38,12 +38,12 @@ static LoaderConfig defaultV4Config() { final RegexpFactory regexpFactory; - LoaderConfig(SchemaClient schemaClient, Map formatValidators, + LoaderConfig(SchemaClient schemaClient, Map formatValidators, SpecificationVersion specVersion, boolean useDefaults) { this(schemaClient, formatValidators, emptyMap(), specVersion, useDefaults, false, new JavaUtilRegexpFactory()); } - LoaderConfig(SchemaClient schemaClient, Map formatValidators, + LoaderConfig(SchemaClient schemaClient, Map formatValidators, Map schemasByURI, SpecificationVersion specVersion, boolean useDefaults, boolean nullableSupport, RegexpFactory regexpFactory) { diff --git a/core/src/main/java/org/everit/json/schema/loader/SchemaLoader.java b/core/src/main/java/org/everit/json/schema/loader/SchemaLoader.java index 505586514..7afbc1201 100644 --- a/core/src/main/java/org/everit/json/schema/loader/SchemaLoader.java +++ b/core/src/main/java/org/everit/json/schema/loader/SchemaLoader.java @@ -21,7 +21,7 @@ import org.everit.json.schema.CombinedSchema; import org.everit.json.schema.EmptySchema; import org.everit.json.schema.FalseSchema; -import org.everit.json.schema.FormatValidator; +import org.everit.json.schema.AbstractFormatValidator; import org.everit.json.schema.Schema; import org.everit.json.schema.SchemaException; import org.everit.json.schema.SchemaLocation; @@ -58,7 +58,7 @@ public static class SchemaLoaderBuilder { SchemaLocation pointerToCurrentObj = SchemaLocation.empty(); - Map formatValidators = new HashMap<>(); + Map formatValidators = new HashMap<>(); SpecificationVersion specVersion; @@ -77,13 +77,13 @@ public SchemaLoaderBuilder() { } /** - * Registers a format validator with the name returned by {@link FormatValidator#formatName()}. + * Registers a format validator with the name returned by {@link AbstractFormatValidator#formatName()}. * * @param formatValidator * the format validator to be registered with its name * @return {@code this} */ - public SchemaLoaderBuilder addFormatValidator(FormatValidator formatValidator) { + public SchemaLoaderBuilder addFormatValidator(AbstractFormatValidator formatValidator) { formatValidators.put(formatValidator.formatName(), formatValidator); return this; } @@ -99,7 +99,7 @@ public SchemaLoaderBuilder addFormatValidator(FormatValidator formatValidator) { */ @Deprecated public SchemaLoaderBuilder addFormatValidator(String formatName, - final FormatValidator formatValidator) { + final AbstractFormatValidator formatValidator) { if (!Objects.equals(formatName, formatValidator.formatName())) { formatValidators.put(formatName, new WrappingFormatValidator(formatName, formatValidator)); } else { @@ -206,7 +206,7 @@ public SchemaLoaderBuilder schemaJson(Object schema) { return this; } - SchemaLoaderBuilder formatValidators(Map formatValidators) { + SchemaLoaderBuilder formatValidators(Map formatValidators) { this.formatValidators = formatValidators; return this; } @@ -448,7 +448,7 @@ SpecificationVersion specVersion() { * @deprecated */ @Deprecated - Optional getFormatValidator(String formatName) { + Optional getFormatValidator(String formatName) { return Optional.ofNullable(config.formatValidators.get(formatName)); } diff --git a/core/src/main/java/org/everit/json/schema/loader/SpecificationVersion.java b/core/src/main/java/org/everit/json/schema/loader/SpecificationVersion.java index b60403ad7..ef8bf45d8 100644 --- a/core/src/main/java/org/everit/json/schema/loader/SpecificationVersion.java +++ b/core/src/main/java/org/everit/json/schema/loader/SpecificationVersion.java @@ -10,6 +10,7 @@ import java.util.List; import java.util.Map; +import org.everit.json.schema.AbstractFormatValidator; import org.everit.json.schema.FormatValidator; import org.everit.json.schema.internal.DateFormatValidator; import org.everit.json.schema.internal.DateTimeFormatValidator; @@ -48,7 +49,7 @@ enum SpecificationVersion { return "http://json-schema.org/draft-04/schema"; } - @Override Map defaultFormatValidators() { + @Override Map defaultFormatValidators() { return V4_VALIDATORS; } @@ -69,7 +70,7 @@ enum SpecificationVersion { return "http://json-schema.org/draft-06/schema"; } - @Override Map defaultFormatValidators() { + @Override Map defaultFormatValidators() { return V6_VALIDATORS; } @@ -90,7 +91,7 @@ enum SpecificationVersion { return "http://json-schema.org/draft-07/schema"; } - @Override Map defaultFormatValidators() { + @Override Map defaultFormatValidators() { return V7_VALIDATORS; } }; @@ -129,7 +130,7 @@ private static List keywords(String... keywords) { return unmodifiableList(asList(keywords)); } - private static final Map V4_VALIDATORS = formatValidators(null, + private static final Map V4_VALIDATORS = formatValidators(null, new DateTimeFormatValidator(), new URIV4FormatValidator(), new EmailFormatValidator(), @@ -138,14 +139,14 @@ private static List keywords(String... keywords) { new HostnameFormatValidator() ); - private static final Map V6_VALIDATORS = formatValidators(V4_VALIDATORS, + private static final Map V6_VALIDATORS = formatValidators(V4_VALIDATORS, new JsonPointerFormatValidator(), new URIFormatValidator(), new URIReferenceFormatValidator(), new URITemplateFormatValidator() ); - private static final Map V7_VALIDATORS = formatValidators(V6_VALIDATORS, + private static final Map V7_VALIDATORS = formatValidators(V6_VALIDATORS, new DateFormatValidator(), new URIFormatValidator(false), new TimeFormatValidator(), @@ -153,8 +154,8 @@ private static List keywords(String... keywords) { new RelativeJsonPointerFormatValidator() ); - private static Map formatValidators(Map parent, FormatValidator... validators) { - Map validatorMap = (parent == null) ? new HashMap<>() : new HashMap<>(parent); + private static Map formatValidators(Map parent, FormatValidator... validators) { + Map validatorMap = (parent == null) ? new HashMap<>() : new HashMap<>(parent); for (FormatValidator validator : validators) { validatorMap.put(validator.formatName(), validator); } @@ -169,7 +170,7 @@ private static Map formatValidators(Map defaultFormatValidators(); + abstract Map defaultFormatValidators(); public boolean isAtLeast(SpecificationVersion lowerInclusiveBound) { return this.ordinal() >= lowerInclusiveBound.ordinal(); diff --git a/core/src/main/java/org/everit/json/schema/loader/StringSchemaLoader.java b/core/src/main/java/org/everit/json/schema/loader/StringSchemaLoader.java index 1633f9f3e..d9f6bb229 100644 --- a/core/src/main/java/org/everit/json/schema/loader/StringSchemaLoader.java +++ b/core/src/main/java/org/everit/json/schema/loader/StringSchemaLoader.java @@ -6,7 +6,7 @@ import java.util.Map; -import org.everit.json.schema.FormatValidator; +import org.everit.json.schema.AbstractFormatValidator; import org.everit.json.schema.StringSchema; /** @@ -16,7 +16,7 @@ public class StringSchemaLoader { private LoadingState ls; - private Map formatValidators; + private Map formatValidators; private boolean useDefault; @@ -30,7 +30,7 @@ public StringSchemaLoader(LoadingState ls) { this(ls, DRAFT_4.defaultFormatValidators()); } - StringSchemaLoader(LoadingState ls, Map formatValidators) { + StringSchemaLoader(LoadingState ls, Map formatValidators) { this.ls = requireNonNull(ls, "ls cannot be null"); this.formatValidators = unmodifiableMap(requireNonNull(formatValidators, "formatValidators cannot be null")); } @@ -48,7 +48,7 @@ public StringSchema.Builder load() { } private void addFormatValidator(StringSchema.Builder builder, String formatName) { - FormatValidator formatValidator = formatValidators.get(formatName); + AbstractFormatValidator formatValidator = formatValidators.get(formatName); if (formatValidator != null) { builder.formatValidator(formatValidator); } diff --git a/core/src/main/java/org/everit/json/schema/loader/internal/WrappingFormatValidator.java b/core/src/main/java/org/everit/json/schema/loader/internal/WrappingFormatValidator.java index 92e1460b9..35c501914 100644 --- a/core/src/main/java/org/everit/json/schema/loader/internal/WrappingFormatValidator.java +++ b/core/src/main/java/org/everit/json/schema/loader/internal/WrappingFormatValidator.java @@ -1,28 +1,33 @@ package org.everit.json.schema.loader.internal; -import org.everit.json.schema.FormatValidator; +import org.everit.json.schema.AbstractFormatValidator; +import java.util.Map; import java.util.Optional; import static java.util.Objects.requireNonNull; -public class WrappingFormatValidator implements FormatValidator { +public class WrappingFormatValidator implements AbstractFormatValidator { private final String formatName; - private final FormatValidator formatValidator; + private final AbstractFormatValidator formatValidator; - public WrappingFormatValidator(String formatName, FormatValidator wrappedValidator) { + public WrappingFormatValidator(String formatName, AbstractFormatValidator wrappedValidator) { this.formatName = requireNonNull(formatName, "formatName cannot be null"); this.formatValidator = requireNonNull(wrappedValidator, "wrappedValidator cannot be null"); } - @Override public Optional validate(String subject) { return formatValidator.validate(subject); } + @Override + public Optional validate(String subject, Map unprocessedProperties) { + return formatValidator.validate(subject, unprocessedProperties); + } + @Override public String formatName() { return formatName; diff --git a/core/src/test/java/org/everit/json/schema/StringSchemaTest.java b/core/src/test/java/org/everit/json/schema/StringSchemaTest.java index 9c70cb28a..13d815164 100644 --- a/core/src/test/java/org/everit/json/schema/StringSchemaTest.java +++ b/core/src/test/java/org/everit/json/schema/StringSchemaTest.java @@ -28,7 +28,7 @@ private static Schema loadWithNullableSupport(JSONObject rawSchemaJson) { @Test public void formatFailure() { StringSchema subject = buildWithLocation(StringSchema.builder() - .formatValidator(subj -> Optional.of("violation"))); + .formatValidator(((FormatValidator)((subj) -> Optional.of("violation"))))); TestSupport.failureOf(subject) .expectedKeyword("format") .input("string") @@ -37,7 +37,7 @@ public void formatFailure() { @Test public void formatSuccess() { - StringSchema subject = StringSchema.builder().formatValidator(subj -> Optional.empty()).build(); + StringSchema subject = StringSchema.builder().formatValidator(((FormatValidator)((subj) -> Optional.empty()))).build(); subject.validate("string"); } diff --git a/core/src/test/java/org/everit/json/schema/internal/DefaultFormatValidatorTest.java b/core/src/test/java/org/everit/json/schema/internal/DefaultFormatValidatorTest.java index f70aead47..c7c6e42a3 100644 --- a/core/src/test/java/org/everit/json/schema/internal/DefaultFormatValidatorTest.java +++ b/core/src/test/java/org/everit/json/schema/internal/DefaultFormatValidatorTest.java @@ -18,6 +18,7 @@ import org.everit.json.schema.FormatValidator; import org.junit.Test; +import java.util.Map; import java.util.Optional; import static org.everit.json.schema.internal.ValidatorTestSupport.assertFailure; diff --git a/core/src/test/java/org/everit/json/schema/internal/URIV4FormatValidatorTest.java b/core/src/test/java/org/everit/json/schema/internal/URIV4FormatValidatorTest.java index fdb455f9b..c7f512a53 100644 --- a/core/src/test/java/org/everit/json/schema/internal/URIV4FormatValidatorTest.java +++ b/core/src/test/java/org/everit/json/schema/internal/URIV4FormatValidatorTest.java @@ -9,16 +9,16 @@ public class URIV4FormatValidatorTest { @Test public void relativeURI() { - assertFalse(new URIV4FormatValidator().validate("abc").isPresent()); + assertFalse(new URIV4FormatValidator().validate("abc",null).isPresent()); } @Test public void absoluteURI() { - assertFalse(new URIV4FormatValidator().validate("http://a.b.c").isPresent()); + assertFalse(new URIV4FormatValidator().validate("http://a.b.c",null).isPresent()); } @Test public void notURI() { - assertTrue(new URIV4FormatValidator().validate("\\\\\\\\WINDOWS\\\\fileshare").isPresent()); + assertTrue(new URIV4FormatValidator().validate("\\\\\\\\WINDOWS\\\\fileshare",null).isPresent()); } } diff --git a/core/src/test/java/org/everit/json/schema/internal/ValidatorTestSupport.java b/core/src/test/java/org/everit/json/schema/internal/ValidatorTestSupport.java index d434b557e..0351d9928 100644 --- a/core/src/test/java/org/everit/json/schema/internal/ValidatorTestSupport.java +++ b/core/src/test/java/org/everit/json/schema/internal/ValidatorTestSupport.java @@ -2,6 +2,7 @@ import static org.junit.Assert.assertTrue; +import java.util.Map; import java.util.Optional; import org.everit.json.schema.FormatValidator; @@ -10,13 +11,21 @@ public final class ValidatorTestSupport { static void assertSuccess(String subject, FormatValidator format) { - Optional opt = format.validate(subject); + assertSuccess(subject, format, null); + } + + static void assertSuccess(String subject, FormatValidator format, Map unprocessedProperties) { + Optional opt = format.validate(subject, unprocessedProperties); Assert.assertNotNull("the optional is not null", opt); Assert.assertFalse("failure not exist", opt.isPresent()); } static void assertFailure(String subject, FormatValidator format, String expectedFailure) { - Optional opt = format.validate(subject); + assertFailure(subject, format, null, expectedFailure); + } + + static void assertFailure(String subject, FormatValidator format, Map unprocessedProperties, String expectedFailure) { + Optional opt = format.validate(subject, unprocessedProperties); Assert.assertNotNull("the optional is not null", opt); assertTrue("failure exists", opt.isPresent()); Assert.assertEquals(expectedFailure, opt.get()); diff --git a/core/src/test/java/org/everit/json/schema/loader/CustomFormatValidatorExtTest.java b/core/src/test/java/org/everit/json/schema/loader/CustomFormatValidatorExtTest.java new file mode 100644 index 000000000..926469c50 --- /dev/null +++ b/core/src/test/java/org/everit/json/schema/loader/CustomFormatValidatorExtTest.java @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2011 Everit Kft. (http://www.everit.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.everit.json.schema.loader; + +import org.everit.json.schema.ContextualFormatValidator; +import org.everit.json.schema.ResourceLoader; +import org.everit.json.schema.ValidationException; +import org.json.JSONObject; +import org.junit.Assert; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import static org.junit.Assert.assertEquals; + +public class CustomFormatValidatorExtTest { + + private final ResourceLoader loader = ResourceLoader.DEFAULT; + + static class DivisibleValidator implements ContextualFormatValidator { + + @Override + public Optional validate(final String subject, final Map unprocessedProperties) { + if (unprocessedProperties.containsKey("factors")) { + try { + long divisible = Long.parseLong(subject); + try { + List factors = (List) unprocessedProperties.get("factors"); + for (String strFactor: factors) { + try { + long factor = Long.parseLong(strFactor); + if (divisible % factor != 0) { + return Optional.of(String.format("[%s] is not divisible by [%s]", subject, strFactor)); + } + } catch(NumberFormatException nfe) { + return Optional.of(String.format("the factor [%s] is not a parsable number", strFactor)); + } + } + return Optional.empty(); + } catch(ClassCastException cce) { + return Optional.of("'factors' is not an array in JSON Schema"); + } + } catch(NumberFormatException nfe) { + return Optional.of(String.format("the string [%s] is not a parsable number", subject)); + } + } else { + return Optional.of(String.format("no declared 'factors' in JSON Schema", subject)); + } + } + + @Override + public String formatName() { + return "divisible"; + } + } + + @Test + public void testWorks() { + SchemaLoader schemaLoader = SchemaLoader.builder() + .schemaJson(baseSchemaJson()) + .addFormatValidator("divisible", new DivisibleValidator()) + .build(); + + try { + schemaLoader.load().build().validate(loader.readObj("customformat-ext-works_data.json")); + } catch (ValidationException ve) { + Assert.fail("throwed exception"); + } + } + + @Test + public void testFail() { + SchemaLoader schemaLoader = SchemaLoader.builder() + .schemaJson(baseSchemaJson()) + .addFormatValidator("divisible", new DivisibleValidator()) + .build(); + + try { + schemaLoader.load().build().validate(loader.readObj("customformat-ext-fail_data.json")); + Assert.fail("did not throw exception"); + } catch (ValidationException ve) { + } + } + + @Test + public void nameOverride() { + JSONObject rawSchemaJson = baseSchemaJson(); + JSONObject idPropSchema = (JSONObject) rawSchemaJson.query("/properties/v"); + idPropSchema.put("format", "somethingelse"); + SchemaLoader schemaLoader = SchemaLoader.builder() + .schemaJson(rawSchemaJson) + .addFormatValidator("somethingelse", new DivisibleValidator()) + .build(); + Object actual = fetchFormatValueFromOutputJson(schemaLoader); + assertEquals("somethingelse", actual); + } + + private Object fetchFormatValueFromOutputJson(SchemaLoader schemaLoader) { + return new JSONObject(schemaLoader.load().build().toString()) + .query("/properties/v/format"); + } + + private JSONObject baseSchemaJson() { + return loader.readObj("customformat-ext-schema.json"); + } + +} diff --git a/core/src/test/java/org/everit/json/schema/loader/CustomFormatValidatorTest.java b/core/src/test/java/org/everit/json/schema/loader/CustomFormatValidatorTest.java index 229debf1c..b1b70bcb9 100644 --- a/core/src/test/java/org/everit/json/schema/loader/CustomFormatValidatorTest.java +++ b/core/src/test/java/org/everit/json/schema/loader/CustomFormatValidatorTest.java @@ -22,6 +22,7 @@ import org.junit.Assert; import org.junit.Test; +import java.util.Map; import java.util.Optional; import static org.junit.Assert.assertEquals; diff --git a/core/src/test/java/org/everit/json/schema/loader/SchemaLoaderTest.java b/core/src/test/java/org/everit/json/schema/loader/SchemaLoaderTest.java index 0928ae389..b0e2892ab 100644 --- a/core/src/test/java/org/everit/json/schema/loader/SchemaLoaderTest.java +++ b/core/src/test/java/org/everit/json/schema/loader/SchemaLoaderTest.java @@ -33,6 +33,7 @@ import org.everit.json.schema.EmptySchema; import org.everit.json.schema.EnumSchema; import org.everit.json.schema.FalseSchema; +import org.everit.json.schema.FormatValidator; import org.everit.json.schema.NotSchema; import org.everit.json.schema.NullSchema; import org.everit.json.schema.NumberSchema; @@ -97,7 +98,7 @@ public void builderUsesDefaultSchemaClient() { public void customFormat() { Schema subject = SchemaLoader.builder() .schemaJson(get("customFormat")) - .addFormatValidator("custom", obj -> Optional.of("failure")) + .addFormatValidator("custom", ((FormatValidator)((obj) -> Optional.of("failure")))) .build().load().build(); TestSupport.expectFailure(subject, "asd"); } diff --git a/core/src/test/java/org/everit/json/schema/loader/SpecificationVersionTest.java b/core/src/test/java/org/everit/json/schema/loader/SpecificationVersionTest.java index dd008fd03..4df725ab1 100644 --- a/core/src/test/java/org/everit/json/schema/loader/SpecificationVersionTest.java +++ b/core/src/test/java/org/everit/json/schema/loader/SpecificationVersionTest.java @@ -11,7 +11,7 @@ import java.util.Map; import java.util.Set; -import org.everit.json.schema.FormatValidator; +import org.everit.json.schema.AbstractFormatValidator; import org.junit.Test; public class SpecificationVersionTest { @@ -24,14 +24,14 @@ public void v6ContainsAdditionalFormats() { @Test public void v4MapMatchesFormatNames() { - for (Map.Entry entry : DRAFT_4.defaultFormatValidators().entrySet()) { + for (Map.Entry entry : DRAFT_4.defaultFormatValidators().entrySet()) { assertEquals(entry.getKey(), entry.getValue().formatName()); } } @Test public void v6MapMatchesFormatNames() { - for (Map.Entry entry : DRAFT_6.defaultFormatValidators().entrySet()) { + for (Map.Entry entry : DRAFT_6.defaultFormatValidators().entrySet()) { assertEquals(entry.getKey(), entry.getValue().formatName()); } } diff --git a/core/src/test/resources/org/everit/jsonvalidator/customformat-ext-fail_data.json b/core/src/test/resources/org/everit/jsonvalidator/customformat-ext-fail_data.json new file mode 100644 index 000000000..aef402027 --- /dev/null +++ b/core/src/test/resources/org/everit/jsonvalidator/customformat-ext-fail_data.json @@ -0,0 +1,3 @@ +{ + "v": "21" +} diff --git a/core/src/test/resources/org/everit/jsonvalidator/customformat-ext-schema.json b/core/src/test/resources/org/everit/jsonvalidator/customformat-ext-schema.json new file mode 100644 index 000000000..f070b7c44 --- /dev/null +++ b/core/src/test/resources/org/everit/jsonvalidator/customformat-ext-schema.json @@ -0,0 +1,14 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "properties": { + "v": { + "type": "string", + "format": "divisible", + "factors": [ "3", "5" ] + } + }, + "required": [ + "v" + ] +} diff --git a/core/src/test/resources/org/everit/jsonvalidator/customformat-ext-works_data.json b/core/src/test/resources/org/everit/jsonvalidator/customformat-ext-works_data.json new file mode 100644 index 000000000..5342cbb45 --- /dev/null +++ b/core/src/test/resources/org/everit/jsonvalidator/customformat-ext-works_data.json @@ -0,0 +1,3 @@ +{ + "v": "15" +}