From f6e89a01069eb8b5d7e63f4d094bed11a74dc1e7 Mon Sep 17 00:00:00 2001 From: zhxiaog Date: Thu, 16 Apr 2020 16:29:09 +0800 Subject: [PATCH 1/2] can recognize draft 201909 --- .../schema/loader/SpecificationVersion.java | 38 +++++++++++++++++++ .../json/schema/loader/SchemaLoaderTest.java | 10 ++++- .../org/everit/jsonvalidator/testschemas.json | 4 ++ 3 files changed, 51 insertions(+), 1 deletion(-) 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 ba66b0607..a3e5ea6f2 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 @@ -103,6 +103,30 @@ public enum SpecificationVersion { @Override Map defaultFormatValidators() { return V7_VALIDATORS; } + + }, DRAFT_201909 { + @Override List arrayKeywords() { + return V2019_ARRAY_KEYWORDS; + } + + @Override List objectKeywords() { + return V2019_OBJECT_KEYWORDS; + } + + @Override public String idKeyword() { + return DRAFT_6.idKeyword(); + } + + @Override List metaSchemaUrls() { + return Arrays.asList( + "http://json-schema.org/draft/2019-09/schema", + "https://json-schema.org/draft/2019-09/schema" + ); + } + + @Override Map defaultFormatValidators() { + return V201909_VALIDATORS; + } }; static SpecificationVersion getByMetaSchemaUrl(String metaSchemaUrl) { @@ -118,6 +142,18 @@ public static Optional lookupByMetaSchemaUrl(String metaSc .findFirst(); } + private static final List V2019_OBJECT_KEYWORDS = keywords("properties", "required", + "minProperties", + "maxProperties", + "dependencies", + "patternProperties", + "additionalProperties", + "propertyNames", + "dependentSchemas"); + + private static final List V2019_ARRAY_KEYWORDS = keywords("items", "additionalItems", "minItems", + "maxItems", "uniqueItems", "contains", "unevaluatedItems"); + private static final List V6_OBJECT_KEYWORDS = keywords("properties", "required", "minProperties", "maxProperties", @@ -167,6 +203,8 @@ private static List keywords(String... keywords) { new RelativeJsonPointerFormatValidator() ); + private static final Map V201909_VALIDATORS = formatValidators(V7_VALIDATORS); + private static Map formatValidators(Map parent, FormatValidator... validators) { Map validatorMap = (parent == null) ? new HashMap<>() : new HashMap<>(parent); for (FormatValidator validator : validators) { 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 0828568f0..77870e658 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 @@ -8,7 +8,7 @@ import static org.everit.json.schema.TestSupport.loadAsV6; import static org.everit.json.schema.TestSupport.loadAsV7; import static org.everit.json.schema.TestSupport.v6Loader; -import static org.everit.json.schema.loader.SpecificationVersion.DRAFT_6; +import static org.everit.json.schema.loader.SpecificationVersion.*; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -825,4 +825,12 @@ public void explicitlySetResolutionScope_isMappedToSchemaLocation() throws URISy assertEquals(new SchemaLocation(new URI("http://example.org"), emptyList()), actual.getLocation()); } + @Test + public void canRecognizeDraft201909() { + SchemaLoaderBuilder builder = SchemaLoader.builder(); + SchemaLoader loader = builder.schemaJson(get("explicitSchemaVersionFor201909")).build(); + assertEquals(DRAFT_201909.defaultFormatValidators(), builder.formatValidators); + assertEquals(DRAFT_201909, loader.specVersion()); + } + } diff --git a/core/src/test/resources/org/everit/jsonvalidator/testschemas.json b/core/src/test/resources/org/everit/jsonvalidator/testschemas.json index c2209affb..8037f69f3 100644 --- a/core/src/test/resources/org/everit/jsonvalidator/testschemas.json +++ b/core/src/test/resources/org/everit/jsonvalidator/testschemas.json @@ -730,5 +730,9 @@ } } } + }, + "explicitSchemaVersionFor201909": { + "$schema": "http://json-schema.org/draft/2019-09/schema", + "type": "object" } } From 69f88aee81ffb4cdb0362729ca5155a50b4b68ed Mon Sep 17 00:00:00 2001 From: zhxiaog Date: Thu, 16 Apr 2020 18:13:21 +0800 Subject: [PATCH 2/2] add duration format support & draft-2019-09 tests --- .../everit/json/schema/FormatValidator.java | 3 ++ .../internal/DurationFormatValidator.java | 27 ++++++++++ .../schema/loader/ExclusiveLimitHandler.java | 3 +- .../json/schema/loader/SchemaLoader.java | 10 ++-- .../schema/loader/SpecificationVersion.java | 5 +- .../json/schema/FormatValidatorTest.java | 3 +- .../internal/DefaultFormatValidatorTest.java | 7 +++ .../json/schema/V201909TestSuiteTest.java | 49 +++++++++++++++++++ .../json/schema/draft201909/duration.json | 18 +++++++ 9 files changed, 119 insertions(+), 6 deletions(-) create mode 100644 core/src/main/java/org/everit/json/schema/internal/DurationFormatValidator.java create mode 100644 tests/vanilla/src/main/java/org/everit/json/schema/V201909TestSuiteTest.java create mode 100644 tests/vanilla/src/main/resources/org/everit/json/schema/draft201909/duration.json 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..1c1879cc0 100644 --- a/core/src/main/java/org/everit/json/schema/FormatValidator.java +++ b/core/src/main/java/org/everit/json/schema/FormatValidator.java @@ -5,6 +5,7 @@ import java.util.Optional; import org.everit.json.schema.internal.DateTimeFormatValidator; +import org.everit.json.schema.internal.DurationFormatValidator; import org.everit.json.schema.internal.EmailFormatValidator; import org.everit.json.schema.internal.HostnameFormatValidator; import org.everit.json.schema.internal.IPV4Validator; @@ -54,6 +55,8 @@ static FormatValidator forFormat(final String formatName) { return new IPV4Validator(); case "ipv6": return new IPV6Validator(); + case "duration": + return new DurationFormatValidator(); default: throw new IllegalArgumentException("unsupported format: " + formatName); } diff --git a/core/src/main/java/org/everit/json/schema/internal/DurationFormatValidator.java b/core/src/main/java/org/everit/json/schema/internal/DurationFormatValidator.java new file mode 100644 index 000000000..0b9caac95 --- /dev/null +++ b/core/src/main/java/org/everit/json/schema/internal/DurationFormatValidator.java @@ -0,0 +1,27 @@ +package org.everit.json.schema.internal; + +import org.everit.json.schema.FormatValidator; + +import java.time.Duration; +import java.time.format.DateTimeParseException; +import java.util.Optional; + +/** + * Implementation of the `duration` format value. + */ +public class DurationFormatValidator implements FormatValidator { + @Override + public Optional validate(String subject) { + try { + Duration.parse(subject); + return Optional.empty(); + } catch (DateTimeParseException ex) { + return Optional.of(String.format("[%s] is not a valid %s. Expected ISO-8601 duration format", subject, formatName())); + } + } + + @Override + public String formatName() { + return "duration"; + } +} diff --git a/core/src/main/java/org/everit/json/schema/loader/ExclusiveLimitHandler.java b/core/src/main/java/org/everit/json/schema/loader/ExclusiveLimitHandler.java index 887284a1b..2195c91be 100644 --- a/core/src/main/java/org/everit/json/schema/loader/ExclusiveLimitHandler.java +++ b/core/src/main/java/org/everit/json/schema/loader/ExclusiveLimitHandler.java @@ -35,7 +35,8 @@ static ExclusiveLimitHandler ofSpecVersion(SpecificationVersion specVersion) { switch (specVersion) { case DRAFT_4: return new V4ExclusiveLimitHandler(); case DRAFT_6: - case DRAFT_7: return new V6ExclusiveLimitHandler(); + case DRAFT_7: + case DRAFT_201909: return new V6ExclusiveLimitHandler(); default: throw new RuntimeException("unknown spec version: " + specVersion); } } 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 17090aa78..a21abbea8 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 @@ -5,9 +5,7 @@ import static java.util.Objects.requireNonNull; import static java.util.stream.Collectors.toList; import static org.everit.json.schema.loader.OrgJsonUtil.toMap; -import static org.everit.json.schema.loader.SpecificationVersion.DRAFT_4; -import static org.everit.json.schema.loader.SpecificationVersion.DRAFT_6; -import static org.everit.json.schema.loader.SpecificationVersion.DRAFT_7; +import static org.everit.json.schema.loader.SpecificationVersion.*; import java.net.URI; import java.net.URISyntaxException; @@ -125,6 +123,12 @@ public SchemaLoaderBuilder draftV7Support() { return this; } + public SchemaLoaderBuilder draftV201909Support() { + setSpecVersion(DRAFT_201909); + specVersionIsExplicitlySet = true; + return this; + } + private void setSpecVersion(SpecificationVersion specVersion) { this.specVersion = specVersion; } 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 a3e5ea6f2..f4b00d81f 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 @@ -3,6 +3,7 @@ import org.everit.json.schema.FormatValidator; import org.everit.json.schema.internal.DateFormatValidator; import org.everit.json.schema.internal.DateTimeFormatValidator; +import org.everit.json.schema.internal.DurationFormatValidator; import org.everit.json.schema.internal.EmailFormatValidator; import org.everit.json.schema.internal.HostnameFormatValidator; import org.everit.json.schema.internal.IPV4Validator; @@ -203,7 +204,9 @@ private static List keywords(String... keywords) { new RelativeJsonPointerFormatValidator() ); - private static final Map V201909_VALIDATORS = formatValidators(V7_VALIDATORS); + private static final Map V201909_VALIDATORS = formatValidators(V7_VALIDATORS, + new DurationFormatValidator() + ); private static Map formatValidators(Map parent, FormatValidator... validators) { Map validatorMap = (parent == null) ? new HashMap<>() : new HashMap<>(parent); diff --git a/core/src/test/java/org/everit/json/schema/FormatValidatorTest.java b/core/src/test/java/org/everit/json/schema/FormatValidatorTest.java index b85958926..d10a55580 100644 --- a/core/src/test/java/org/everit/json/schema/FormatValidatorTest.java +++ b/core/src/test/java/org/everit/json/schema/FormatValidatorTest.java @@ -34,7 +34,8 @@ public static List params() { new Object[] { "hostname" }, new Object[] { "ipv6" }, new Object[] { "ipv4" }, - new Object[] { "uri" } + new Object[] { "uri" }, + new Object[] { "duration" } ); } 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..759b43b11 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 @@ -348,4 +348,11 @@ public void regexFailure() { assertFailure("^(abc]", new RegexFormatValidator(), "[^(abc]] is not a valid regular expression"); } + @Test + public void durationSuccess() { + assertSuccess("P1D", new DurationFormatValidator()); + assertSuccess("PT1H", new DurationFormatValidator()); + assertSuccess("PT20.345S", new DurationFormatValidator()); + assertSuccess("P2DT3H4M", new DurationFormatValidator()); + } } diff --git a/tests/vanilla/src/main/java/org/everit/json/schema/V201909TestSuiteTest.java b/tests/vanilla/src/main/java/org/everit/json/schema/V201909TestSuiteTest.java new file mode 100644 index 000000000..03bc0d653 --- /dev/null +++ b/tests/vanilla/src/main/java/org/everit/json/schema/V201909TestSuiteTest.java @@ -0,0 +1,49 @@ +package org.everit.json.schema; + +import org.everit.json.schema.loader.SchemaLoader; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.util.List; + +@RunWith(Parameterized.class) +public class V201909TestSuiteTest { + + + private static JettyWrapper server; + + @Parameterized.Parameters(name = "{1}") + public static List params() { + return TestCase.loadAsParamsFromPackage("org.everit.json.schema.draft201909"); + } + + @BeforeClass + public static void startJetty() throws Exception { + (server = new JettyWrapper("/org/everit/json/schema/remotes")).start(); + } + + @AfterClass + public static void stopJetty() throws Exception { + server.stop(); + } + + private TestCase tc; + + public V201909TestSuiteTest(TestCase testcase, String descr) { + this.tc = testcase; + tc.loadSchema(SchemaLoader.builder().draftV201909Support()); + } + + @Test + public void testInCollectingMode() { + tc.runTestInCollectingMode(); + } + + @Test + public void testInEarlyFailingMode() { + tc.runTestInEarlyFailureMode(); + } + } diff --git a/tests/vanilla/src/main/resources/org/everit/json/schema/draft201909/duration.json b/tests/vanilla/src/main/resources/org/everit/json/schema/draft201909/duration.json new file mode 100644 index 000000000..68e4799f5 --- /dev/null +++ b/tests/vanilla/src/main/resources/org/everit/json/schema/draft201909/duration.json @@ -0,0 +1,18 @@ +[ + { + "description": "validation of duration strings", + "schema": {"format": "duration"}, + "tests": [ + { + "description": "a valid duration string", + "data": "P4DT12H30M5S", + "valid": true + }, + { + "description": "an invalid duration string", + "data": "PT1D", + "valid": false + } + ] + } +]