Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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<String> 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";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -103,6 +104,30 @@ public enum SpecificationVersion {
@Override Map<String, FormatValidator> defaultFormatValidators() {
return V7_VALIDATORS;
}

}, DRAFT_201909 {
@Override List<String> arrayKeywords() {
return V2019_ARRAY_KEYWORDS;
}

@Override List<String> objectKeywords() {
return V2019_OBJECT_KEYWORDS;
}

@Override public String idKeyword() {
return DRAFT_6.idKeyword();
}

@Override List<String> metaSchemaUrls() {
return Arrays.asList(
"http://json-schema.org/draft/2019-09/schema",
"https://json-schema.org/draft/2019-09/schema"
);
}

@Override Map<String, FormatValidator> defaultFormatValidators() {
return V201909_VALIDATORS;
}
};

static SpecificationVersion getByMetaSchemaUrl(String metaSchemaUrl) {
Expand All @@ -118,6 +143,18 @@ public static Optional<SpecificationVersion> lookupByMetaSchemaUrl(String metaSc
.findFirst();
}

private static final List<String> V2019_OBJECT_KEYWORDS = keywords("properties", "required",
"minProperties",
"maxProperties",
"dependencies",
"patternProperties",
"additionalProperties",
"propertyNames",
"dependentSchemas");

private static final List<String> V2019_ARRAY_KEYWORDS = keywords("items", "additionalItems", "minItems",
"maxItems", "uniqueItems", "contains", "unevaluatedItems");

private static final List<String> V6_OBJECT_KEYWORDS = keywords("properties", "required",
"minProperties",
"maxProperties",
Expand Down Expand Up @@ -167,6 +204,10 @@ private static List<String> keywords(String... keywords) {
new RelativeJsonPointerFormatValidator()
);

private static final Map<String, FormatValidator> V201909_VALIDATORS = formatValidators(V7_VALIDATORS,
new DurationFormatValidator()
);

private static Map<String, FormatValidator> formatValidators(Map<String, FormatValidator> parent, FormatValidator... validators) {
Map<String, FormatValidator> validatorMap = (parent == null) ? new HashMap<>() : new HashMap<>(parent);
for (FormatValidator validator : validators) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ public static List<Object[]> params() {
new Object[] { "hostname" },
new Object[] { "ipv6" },
new Object[] { "ipv4" },
new Object[] { "uri" }
new Object[] { "uri" },
new Object[] { "duration" }
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -730,5 +730,9 @@
}
}
}
},
"explicitSchemaVersionFor201909": {
"$schema": "http://json-schema.org/draft/2019-09/schema",
"type": "object"
}
}
Original file line number Diff line number Diff line change
@@ -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<Object[]> 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();
}
}
Original file line number Diff line number Diff line change
@@ -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
}
]
}
]