diff --git a/README.md b/README.md
index 94317dbd..3f9e87b0 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,14 @@
-[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=sebastian-toepfer_json-schema&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=sebastian-toepfer_json-schema)
-[![Reproducible Builds](https://img.shields.io/badge/Reproducible_Builds-ok-success?labelColor=1e5b96)](https://github.com/jvm-repo-rebuild/reproducible-central#io.github.sebastian-toepfer.json-schema:json-schema)
+![Sonar Quality Gate](https://img.shields.io/sonar/quality_gate/sebastian-toepfer_json-schema?server=https%3A%2F%2Fsonarcloud.io)
+![Sonar Tests](https://img.shields.io/sonar/tests/sebastian-toepfer_json-schema?server=https%3A%2F%2Fsonarcloud.io)
+![Sonar Violations](https://img.shields.io/sonar/violations/sebastian-toepfer_json-schema?server=https%3A%2F%2Fsonarcloud.io)
+
+![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/sebastian-toepfer/json-schema/build.yml)
+
+![Maven Central Version](https://img.shields.io/maven-central/v/io.github.sebastian-toepfer.json-schema/json-schema)
+![GitHub Release](https://img.shields.io/github/v/release/sebastian-toepfer/json-schema)
+![GitHub commits since latest release](https://img.shields.io/github/commits-since/sebastian-toepfer/json-schema/latest)
+
+[![Reproducible Builds](https://img.shields.io/badge/Reproducible_Builds-ok-success?labelColor=1e5b96)](https://github.com/jvm-repo-rebuild/reproducible-central/blob/master/content/io/github/sebastian-toepfer/json-schema/json-schema/README.md)
# json-schema
json schema for json-api
diff --git a/api/pom.xml b/api/pom.xml
index 1389663e..96e27abf 100644
--- a/api/pom.xml
+++ b/api/pom.xml
@@ -5,7 +5,7 @@
io.github.sebastian-toepfer.json-schema
json-schema
- 0.2.1
+ 0.3.0-SNAPSHOT
json-schema-api
diff --git a/core/pom.xml b/core/pom.xml
index 92c55112..8f77065e 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -6,7 +6,7 @@
io.github.sebastian-toepfer.json-schema
json-schema
- 0.2.1
+ 0.3.0-SNAPSHOT
json-schema-core
@@ -81,14 +81,7 @@
com.google.errorprone
error_prone_annotations
test
-
-
-
- jakarta.json
- jakarta.json-api
- provided
-
-
+
org.eclipse.parsson
parsson
@@ -99,6 +92,17 @@
media-core
test
+
+ nl.jqno.equalsverifier
+ equalsverifier
+ test
+
+
+
+ jakarta.json
+ jakarta.json-api
+ provided
+
com.github.spotbugs
@@ -117,10 +121,14 @@
**/tests/draft2019-09/additionalItems.json
-->
**/tests/draft2020-12/additionalProperties.json
+ **/tests/draft2020-12/allOf.json
+ **/tests/draft2020-12/anyOf.json
+ **/tests/draft2020-12/oneOf.json
**/tests/draft2020-12/boolean_schema.json
**/tests/draft2020-12/const.json
**/tests/draft2020-12/contains.json
**/tests/draft2020-12/dependentRequired.json
+ **/tests/draft2020-12/dependentSchemas.json
**/tests/draft2020-12/enum.json
**/tests/draft2020-12/exclusiveMaximum.json
**/tests/draft2020-12/exclusiveMinimum.json
@@ -139,6 +147,9 @@
**/tests/draft2020-12/minLength.json
**/tests/draft2020-12/minimum.json
**/tests/draft2020-12/minProperties.json
+
**/tests/draft2020-12/multipleOf.json
**/tests/draft2020-12/pattern.json
**/tests/draft2020-12/patternProperties.json
diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/AbstractJsonValueSchema.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/AbstractJsonValueSchema.java
index 09a7ea53..a916aa78 100644
--- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/AbstractJsonValueSchema.java
+++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/AbstractJsonValueSchema.java
@@ -51,4 +51,9 @@ public final JsonObject asJsonObject() {
public final JsonArray asJsonArray() {
return value.asJsonArray();
}
+
+ @Override
+ public String toString() {
+ return value.toString();
+ }
}
diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/DefaultJsonSubSchema.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/DefaultJsonSubSchema.java
index ea5b225b..639dc4f6 100644
--- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/DefaultJsonSubSchema.java
+++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/DefaultJsonSubSchema.java
@@ -116,4 +116,9 @@ public ValueType getValueType() {
public JsonObject asJsonObject() {
return schema.asJsonObject();
}
+
+ @Override
+ public String toString() {
+ return schema.toString();
+ }
}
diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/Keywords.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/Keywords.java
index 8ee64c12..df243365 100644
--- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/Keywords.java
+++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/Keywords.java
@@ -29,7 +29,11 @@
import io.github.sebastiantoepfer.jsonschema.JsonSchema;
import io.github.sebastiantoepfer.jsonschema.Vocabulary;
import io.github.sebastiantoepfer.jsonschema.core.vocab.applicator.ApplicatorVocabulary;
+import io.github.sebastiantoepfer.jsonschema.core.vocab.content.ContentVocabulary;
import io.github.sebastiantoepfer.jsonschema.core.vocab.core.CoreVocabulary;
+import io.github.sebastiantoepfer.jsonschema.core.vocab.format.FormatAnnotationVocabulary;
+import io.github.sebastiantoepfer.jsonschema.core.vocab.meta.MetaDataVocabulary;
+import io.github.sebastiantoepfer.jsonschema.core.vocab.unevaluated.UnevaluatedVocabulary;
import io.github.sebastiantoepfer.jsonschema.core.vocab.validation.ValidationVocabulary;
import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.VocabularyDefinition;
@@ -54,7 +58,14 @@ final class Keywords {
.stream()
.collect(toMap(Vocabulary::id, Function.identity()));
- DEFAULT_VOCABS = List.of(new ValidationVocabulary(JsonProvider.provider()), new ApplicatorVocabulary());
+ DEFAULT_VOCABS = List.of(
+ new ApplicatorVocabulary(),
+ new ValidationVocabulary(JsonProvider.provider()),
+ new MetaDataVocabulary(),
+ new FormatAnnotationVocabulary(),
+ new UnevaluatedVocabulary(),
+ new ContentVocabulary()
+ );
}
private final Collection vocabularies;
@@ -63,8 +74,8 @@ public Keywords(final Collection vocabDefs) {
if (
vocabDefs
.stream()
- .filter(vocabDef -> MANDANTORY_VOCABS.containsKey(vocabDef.id()))
- .anyMatch(not(VocabularyDefinition::required))
+ .filter(vocabDef -> MANDANTORY_VOCABS.keySet().stream().anyMatch(vocabDef::hasid))
+ .anyMatch(not(VocabularyDefinition::isRequired))
) {
throw new IllegalArgumentException("can not be created without core vocabulary is requiered!");
}
diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/type/AffectByType.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/type/AffectByType.java
new file mode 100644
index 00000000..de1ef5d6
--- /dev/null
+++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/type/AffectByType.java
@@ -0,0 +1,43 @@
+/*
+ * The MIT License
+ *
+ * Copyright 2024 sebastian.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package io.github.sebastiantoepfer.jsonschema.core.keyword.type;
+
+import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
+
+public enum AffectByType {
+ EXTENDS {
+ @Override
+ Keyword affect(final Keyword affectedKeyword) {
+ return affectedKeyword;
+ }
+ },
+ REPLACE {
+ @Override
+ Keyword affect(final Keyword affectedKeyword) {
+ return new ReplacingKeyword(affectedKeyword);
+ }
+ };
+
+ abstract Keyword affect(final Keyword affectedKeyword);
+}
diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/type/AffectedBy.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/type/AffectedBy.java
new file mode 100644
index 00000000..0418be5c
--- /dev/null
+++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/type/AffectedBy.java
@@ -0,0 +1,89 @@
+/*
+ * The MIT License
+ *
+ * Copyright 2024 sebastian.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package io.github.sebastiantoepfer.jsonschema.core.keyword.type;
+
+import io.github.sebastiantoepfer.jsonschema.JsonSchema;
+import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
+import java.util.Objects;
+import java.util.function.Function;
+import java.util.function.UnaryOperator;
+
+public final class AffectedBy implements Comparable {
+
+ private final AffectByType type;
+ private final String name;
+
+ public AffectedBy(final AffectByType type, final String name) {
+ this.type = Objects.requireNonNull(type);
+ this.name = Objects.requireNonNull(name);
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 7;
+ hash = 83 * hash + Objects.hashCode(this.type);
+ hash = 83 * hash + Objects.hashCode(this.name);
+ return hash;
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ return compareTo((AffectedBy) obj) == 0;
+ }
+
+ @Override
+ public int compareTo(final AffectedBy other) {
+ final int result;
+ if (type.compareTo(other.type) == 0) {
+ result = name.compareTo(other.name);
+ } else {
+ result = type.compareTo(other.type);
+ }
+ return result;
+ }
+
+ Function findAffectedByKeywordIn(final JsonSchema schema) {
+ final UnaryOperator result;
+ if (schema.keywordByName(name).isPresent()) {
+ result = type::affect;
+ } else {
+ result = k -> k;
+ }
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "AffectedBy{" + "type=" + type + ", name=" + name + '}';
+ }
+}
diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/type/AffectedByKeywordType.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/type/AffectedByKeywordType.java
index ab528879..4f16fd38 100644
--- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/type/AffectedByKeywordType.java
+++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/type/AffectedByKeywordType.java
@@ -23,28 +23,30 @@
*/
package io.github.sebastiantoepfer.jsonschema.core.keyword.type;
-import static java.util.stream.Collectors.collectingAndThen;
-import static java.util.stream.Collectors.toList;
-
import io.github.sebastiantoepfer.jsonschema.JsonSchema;
import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
import io.github.sebastiantoepfer.jsonschema.keyword.KeywordType;
+import java.util.Collection;
import java.util.List;
import java.util.Objects;
-import java.util.Optional;
-import java.util.function.BiFunction;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import java.util.function.Function;
-public class AffectedByKeywordType implements KeywordType {
+public final class AffectedByKeywordType implements KeywordType {
private final String name;
- private final List affectedBy;
- private final BiFunction, JsonSchema, Keyword> keywordCreator;
+ private final Collection affectedBy;
+ private final Function keywordCreator;
public AffectedByKeywordType(
final String name,
- final List affectedBy,
- final BiFunction, JsonSchema, Keyword> keywordCreator
+ final Collection affectedBy,
+ final Function keywordCreator
) {
+ if (affectedBy.isEmpty()) {
+ throw new IllegalArgumentException("affectedBy can not be empty!");
+ }
this.name = Objects.requireNonNull(name);
this.affectedBy = List.copyOf(affectedBy);
this.keywordCreator = Objects.requireNonNull(keywordCreator);
@@ -57,24 +59,24 @@ public String name() {
@Override
public Keyword createKeyword(final JsonSchema schema) {
- return new AffectedByKeyword(schema, name, affectedBy, keywordCreator);
+ return new AffectedKeyword(schema, name, affectedBy, keywordCreator);
}
- static final class AffectedByKeyword extends KeywordRelationship {
+ static final class AffectedKeyword extends KeywordRelationship {
private final JsonSchema schema;
- private final List affectedBy;
- private final BiFunction, JsonSchema, Keyword> keywordCreator;
+ private final SortedSet affectedBy;
+ private final Function keywordCreator;
- public AffectedByKeyword(
+ public AffectedKeyword(
final JsonSchema schema,
final String name,
- final List affectedBy,
- final BiFunction, JsonSchema, Keyword> keywordCreator
+ final Collection affectedBy,
+ final Function keywordCreator
) {
super(name);
this.schema = Objects.requireNonNull(schema);
- this.affectedBy = List.copyOf(affectedBy);
+ this.affectedBy = new TreeSet<>(affectedBy);
this.keywordCreator = Objects.requireNonNull(keywordCreator);
}
@@ -82,9 +84,10 @@ public AffectedByKeyword(
protected Keyword delegate() {
return affectedBy
.stream()
- .map(schema::keywordByName)
- .flatMap(Optional::stream)
- .collect(collectingAndThen(toList(), k -> keywordCreator.apply(k, schema)));
+ .map(a -> a.findAffectedByKeywordIn(schema))
+ .reduce(Function::andThen)
+ .orElseThrow()
+ .apply(keywordCreator.apply(schema));
}
}
}
diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/type/Affects.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/type/Affects.java
new file mode 100644
index 00000000..62c181d3
--- /dev/null
+++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/type/Affects.java
@@ -0,0 +1,94 @@
+/*
+ * The MIT License
+ *
+ * Copyright 2024 sebastian.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package io.github.sebastiantoepfer.jsonschema.core.keyword.type;
+
+import io.github.sebastiantoepfer.jsonschema.JsonSchema;
+import io.github.sebastiantoepfer.jsonschema.keyword.Annotation;
+import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
+import io.github.sebastiantoepfer.jsonschema.keyword.StaticAnnotation;
+import jakarta.json.JsonValue;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.function.Function;
+
+public final class Affects {
+
+ private final String name;
+ private final AbsenceStrategy strategy;
+
+ public Affects(final String name, final JsonValue answerInAbsence) {
+ this(name, new ProvideDefaultValue(answerInAbsence));
+ }
+
+ public Affects(final String name, final AbsenceStrategy strategy) {
+ this.name = Objects.requireNonNull(name);
+ this.strategy = Objects.requireNonNull(strategy);
+ }
+
+ @Override
+ public String toString() {
+ return "Affects{" + "name=" + name + ", strategy=" + strategy.getClass() + '}';
+ }
+
+ Map.Entry> findAffectsKeywordIn(final JsonSchema schema) {
+ final Map.Entry> result;
+ final Optional annotation = schema
+ .keywordByName(name)
+ .filter(k -> k.hasCategory(Keyword.KeywordCategory.ANNOTATION))
+ .map(Keyword::asAnnotation);
+ if (annotation.isPresent()) {
+ result = Map.entry(annotation.get(), k -> k);
+ } else {
+ result = strategy.create(name);
+ }
+ return result;
+ }
+
+ public interface AbsenceStrategy {
+ Map.Entry> create(String name);
+ }
+
+ public static final class ReplaceKeyword implements AbsenceStrategy {
+
+ @Override
+ public Map.Entry> create(final String name) {
+ return Map.entry(new StaticAnnotation(name, JsonValue.NULL), ReplacingKeyword::new);
+ }
+ }
+
+ public static final class ProvideDefaultValue implements AbsenceStrategy {
+
+ private final JsonValue answerInAbsence;
+
+ public ProvideDefaultValue(final JsonValue answerInAbsence) {
+ this.answerInAbsence = Objects.requireNonNullElse(answerInAbsence, JsonValue.NULL);
+ }
+
+ @Override
+ public Map.Entry> create(final String name) {
+ return Map.entry(new StaticAnnotation(name, answerInAbsence), k -> k);
+ }
+ }
+}
diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/type/AffectsKeywordType.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/type/AffectsKeywordType.java
index 33a27e87..5cf8620d 100644
--- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/type/AffectsKeywordType.java
+++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/type/AffectsKeywordType.java
@@ -27,24 +27,27 @@
import io.github.sebastiantoepfer.jsonschema.keyword.Annotation;
import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
import io.github.sebastiantoepfer.jsonschema.keyword.KeywordType;
-import io.github.sebastiantoepfer.jsonschema.keyword.StaticAnnotation;
-import jakarta.json.JsonValue;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.function.BiFunction;
+import java.util.function.Function;
public class AffectsKeywordType implements KeywordType {
private final String name;
- private final String affects;
- private final BiFunction keywordCreator;
+ private final Collection affects;
+ private final BiFunction, JsonSchema, Keyword> keywordCreator;
public AffectsKeywordType(
final String name,
- final String affects,
- final BiFunction keywordCreator
+ final Collection affects,
+ final BiFunction, JsonSchema, Keyword> keywordCreator
) {
- this.name = name;
- this.affects = affects;
+ this.name = Objects.requireNonNull(name);
+ this.affects = List.copyOf(affects);
this.keywordCreator = keywordCreator;
}
@@ -55,36 +58,46 @@ public String name() {
@Override
public Keyword createKeyword(final JsonSchema schema) {
- return new AffectsKeyword(schema, name, affects, keywordCreator);
+ return new AffectsKeyword(schema, name, List.copyOf(affects), keywordCreator);
}
static final class AffectsKeyword extends KeywordRelationship {
private final JsonSchema schema;
- private final String affects;
- private final BiFunction keywordCreator;
+ private final Collection affects;
+ private final BiFunction, JsonSchema, Keyword> keywordCreator;
public AffectsKeyword(
final JsonSchema schema,
final String name,
- final String affects,
- final BiFunction keywordCreator
+ final List affects,
+ final BiFunction, JsonSchema, Keyword> keywordCreator
) {
super(name);
this.schema = Objects.requireNonNull(schema);
- this.affects = affects;
+ this.affects = List.copyOf(affects);
this.keywordCreator = Objects.requireNonNull(keywordCreator);
}
@Override
protected Keyword delegate() {
- return keywordCreator.apply(
- schema
- .keywordByName(affects)
- .map(Keyword::asAnnotation)
- .orElseGet(() -> new StaticAnnotation(affects, JsonValue.NULL)),
- schema
- );
+ //ugly ... map.entry is not the right structure ...
+ final Map.Entry, Function> p = affects
+ .stream()
+ .map(a -> a.findAffectsKeywordIn(schema))
+ .reduce(
+ Map.entry(List.of(), k -> k),
+ (
+ Map.Entry, Function> t,
+ Map.Entry> u
+ ) -> {
+ final ArrayList newAnnotations = new ArrayList<>(t.getKey());
+ newAnnotations.add(u.getKey());
+ return Map.entry(newAnnotations, t.getValue().andThen(u.getValue()));
+ },
+ (l, r) -> null
+ );
+ return p.getValue().apply(keywordCreator.apply(p.getKey(), schema));
}
}
}
diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/type/ReplacingKeyword.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/type/ReplacingKeyword.java
new file mode 100644
index 00000000..39d5a619
--- /dev/null
+++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/type/ReplacingKeyword.java
@@ -0,0 +1,114 @@
+/*
+ * The MIT License
+ *
+ * Copyright 2024 sebastian.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package io.github.sebastiantoepfer.jsonschema.core.keyword.type;
+
+import static java.util.function.Predicate.not;
+import static java.util.stream.Collectors.toSet;
+
+import io.github.sebastiantoepfer.ddd.common.Media;
+import io.github.sebastiantoepfer.jsonschema.keyword.Annotation;
+import io.github.sebastiantoepfer.jsonschema.keyword.Applicator;
+import io.github.sebastiantoepfer.jsonschema.keyword.Assertion;
+import io.github.sebastiantoepfer.jsonschema.keyword.Identifier;
+import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
+import io.github.sebastiantoepfer.jsonschema.keyword.ReservedLocation;
+import java.util.Collection;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Objects;
+
+final class ReplacingKeyword implements Keyword {
+
+ private final Keyword keywordToReplace;
+ private final Collection categoriesToReplace;
+
+ public ReplacingKeyword(final Keyword keywordToReplace) {
+ this(keywordToReplace, EnumSet.of(KeywordCategory.APPLICATOR, KeywordCategory.ASSERTION));
+ }
+
+ public ReplacingKeyword(final Keyword keywordToReplace, final Collection categoriesToReplace) {
+ this.keywordToReplace = Objects.requireNonNull(keywordToReplace);
+ this.categoriesToReplace = List.copyOf(categoriesToReplace);
+ }
+
+ @Override
+ public Identifier asIdentifier() {
+ if (categoriesToReplace.contains(KeywordCategory.IDENTIFIER)) {
+ throw new UnsupportedOperationException();
+ } else {
+ return keywordToReplace.asIdentifier();
+ }
+ }
+
+ @Override
+ public Assertion asAssertion() {
+ if (categoriesToReplace.contains(KeywordCategory.ASSERTION)) {
+ throw new UnsupportedOperationException();
+ } else {
+ return keywordToReplace.asAssertion();
+ }
+ }
+
+ @Override
+ public Annotation asAnnotation() {
+ if (categoriesToReplace.contains(KeywordCategory.ANNOTATION)) {
+ throw new UnsupportedOperationException();
+ } else {
+ return keywordToReplace.asAnnotation();
+ }
+ }
+
+ @Override
+ public Applicator asApplicator() {
+ if (categoriesToReplace.contains(KeywordCategory.APPLICATOR)) {
+ throw new UnsupportedOperationException();
+ } else {
+ return keywordToReplace.asApplicator();
+ }
+ }
+
+ @Override
+ public ReservedLocation asReservedLocation() {
+ if (categoriesToReplace.contains(KeywordCategory.RESERVED_LOCATION)) {
+ throw new UnsupportedOperationException();
+ } else {
+ return keywordToReplace.asReservedLocation();
+ }
+ }
+
+ @Override
+ public Collection categories() {
+ return keywordToReplace.categories().stream().filter(not(categoriesToReplace::contains)).collect(toSet());
+ }
+
+ @Override
+ public boolean hasName(final String string) {
+ return keywordToReplace.hasName(string);
+ }
+
+ @Override
+ public > T printOn(final T media) {
+ return keywordToReplace.printOn(media);
+ }
+}
diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/type/ArraySubSchemaKeywordType.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/type/SchemaArrayKeywordType.java
similarity index 91%
rename from core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/type/ArraySubSchemaKeywordType.java
rename to core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/type/SchemaArrayKeywordType.java
index 77ac2eb4..9dcbeb2b 100644
--- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/type/ArraySubSchemaKeywordType.java
+++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/type/SchemaArrayKeywordType.java
@@ -33,12 +33,12 @@
import java.util.Objects;
import java.util.function.Function;
-public final class ArraySubSchemaKeywordType implements KeywordType {
+public final class SchemaArrayKeywordType implements KeywordType {
private final String name;
private final Function, Keyword> keywordCreator;
- public ArraySubSchemaKeywordType(final String name, final Function, Keyword> keywordCreator) {
+ public SchemaArrayKeywordType(final String name, final Function, Keyword> keywordCreator) {
this.name = Objects.requireNonNull(name);
this.keywordCreator = Objects.requireNonNull(keywordCreator);
}
diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/OfficialVocabularies.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/OfficialVocabularies.java
index 306bde21..78d53762 100644
--- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/OfficialVocabularies.java
+++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/OfficialVocabularies.java
@@ -27,7 +27,7 @@
import io.github.sebastiantoepfer.jsonschema.core.vocab.applicator.ApplicatorVocabulary;
import io.github.sebastiantoepfer.jsonschema.core.vocab.content.ContentVocabulary;
import io.github.sebastiantoepfer.jsonschema.core.vocab.core.CoreVocabulary;
-import io.github.sebastiantoepfer.jsonschema.core.vocab.format.FormatVocabulary;
+import io.github.sebastiantoepfer.jsonschema.core.vocab.format.FormatAnnotationVocabulary;
import io.github.sebastiantoepfer.jsonschema.core.vocab.meta.MetaDataVocabulary;
import io.github.sebastiantoepfer.jsonschema.core.vocab.unevaluated.UnevaluatedVocabulary;
import io.github.sebastiantoepfer.jsonschema.core.vocab.validation.ValidationVocabulary;
@@ -49,7 +49,7 @@ public final class OfficialVocabularies implements LazyVocabularies {
new ApplicatorVocabulary(),
new ValidationVocabulary(JSONP),
new MetaDataVocabulary(),
- new FormatVocabulary(),
+ new FormatAnnotationVocabulary(),
new UnevaluatedVocabulary(),
new ContentVocabulary()
);
diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/AdditionalPropertiesKeyword.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/AdditionalPropertiesKeyword.java
index 85714078..52571818 100644
--- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/AdditionalPropertiesKeyword.java
+++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/AdditionalPropertiesKeyword.java
@@ -23,9 +23,11 @@
*/
package io.github.sebastiantoepfer.jsonschema.core.vocab.applicator;
+import static java.util.function.Predicate.not;
+
import io.github.sebastiantoepfer.ddd.common.Media;
import io.github.sebastiantoepfer.jsonschema.InstanceType;
-import io.github.sebastiantoepfer.jsonschema.JsonSubSchema;
+import io.github.sebastiantoepfer.jsonschema.JsonSchema;
import io.github.sebastiantoepfer.jsonschema.keyword.Annotation;
import io.github.sebastiantoepfer.jsonschema.keyword.Applicator;
import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
@@ -38,8 +40,6 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
-import java.util.Optional;
-import java.util.function.Predicate;
import java.util.stream.Stream;
/**
@@ -61,10 +61,15 @@
final class AdditionalPropertiesKeyword implements Applicator, Annotation {
static final String NAME = "additionalProperties";
- private final JsonSubSchema additionalPropertiesSchema;
+ private final Collection affectedBy;
+ private final JsonSchema additionalPropertiesSchema;
- public AdditionalPropertiesKeyword(final JsonSubSchema additionalPropertiesSchema) {
+ public AdditionalPropertiesKeyword(
+ final Collection affectedBy,
+ final JsonSchema additionalPropertiesSchema
+ ) {
this.additionalPropertiesSchema = additionalPropertiesSchema;
+ this.affectedBy = List.copyOf(affectedBy);
}
@Override
@@ -93,16 +98,12 @@ public JsonValue valueFor(final JsonValue instance) {
private Stream> findPropertiesForValidation(final JsonObject instance) {
final Collection ignoredProperties = findPropertyNamesAlreadyConveredByOthersIn(instance);
- return instance.entrySet().stream().filter(Predicate.not(e -> ignoredProperties.contains(e.getKey())));
+ return instance.entrySet().stream().filter(not(e -> ignoredProperties.contains(e.getKey())));
}
private Collection findPropertyNamesAlreadyConveredByOthersIn(final JsonValue instance) {
- return Stream.of(
- additionalPropertiesSchema.owner().keywordByName("properties"),
- additionalPropertiesSchema.owner().keywordByName("patternProperties")
- )
- .flatMap(Optional::stream)
- .map(Keyword::asAnnotation)
+ return affectedBy
+ .stream()
.map(anno -> anno.valueFor(instance))
.map(JsonValue::asJsonArray)
.flatMap(Collection::stream)
diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/AllOfKeyword.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/AllOfKeyword.java
new file mode 100644
index 00000000..b78dfe6e
--- /dev/null
+++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/AllOfKeyword.java
@@ -0,0 +1,70 @@
+/*
+ * The MIT License
+ *
+ * Copyright 2024 sebastian.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package io.github.sebastiantoepfer.jsonschema.core.vocab.applicator;
+
+import io.github.sebastiantoepfer.ddd.common.Media;
+import io.github.sebastiantoepfer.jsonschema.JsonSchema;
+import io.github.sebastiantoepfer.jsonschema.keyword.Applicator;
+import jakarta.json.JsonValue;
+import java.util.Collection;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * allOf : Array
+ * An instance validates successfully against this keyword if it validates successfully against all schemas defined by
+ * this keyword’s value.
+ *
+ * kind
+ *
+ *
+ * source: https://www.learnjsonschema.com/2020-12/applicator/allof/
+ * spec: https://json-schema.org/draft/2020-12/json-schema-core.html#section-10.2.1.1
+ */
+final class AllOfKeyword implements Applicator {
+
+ static final String NAME = "allOf";
+ private final Collection schemas;
+
+ public AllOfKeyword(final Collection schemas) {
+ this.schemas = List.copyOf(schemas);
+ }
+
+ @Override
+ public boolean applyTo(final JsonValue instance) {
+ return schemas.stream().map(JsonSchema::validator).allMatch(v -> v.isValid(instance));
+ }
+
+ @Override
+ public boolean hasName(final String name) {
+ return Objects.equals(NAME, name);
+ }
+
+ @Override
+ public > T printOn(final T media) {
+ return media.withValue(NAME, schemas);
+ }
+}
diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/AnyOfKeyword.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/AnyOfKeyword.java
new file mode 100644
index 00000000..79db69af
--- /dev/null
+++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/AnyOfKeyword.java
@@ -0,0 +1,57 @@
+/*
+ * The MIT License
+ *
+ * Copyright 2024 sebastian.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package io.github.sebastiantoepfer.jsonschema.core.vocab.applicator;
+
+import io.github.sebastiantoepfer.ddd.common.Media;
+import io.github.sebastiantoepfer.jsonschema.JsonSchema;
+import io.github.sebastiantoepfer.jsonschema.keyword.Applicator;
+import jakarta.json.JsonValue;
+import java.util.Collection;
+import java.util.List;
+import java.util.Objects;
+
+final class AnyOfKeyword implements Applicator {
+
+ static final String NAME = "anyOf";
+ private final Collection schemas;
+
+ public AnyOfKeyword(final Collection schemas) {
+ this.schemas = List.copyOf(schemas);
+ }
+
+ @Override
+ public boolean applyTo(final JsonValue instance) {
+ return schemas.stream().map(JsonSchema::validator).anyMatch(v -> v.isValid(instance));
+ }
+
+ @Override
+ public boolean hasName(final String name) {
+ return Objects.equals(NAME, name);
+ }
+
+ @Override
+ public > T printOn(final T media) {
+ return media.withValue(NAME, schemas);
+ }
+}
diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/ApplicatorVocabulary.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/ApplicatorVocabulary.java
index ba3a0076..75384f96 100644
--- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/ApplicatorVocabulary.java
+++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/ApplicatorVocabulary.java
@@ -24,12 +24,18 @@
package io.github.sebastiantoepfer.jsonschema.core.vocab.applicator;
import io.github.sebastiantoepfer.jsonschema.Vocabulary;
+import io.github.sebastiantoepfer.jsonschema.core.keyword.type.AffectByType;
+import io.github.sebastiantoepfer.jsonschema.core.keyword.type.AffectedBy;
import io.github.sebastiantoepfer.jsonschema.core.keyword.type.AffectedByKeywordType;
-import io.github.sebastiantoepfer.jsonschema.core.keyword.type.ArraySubSchemaKeywordType;
+import io.github.sebastiantoepfer.jsonschema.core.keyword.type.Affects;
+import io.github.sebastiantoepfer.jsonschema.core.keyword.type.AffectsKeywordType;
import io.github.sebastiantoepfer.jsonschema.core.keyword.type.NamedJsonSchemaKeywordType;
+import io.github.sebastiantoepfer.jsonschema.core.keyword.type.SchemaArrayKeywordType;
import io.github.sebastiantoepfer.jsonschema.core.keyword.type.SubSchemaKeywordType;
import io.github.sebastiantoepfer.jsonschema.keyword.KeywordType;
-import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.DefaultVocabulary;
+import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.ListVocabulary;
+import jakarta.json.Json;
+import jakarta.json.JsonValue;
import java.net.URI;
import java.util.List;
import java.util.Optional;
@@ -46,19 +52,55 @@ public final class ApplicatorVocabulary implements Vocabulary {
private final Vocabulary vocab;
public ApplicatorVocabulary() {
- this.vocab = new DefaultVocabulary(
+ this.vocab = new ListVocabulary(
URI.create("https://json-schema.org/draft/2020-12/vocab/applicator"),
+ new SchemaArrayKeywordType(AllOfKeyword.NAME, AllOfKeyword::new),
+ new SchemaArrayKeywordType(AnyOfKeyword.NAME, AnyOfKeyword::new),
+ new SchemaArrayKeywordType(OneOfKeyword.NAME, OneOfKeyword::new),
+ new SubSchemaKeywordType(NotKeyword.NAME, NotKeyword::new),
new NamedJsonSchemaKeywordType(PropertiesKeyword.NAME, PropertiesKeyword::new),
- new SubSchemaKeywordType(AdditionalPropertiesKeyword.NAME, AdditionalPropertiesKeyword::new),
+ //nomally affectedBy ... but we had the needed function only in affects :(
+ new AffectsKeywordType(
+ AdditionalPropertiesKeyword.NAME,
+ List.of(
+ new Affects("properties", JsonValue.EMPTY_JSON_ARRAY),
+ new Affects("patternProperties", JsonValue.EMPTY_JSON_ARRAY)
+ ),
+ (affects, schema) ->
+ new SubSchemaKeywordType(
+ AdditionalPropertiesKeyword.NAME,
+ s -> new AdditionalPropertiesKeyword(affects, s)
+ ).createKeyword(schema)
+ ),
new NamedJsonSchemaKeywordType(PatternPropertiesKeyword.NAME, PatternPropertiesKeyword::new),
- new SubSchemaKeywordType(ItemsKeyword.NAME, ItemsKeyword::new),
- new ArraySubSchemaKeywordType(PrefixItemsKeyword.NAME, PrefixItemsKeyword::new),
- //normally affeced by minContains and maxContains, but only min has a direct effect!
+ new NamedJsonSchemaKeywordType(DependentSchemasKeyword.NAME, DependentSchemasKeyword::new),
+ //this example shows my missunderstanding from affects, affectedBy and keywordtypes :(
+ new AffectedByKeywordType(
+ ItemsKeyword.NAME,
+ List.of(
+ new AffectedBy(AffectByType.EXTENDS, "minItems"),
+ new AffectedBy(AffectByType.EXTENDS, "maxItems")
+ ),
+ //nomally affectedBy too ... but we had the needed function only in affects :(
+ schema ->
+ new AffectsKeywordType(
+ ItemsKeyword.NAME,
+ List.of(new Affects("prefixItems", Json.createValue(-1))),
+ (affects, subSchema) ->
+ new SubSchemaKeywordType(
+ ItemsKeyword.NAME,
+ s -> new ItemsKeyword(affects, s)
+ ).createKeyword(subSchema)
+ ).createKeyword(schema)
+ ),
+ new SchemaArrayKeywordType(PrefixItemsKeyword.NAME, PrefixItemsKeyword::new),
new AffectedByKeywordType(
ContainsKeyword.NAME,
- List.of("minContains"),
- (a, schema) ->
- new SubSchemaKeywordType(ContainsKeyword.NAME, s -> new ContainsKeyword(a, s)).createKeyword(schema)
+ List.of(
+ new AffectedBy(AffectByType.REPLACE, "minContains"),
+ new AffectedBy(AffectByType.EXTENDS, "maxContains")
+ ),
+ new SubSchemaKeywordType(ContainsKeyword.NAME, ContainsKeyword::new)::createKeyword
)
);
}
diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/ContainsKeyword.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/ContainsKeyword.java
index 49636d27..c22e044b 100644
--- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/ContainsKeyword.java
+++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/ContainsKeyword.java
@@ -30,7 +30,6 @@
import io.github.sebastiantoepfer.jsonschema.JsonSchema;
import io.github.sebastiantoepfer.jsonschema.keyword.Annotation;
import io.github.sebastiantoepfer.jsonschema.keyword.Applicator;
-import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
import jakarta.json.JsonArray;
import jakarta.json.JsonValue;
import java.util.Collection;
@@ -54,10 +53,8 @@ final class ContainsKeyword implements Applicator, Annotation {
static final String NAME = "contains";
private final JsonSchema contains;
- private final List affectedBy;
- public ContainsKeyword(final List affectedBy, final JsonSchema contains) {
- this.affectedBy = List.copyOf(affectedBy);
+ public ContainsKeyword(final JsonSchema contains) {
this.contains = Objects.requireNonNull(contains);
}
@@ -82,7 +79,7 @@ public boolean applyTo(final JsonValue instance) {
}
private boolean contains(final JsonArray array) {
- return !affectedBy.isEmpty() || matchingValues(array).findAny().isPresent();
+ return matchingValues(array).findAny().isPresent();
}
@Override
diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/DependentSchemasKeyword.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/DependentSchemasKeyword.java
new file mode 100644
index 00000000..eda475eb
--- /dev/null
+++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/DependentSchemasKeyword.java
@@ -0,0 +1,69 @@
+/*
+ * The MIT License
+ *
+ * Copyright 2024 sebastian.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package io.github.sebastiantoepfer.jsonschema.core.vocab.applicator;
+
+import io.github.sebastiantoepfer.ddd.common.Media;
+import io.github.sebastiantoepfer.jsonschema.InstanceType;
+import io.github.sebastiantoepfer.jsonschema.JsonSchema;
+import io.github.sebastiantoepfer.jsonschema.core.keyword.type.NamedJsonSchemas;
+import io.github.sebastiantoepfer.jsonschema.keyword.Applicator;
+import jakarta.json.JsonObject;
+import jakarta.json.JsonValue;
+import java.util.Objects;
+import java.util.Optional;
+
+final class DependentSchemasKeyword implements Applicator {
+
+ static final String NAME = "dependentSchemas";
+ private final NamedJsonSchemas schemas;
+
+ public DependentSchemasKeyword(final NamedJsonSchemas schemas) {
+ this.schemas = schemas;
+ }
+
+ @Override
+ public boolean applyTo(final JsonValue instance) {
+ return !InstanceType.OBJECT.isInstance(instance) || applyTo(instance.asJsonObject());
+ }
+
+ private boolean applyTo(final JsonObject instance) {
+ return instance
+ .keySet()
+ .stream()
+ .map(schemas::schemaWithName)
+ .flatMap(Optional::stream)
+ .map(JsonSchema::validator)
+ .allMatch(v -> v.isValid(instance));
+ }
+
+ @Override
+ public boolean hasName(final String name) {
+ return Objects.equals(NAME, name);
+ }
+
+ @Override
+ public > T printOn(final T media) {
+ return media.withValue(NAME, schemas);
+ }
+}
diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/ItemsKeyword.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/ItemsKeyword.java
index 2a8acd31..0591c7ed 100644
--- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/ItemsKeyword.java
+++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/ItemsKeyword.java
@@ -25,17 +25,16 @@
import io.github.sebastiantoepfer.ddd.common.Media;
import io.github.sebastiantoepfer.jsonschema.InstanceType;
-import io.github.sebastiantoepfer.jsonschema.JsonSubSchema;
-import io.github.sebastiantoepfer.jsonschema.Validator;
+import io.github.sebastiantoepfer.jsonschema.JsonSchema;
import io.github.sebastiantoepfer.jsonschema.keyword.Annotation;
import io.github.sebastiantoepfer.jsonschema.keyword.Applicator;
-import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
import jakarta.json.JsonArray;
import jakarta.json.JsonNumber;
import jakarta.json.JsonValue;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
+import java.util.stream.Stream;
/**
* items : Schema
@@ -56,9 +55,11 @@
final class ItemsKeyword implements Applicator, Annotation {
static final String NAME = "items";
- private final JsonSubSchema schema;
+ private final Collection affectedBys;
+ private final JsonSchema schema;
- public ItemsKeyword(final JsonSubSchema schema) {
+ public ItemsKeyword(final Collection affectedBys, final JsonSchema schema) {
+ this.affectedBys = List.copyOf(affectedBys);
this.schema = Objects.requireNonNull(schema);
}
@@ -89,28 +90,35 @@ public JsonValue valueFor(final JsonValue value) {
}
private boolean appliesToAnyFor(final JsonArray value) {
- return startIndexFor(value) == -1;
+ return itemsForValidation(value).anyMatch(schema.validator()::isValid);
}
@Override
public boolean applyTo(final JsonValue instance) {
- return !InstanceType.ARRAY.isInstance(instance) || matchesSchema(instance.asJsonArray());
+ return !InstanceType.ARRAY.isInstance(instance) || applyTo(instance.asJsonArray());
}
- private boolean matchesSchema(final JsonArray items) {
- final Validator itemValidator = schema.validator();
- return items.stream().skip(startIndexFor(items) + 1L).allMatch(itemValidator::isValid);
+ private boolean applyTo(final JsonArray items) {
+ return itemsForValidation(items).allMatch(schema.validator()::isValid);
+ }
+
+ private Stream itemsForValidation(final JsonArray items) {
+ return items.stream().skip(startIndexFor(items) + 1L);
}
private int startIndexFor(final JsonArray value) {
- return schema
- .owner()
- .keywordByName("prefixItems")
- .map(Keyword::asAnnotation)
- .map(anno -> anno.valueFor(value))
- .map(v -> new MaxIndexCalculator(value, v))
- .map(MaxIndexCalculator::maxIndex)
- .orElse(-1);
+ final int result;
+ if (affectedBys.isEmpty()) {
+ result = -1;
+ } else {
+ result = affectedBys
+ .stream()
+ .map(anno -> anno.valueFor(value))
+ .map(v -> new MaxIndexCalculator(value, v))
+ .mapToInt(MaxIndexCalculator::maxIndex)
+ .sum();
+ }
+ return result;
}
private static class MaxIndexCalculator {
diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/NotKeyword.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/NotKeyword.java
new file mode 100644
index 00000000..dbda60e0
--- /dev/null
+++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/NotKeyword.java
@@ -0,0 +1,68 @@
+/*
+ * The MIT License
+ *
+ * Copyright 2024 sebastian.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package io.github.sebastiantoepfer.jsonschema.core.vocab.applicator;
+
+import io.github.sebastiantoepfer.ddd.common.Media;
+import io.github.sebastiantoepfer.jsonschema.JsonSchema;
+import io.github.sebastiantoepfer.jsonschema.keyword.Applicator;
+import jakarta.json.JsonValue;
+import java.util.Objects;
+
+/**
+ * not : Schema
+ * An instance is valid against this keyword if it fails to validate successfully against the schema defined by
+ * this keyword.
+ *
+ * kind
+ *
+ *
+ * source: https://www.learnjsonschema.com/2020-12/applicator/not/
+ * spec: https://json-schema.org/draft/2020-12/json-schema-core.html#section-10.2.1.4
+ */
+final class NotKeyword implements Applicator {
+
+ static final String NAME = "not";
+ private final JsonSchema schema;
+
+ public NotKeyword(final JsonSchema schema) {
+ this.schema = Objects.requireNonNull(schema);
+ }
+
+ @Override
+ public boolean applyTo(final JsonValue instance) {
+ return !schema.validator().isValid(instance);
+ }
+
+ @Override
+ public boolean hasName(final String name) {
+ return Objects.equals(NAME, name);
+ }
+
+ @Override
+ public > T printOn(final T media) {
+ return media.withValue(NAME, schema);
+ }
+}
diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/OneOfKeyword.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/OneOfKeyword.java
new file mode 100644
index 00000000..a3054172
--- /dev/null
+++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/OneOfKeyword.java
@@ -0,0 +1,70 @@
+/*
+ * The MIT License
+ *
+ * Copyright 2024 sebastian.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package io.github.sebastiantoepfer.jsonschema.core.vocab.applicator;
+
+import io.github.sebastiantoepfer.ddd.common.Media;
+import io.github.sebastiantoepfer.jsonschema.JsonSchema;
+import io.github.sebastiantoepfer.jsonschema.keyword.Applicator;
+import jakarta.json.JsonValue;
+import java.util.Collection;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * oneOf : Array
+ * An instance validates successfully against this keyword if it validates successfully against exactly one schema
+ * defined by this keyword’s value.
+ *
+ * kind
+ *
+ *
+ * source: https://www.learnjsonschema.com/2020-12/applicator/oneof/
+ * spec: https://json-schema.org/draft/2020-12/json-schema-core.html#section-10.2.1.3
+ */
+final class OneOfKeyword implements Applicator {
+
+ static final String NAME = "oneOf";
+ private final Collection schemas;
+
+ public OneOfKeyword(final Collection schemas) {
+ this.schemas = List.copyOf(schemas);
+ }
+
+ @Override
+ public boolean applyTo(final JsonValue instance) {
+ return schemas.stream().map(JsonSchema::validator).filter(v -> v.isValid(instance)).limit(2).count() == 1;
+ }
+
+ @Override
+ public boolean hasName(final String name) {
+ return Objects.equals(NAME, name);
+ }
+
+ @Override
+ public > T printOn(final T media) {
+ return media.withValue(NAME, schemas);
+ }
+}
diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/content/ContentVocabulary.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/content/ContentVocabulary.java
index 2948db29..ef6e04e5 100644
--- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/content/ContentVocabulary.java
+++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/content/ContentVocabulary.java
@@ -25,7 +25,7 @@
import io.github.sebastiantoepfer.jsonschema.Vocabulary;
import io.github.sebastiantoepfer.jsonschema.keyword.KeywordType;
-import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.DefaultVocabulary;
+import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.ListVocabulary;
import java.net.URI;
import java.util.Optional;
@@ -41,7 +41,7 @@ public final class ContentVocabulary implements Vocabulary {
private final Vocabulary vocab;
public ContentVocabulary() {
- this.vocab = new DefaultVocabulary(URI.create("https://json-schema.org/draft/2020-12/vocab/content"));
+ this.vocab = new ListVocabulary(URI.create("https://json-schema.org/draft/2020-12/vocab/content"));
}
@Override
diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/CoreVocabulary.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/CoreVocabulary.java
index 26673186..0232c6fb 100644
--- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/CoreVocabulary.java
+++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/CoreVocabulary.java
@@ -27,7 +27,7 @@
import io.github.sebastiantoepfer.jsonschema.core.keyword.type.NamedJsonSchemaKeywordType;
import io.github.sebastiantoepfer.jsonschema.core.keyword.type.StringKeywordType;
import io.github.sebastiantoepfer.jsonschema.keyword.KeywordType;
-import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.DefaultVocabulary;
+import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.ListVocabulary;
import jakarta.json.spi.JsonProvider;
import java.net.URI;
import java.util.Optional;
@@ -37,7 +37,7 @@ public final class CoreVocabulary implements Vocabulary {
private final Vocabulary vocab;
public CoreVocabulary(final JsonProvider jsonContext) {
- this.vocab = new DefaultVocabulary(
+ this.vocab = new ListVocabulary(
URI.create("https://json-schema.org/draft/2020-12/vocab/core"),
new StringKeywordType(jsonContext, SchemaKeyword.NAME, value -> new SchemaKeyword(URI.create(value))),
new StringKeywordType(jsonContext, IdKeyword.NAME, value -> new IdKeyword(URI.create(value))),
diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/RefKeyword.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/RefKeyword.java
index de5037d0..c31901b0 100644
--- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/RefKeyword.java
+++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/RefKeyword.java
@@ -25,11 +25,9 @@
import io.github.sebastiantoepfer.ddd.common.Media;
import io.github.sebastiantoepfer.jsonschema.JsonSchema;
-import io.github.sebastiantoepfer.jsonschema.JsonSchemas;
import io.github.sebastiantoepfer.jsonschema.keyword.Applicator;
import jakarta.json.Json;
import jakarta.json.JsonPointer;
-import jakarta.json.JsonReader;
import jakarta.json.JsonValue;
import java.io.IOException;
import java.net.URI;
@@ -51,10 +49,12 @@ final class RefKeyword implements Applicator {
static final String NAME = "$ref";
private final JsonSchema schema;
private final URI uri;
+ private final SchemaRegistry schemaRegistry;
- public RefKeyword(final JsonSchema schema, final URI uri) {
+ public RefKeyword(final JsonSchema schema, final URI uri, final SchemaRegistry schemaRegistry) {
this.schema = Objects.requireNonNull(schema);
this.uri = Objects.requireNonNull(uri);
+ this.schemaRegistry = Objects.requireNonNull(schemaRegistry);
}
@Override
@@ -76,9 +76,9 @@ private JsonSchema retrieveJsonSchema() {
final JsonSchema json;
try {
if (isRemote()) {
- json = retrieveValueFromRemoteLocation();
+ json = retrieveSchemaFromRegistry();
} else {
- json = retrieveValueFromLocalSchema();
+ json = retrieveSchemaFromLocalSchema();
}
return json;
} catch (IOException ex) {
@@ -86,7 +86,7 @@ private JsonSchema retrieveJsonSchema() {
}
}
- private JsonSchema retrieveValueFromLocalSchema() throws IOException {
+ private JsonSchema retrieveSchemaFromLocalSchema() throws IOException {
return schema.rootSchema().subSchema(createPointer()).orElseThrow();
}
@@ -101,10 +101,8 @@ private JsonPointer createPointer() {
return pointer;
}
- private JsonSchema retrieveValueFromRemoteLocation() throws IOException {
- try (final JsonReader reader = Json.createReader(uri.toURL().openStream())) {
- return JsonSchemas.load(reader.readValue());
- }
+ private JsonSchema retrieveSchemaFromRegistry() throws IOException {
+ return schemaRegistry.schemaForUrl(uri);
}
private boolean isRemote() {
diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/RefKeywordType.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/RefKeywordType.java
index dcff9353..93dd6b77 100644
--- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/RefKeywordType.java
+++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/RefKeywordType.java
@@ -34,9 +34,11 @@
final class RefKeywordType implements KeywordType {
private final JsonProvider jsonContext;
+ private final SchemaRegistry schemaRegistry;
public RefKeywordType(final JsonProvider jsonContext) {
this.jsonContext = Objects.requireNonNull(jsonContext);
+ this.schemaRegistry = new SchemaRegistry.RemoteSchemaRegistry();
}
@Override
@@ -49,7 +51,7 @@ public Keyword createKeyword(final JsonSchema schema) {
return new StringKeywordType(
jsonContext,
RefKeyword.NAME,
- s -> new RefKeyword(schema, URI.create(s))
+ s -> new RefKeyword(schema, URI.create(s), schemaRegistry)
).createKeyword(schema);
}
}
diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/SchemaRegistry.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/SchemaRegistry.java
new file mode 100644
index 00000000..1fb4ffe9
--- /dev/null
+++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/SchemaRegistry.java
@@ -0,0 +1,60 @@
+/*
+ * The MIT License
+ *
+ * Copyright 2024 sebastian.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package io.github.sebastiantoepfer.jsonschema.core.vocab.core;
+
+import io.github.sebastiantoepfer.jsonschema.JsonSchema;
+import io.github.sebastiantoepfer.jsonschema.JsonSchemas;
+import jakarta.json.Json;
+import jakarta.json.JsonReader;
+import jakarta.json.JsonValue;
+import java.io.IOException;
+import java.net.URI;
+
+interface SchemaRegistry {
+ JsonSchema schemaForUrl(URI uri) throws IOException;
+
+ class DefaultSchemaRegistry implements SchemaRegistry {
+
+ private JsonSchema schema;
+
+ public DefaultSchemaRegistry() {
+ schema = JsonSchemas.load(JsonValue.FALSE);
+ }
+
+ @Override
+ public JsonSchema schemaForUrl(final URI uri) throws IOException {
+ return schema;
+ }
+ }
+
+ class RemoteSchemaRegistry implements SchemaRegistry {
+
+ @Override
+ public JsonSchema schemaForUrl(final URI uri) throws IOException {
+ try (JsonReader reader = Json.createReader(uri.toURL().openStream())) {
+ return JsonSchemas.load(reader.readValue());
+ }
+ }
+ }
+}
diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/VocabularyKeyword.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/VocabularyKeyword.java
new file mode 100644
index 00000000..1bff8b10
--- /dev/null
+++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/VocabularyKeyword.java
@@ -0,0 +1,127 @@
+/*
+ * The MIT License
+ *
+ * Copyright 2024 sebastian.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package io.github.sebastiantoepfer.jsonschema.core.vocab.core;
+
+import io.github.sebastiantoepfer.ddd.common.Media;
+import io.github.sebastiantoepfer.ddd.media.json.JsonObjectPrintable;
+import io.github.sebastiantoepfer.jsonschema.Vocabulary;
+import io.github.sebastiantoepfer.jsonschema.core.vocab.OfficialVocabularies;
+import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.LazyVocabularies;
+import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.LazyVocabularyDefinition;
+import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.VocabularyDefinition;
+import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.VocabularyDefinitions;
+import jakarta.json.JsonObject;
+import jakarta.json.JsonValue;
+import java.net.URI;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.function.Supplier;
+import java.util.stream.Stream;
+
+/**
+ * $vocabulary : Object<URI, Boolean>
+ * This keyword is used in meta-schemas to identify the required and optional vocabularies available for use in
+ * schemas described by that meta-schema.
+ *
+ *
+ *
+ * source: https://www.learnjsonschema.com/2020-12/core/vocabulary/
+ * spec: https://json-schema.org/draft/2020-12/json-schema-core.html#section-8.1.2
+ */
+final class VocabularyKeyword implements VocabularyDefinitions {
+
+ static final String NAME = "$vocabulary";
+ private final JsonObject vocabularies;
+ private final Supplier> lazyVocabulariesSupplier;
+
+ VocabularyKeyword(final JsonValue vocabularies, final Supplier> lazyVocabulariesSupplier) {
+ this(vocabularies.asJsonObject(), lazyVocabulariesSupplier);
+ }
+
+ VocabularyKeyword(
+ final JsonObject vocabularies,
+ final Supplier> lazyVocabulariesSupplier
+ ) {
+ this.vocabularies = Objects.requireNonNull(vocabularies);
+ this.lazyVocabulariesSupplier = Objects.requireNonNull(lazyVocabulariesSupplier);
+ }
+
+ @Override
+ public > T printOn(final T media) {
+ return media.withValue(NAME, new JsonObjectPrintable(vocabularies));
+ }
+
+ @Override
+ public boolean hasName(final String name) {
+ return Objects.equals(NAME, name);
+ }
+
+ @Override
+ public Collection categories() {
+ //is a identifier after spec ... but how to implement it as it?
+ return List.of();
+ }
+
+ @Override
+ public Stream definitions() {
+ return vocabularies.entrySet().stream().map(LazyNonOfficalVocabularyDefinition::new);
+ }
+
+ private final class LazyNonOfficalVocabularyDefinition implements VocabularyDefinition {
+
+ private final URI id;
+ private final JsonValue required;
+
+ public LazyNonOfficalVocabularyDefinition(final Map.Entry property) {
+ this(URI.create(property.getKey()), property.getValue());
+ }
+
+ public LazyNonOfficalVocabularyDefinition(final URI id, final JsonValue required) {
+ this.id = Objects.requireNonNull(id);
+ this.required = required;
+ }
+
+ @Override
+ public Optional findVocabulary() {
+ return new OfficialVocabularies()
+ .loadVocabularyWithId(id)
+ .or(() -> new LazyVocabularyDefinition(id, isRequired(), lazyVocabulariesSupplier).findVocabulary());
+ }
+
+ @Override
+ public boolean hasid(final URI id) {
+ return Objects.equals(this.id, id);
+ }
+
+ @Override
+ public boolean isRequired() {
+ return JsonValue.TRUE.equals(required);
+ }
+ }
+}
diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/VocabularyKeywordType.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/VocabularyKeywordType.java
index 1bbac9ae..78cff548 100644
--- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/VocabularyKeywordType.java
+++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/VocabularyKeywordType.java
@@ -23,38 +23,35 @@
*/
package io.github.sebastiantoepfer.jsonschema.core.vocab.core;
-import io.github.sebastiantoepfer.ddd.common.Media;
-import io.github.sebastiantoepfer.ddd.media.json.JsonObjectPrintable;
import io.github.sebastiantoepfer.jsonschema.InstanceType;
import io.github.sebastiantoepfer.jsonschema.JsonSchema;
-import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
import io.github.sebastiantoepfer.jsonschema.keyword.KeywordType;
-import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.VocabularyDefinition;
+import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.ServiceLoaderLazyVocabulariesSupplier;
import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.VocabularyDefinitions;
-import jakarta.json.JsonObject;
import jakarta.json.JsonValue;
-import java.net.URI;
-import java.util.Collection;
-import java.util.List;
-import java.util.Objects;
-import java.util.stream.Stream;
/**
* see: https://json-schema.org/draft/2020-12/json-schema-core.html#name-the-vocabulary-keyword
*/
public final class VocabularyKeywordType implements KeywordType {
+ private final ServiceLoaderLazyVocabulariesSupplier lazyVocabulariesSupplier;
+
+ public VocabularyKeywordType() {
+ this.lazyVocabulariesSupplier = new ServiceLoaderLazyVocabulariesSupplier();
+ }
+
@Override
public String name() {
- return "$vocabulary";
+ return VocabularyKeyword.NAME;
}
@Override
- public VocabularyKeyword createKeyword(final JsonSchema schema) {
+ public VocabularyDefinitions createKeyword(final JsonSchema schema) {
final JsonValue value = schema.asJsonObject().get((name()));
final VocabularyKeyword result;
if (InstanceType.OBJECT.isInstance(value)) {
- result = new VocabularyKeyword(value);
+ result = new VocabularyKeyword(value, lazyVocabulariesSupplier);
} else {
throw new IllegalArgumentException(
"must be an object! " +
@@ -64,53 +61,4 @@ public VocabularyKeyword createKeyword(final JsonSchema schema) {
}
return result;
}
-
- /**
- * $vocabulary : Object<URI, Boolean>
- * This keyword is used in meta-schemas to identify the required and optional vocabularies available for use in
- * schemas described by that meta-schema.
- *
- *
- *
- * source: https://www.learnjsonschema.com/2020-12/core/vocabulary/
- * spec: https://json-schema.org/draft/2020-12/json-schema-core.html#section-8.1.2
- */
- public final class VocabularyKeyword implements Keyword, VocabularyDefinitions {
-
- private final JsonObject vocabularies;
-
- VocabularyKeyword(final JsonValue vocabularies) {
- this(vocabularies.asJsonObject());
- }
-
- VocabularyKeyword(final JsonObject vocabularies) {
- this.vocabularies = Objects.requireNonNull(vocabularies);
- }
-
- @Override
- public > T printOn(final T media) {
- return media.withValue(name(), new JsonObjectPrintable(vocabularies));
- }
-
- @Override
- public boolean hasName(final String name) {
- return Objects.equals(name(), name);
- }
-
- @Override
- public Collection categories() {
- //is a identifier after spec ... but how to implement it as it?
- return List.of();
- }
-
- @Override
- public Stream definitions() {
- return vocabularies
- .entrySet()
- .stream()
- .map(entry -> new VocabularyDefinition(URI.create(entry.getKey()), entry.getValue() == JsonValue.TRUE));
- }
- }
}
diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/format/FormatVocabulary.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/format/FormatAnnotationVocabulary.java
similarity index 86%
rename from core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/format/FormatVocabulary.java
rename to core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/format/FormatAnnotationVocabulary.java
index 38cc30b5..1f918bdd 100644
--- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/format/FormatVocabulary.java
+++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/format/FormatAnnotationVocabulary.java
@@ -25,7 +25,7 @@
import io.github.sebastiantoepfer.jsonschema.Vocabulary;
import io.github.sebastiantoepfer.jsonschema.keyword.KeywordType;
-import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.DefaultVocabulary;
+import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.ListVocabulary;
import java.net.URI;
import java.util.Optional;
@@ -36,12 +36,12 @@
* source: https://www.learnjsonschema.com/2020-12/format-annotation/
* spec: https://json-schema.org/draft/2020-12/json-schema-validation.html#section-7.2.1
*/
-public final class FormatVocabulary implements Vocabulary {
+public final class FormatAnnotationVocabulary implements Vocabulary {
private final Vocabulary vocab;
- public FormatVocabulary() {
- this.vocab = new DefaultVocabulary(URI.create("https://json-schema.org/draft/2020-12/vocab/format-annotation"));
+ public FormatAnnotationVocabulary() {
+ this.vocab = new ListVocabulary(URI.create("https://json-schema.org/draft/2020-12/vocab/format-annotation"));
}
@Override
diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/meta/MetaDataVocabulary.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/meta/MetaDataVocabulary.java
index aed1b3e1..b642fbee 100644
--- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/meta/MetaDataVocabulary.java
+++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/meta/MetaDataVocabulary.java
@@ -25,7 +25,7 @@
import io.github.sebastiantoepfer.jsonschema.Vocabulary;
import io.github.sebastiantoepfer.jsonschema.keyword.KeywordType;
-import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.DefaultVocabulary;
+import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.ListVocabulary;
import java.net.URI;
import java.util.Optional;
@@ -41,7 +41,7 @@ public final class MetaDataVocabulary implements Vocabulary {
private final Vocabulary vocab;
public MetaDataVocabulary() {
- this.vocab = new DefaultVocabulary(URI.create("https://json-schema.org/draft/2020-12/vocab/meta-data"));
+ this.vocab = new ListVocabulary(URI.create("https://json-schema.org/draft/2020-12/vocab/meta-data"));
}
@Override
diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/unevaluated/UnevaluatedVocabulary.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/unevaluated/UnevaluatedVocabulary.java
index e868460d..6ae14692 100644
--- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/unevaluated/UnevaluatedVocabulary.java
+++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/unevaluated/UnevaluatedVocabulary.java
@@ -25,7 +25,7 @@
import io.github.sebastiantoepfer.jsonschema.Vocabulary;
import io.github.sebastiantoepfer.jsonschema.keyword.KeywordType;
-import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.DefaultVocabulary;
+import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.ListVocabulary;
import java.net.URI;
import java.util.Optional;
@@ -41,7 +41,7 @@ public final class UnevaluatedVocabulary implements Vocabulary {
private final Vocabulary vocab;
public UnevaluatedVocabulary() {
- this.vocab = new DefaultVocabulary(URI.create("https://json-schema.org/draft/2020-12/vocab/unevaluated"));
+ this.vocab = new ListVocabulary(URI.create("https://json-schema.org/draft/2020-12/vocab/unevaluated"));
}
@Override
diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MaxContainsKeyword.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MaxContainsKeyword.java
index e9e51768..94d9fada 100644
--- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MaxContainsKeyword.java
+++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MaxContainsKeyword.java
@@ -30,6 +30,8 @@
import jakarta.json.JsonArray;
import jakarta.json.JsonValue;
import java.math.BigInteger;
+import java.util.Collection;
+import java.util.List;
import java.util.Objects;
/**
@@ -47,11 +49,11 @@
final class MaxContainsKeyword implements Assertion {
static final String NAME = "maxContains";
- private final Annotation affects;
+ private final Collection affects;
private final BigInteger maxContains;
- public MaxContainsKeyword(final Annotation affects, final BigInteger maxContains) {
- this.affects = Objects.requireNonNull(affects);
+ public MaxContainsKeyword(final Collection affects, final BigInteger maxContains) {
+ this.affects = List.copyOf(affects);
this.maxContains = Objects.requireNonNull(maxContains);
}
@@ -67,20 +69,21 @@ public > T printOn(final T media) {
@Override
public boolean isValidFor(final JsonValue instance) {
- return (
- !InstanceType.ARRAY.isInstance(instance) || isValidFor(affects.valueFor(instance), instance.asJsonArray())
+ return (!InstanceType.ARRAY.isInstance(instance) || isValidFor(instance.asJsonArray()));
+ }
+
+ private boolean isValidFor(final JsonArray instance) {
+ return isValidFor(
+ affects
+ .stream()
+ .map(a -> a.valueFor(instance))
+ .map(v -> new NumberOfMatches(instance, v))
+ .mapToInt(NumberOfMatches::count)
+ .sum()
);
}
- private boolean isValidFor(final JsonValue containing, final JsonArray values) {
- final boolean result;
- if (JsonValue.NULL.equals(containing)) {
- result = true;
- } else if (JsonValue.TRUE.equals(containing)) {
- result = values.size() <= maxContains.intValue();
- } else {
- result = containing.asJsonArray().size() <= maxContains.intValue();
- }
- return result;
+ private boolean isValidFor(final int containing) {
+ return containing <= maxContains.intValue();
}
}
diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MinContainsKeyword.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MinContainsKeyword.java
index 4b6ef50b..e8277014 100644
--- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MinContainsKeyword.java
+++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MinContainsKeyword.java
@@ -30,6 +30,8 @@
import jakarta.json.JsonArray;
import jakarta.json.JsonValue;
import java.math.BigInteger;
+import java.util.Collection;
+import java.util.List;
import java.util.Objects;
/**
@@ -47,11 +49,11 @@
final class MinContainsKeyword implements Assertion {
static final String NAME = "minContains";
- private final Annotation affects;
+ private final Collection affects;
private final BigInteger minContains;
- public MinContainsKeyword(final Annotation affects, final BigInteger minContains) {
- this.affects = Objects.requireNonNull(affects);
+ public MinContainsKeyword(final Collection affects, final BigInteger minContains) {
+ this.affects = List.copyOf(affects);
this.minContains = Objects.requireNonNull(minContains);
}
@@ -67,20 +69,21 @@ public > T printOn(final T media) {
@Override
public boolean isValidFor(final JsonValue instance) {
- return (
- !InstanceType.ARRAY.isInstance(instance) || isValidFor(affects.valueFor(instance), instance.asJsonArray())
+ return (!InstanceType.ARRAY.isInstance(instance) || isValidFor(instance.asJsonArray()));
+ }
+
+ private boolean isValidFor(final JsonArray instance) {
+ return isValidFor(
+ affects
+ .stream()
+ .map(a -> a.valueFor(instance))
+ .map(v -> new NumberOfMatches(instance, v))
+ .mapToInt(NumberOfMatches::count)
+ .sum()
);
}
- private boolean isValidFor(final JsonValue containing, final JsonArray values) {
- final boolean result;
- if (JsonValue.NULL.equals(containing)) {
- result = true;
- } else if (JsonValue.TRUE.equals(containing)) {
- result = values.size() >= minContains.intValue();
- } else {
- result = containing.asJsonArray().size() >= minContains.intValue();
- }
- return result;
+ private boolean isValidFor(final int containing) {
+ return containing >= minContains.intValue();
}
}
diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/NumberOfMatches.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/NumberOfMatches.java
new file mode 100644
index 00000000..bb8f07da
--- /dev/null
+++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/NumberOfMatches.java
@@ -0,0 +1,43 @@
+/*
+ * The MIT License
+ *
+ * Copyright 2024 sebastian.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package io.github.sebastiantoepfer.jsonschema.core.vocab.validation;
+
+import jakarta.json.JsonArray;
+import jakarta.json.JsonValue;
+import java.util.Objects;
+
+final class NumberOfMatches {
+
+ private final JsonArray array;
+ private final JsonValue value;
+
+ public NumberOfMatches(final JsonArray array, final JsonValue value) {
+ this.array = Objects.requireNonNull(array);
+ this.value = Objects.requireNonNull(value);
+ }
+
+ public int count() {
+ return value == JsonValue.TRUE ? array.size() : value.asJsonArray().size();
+ }
+}
diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/ValidationVocabulary.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/ValidationVocabulary.java
index abc376e7..9e4bd0f9 100644
--- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/ValidationVocabulary.java
+++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/ValidationVocabulary.java
@@ -24,6 +24,7 @@
package io.github.sebastiantoepfer.jsonschema.core.vocab.validation;
import io.github.sebastiantoepfer.jsonschema.Vocabulary;
+import io.github.sebastiantoepfer.jsonschema.core.keyword.type.Affects;
import io.github.sebastiantoepfer.jsonschema.core.keyword.type.AffectsKeywordType;
import io.github.sebastiantoepfer.jsonschema.core.keyword.type.AnyKeywordType;
import io.github.sebastiantoepfer.jsonschema.core.keyword.type.ArrayKeywordType;
@@ -34,9 +35,10 @@
import io.github.sebastiantoepfer.jsonschema.core.keyword.type.StringArrayKeywordType;
import io.github.sebastiantoepfer.jsonschema.core.keyword.type.StringKeywordType;
import io.github.sebastiantoepfer.jsonschema.keyword.KeywordType;
-import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.DefaultVocabulary;
+import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.ListVocabulary;
import jakarta.json.spi.JsonProvider;
import java.net.URI;
+import java.util.List;
import java.util.Optional;
public final class ValidationVocabulary implements Vocabulary {
@@ -44,7 +46,7 @@ public final class ValidationVocabulary implements Vocabulary {
private final Vocabulary vocab;
public ValidationVocabulary(final JsonProvider jsonContext) {
- this.vocab = new DefaultVocabulary(
+ this.vocab = new ListVocabulary(
URI.create("https://json-schema.org/draft/2020-12/vocab/validation"),
new TypeKeywordType(),
new AnyKeywordType(jsonContext, ConstKeyword.NAME, ConstKeyword::new),
@@ -65,7 +67,7 @@ public ValidationVocabulary(final JsonProvider jsonContext) {
new IntegerKeywordType(jsonContext, MinItemsKeyword.NAME, MinItemsKeyword::new),
new AffectsKeywordType(
MaxContainsKeyword.NAME,
- "contains",
+ List.of(new Affects("contains", new Affects.ReplaceKeyword())),
(affects, schema) ->
new IntegerKeywordType(
JsonProvider.provider(),
@@ -75,13 +77,13 @@ public ValidationVocabulary(final JsonProvider jsonContext) {
),
new AffectsKeywordType(
MinContainsKeyword.NAME,
- "contains",
- (a, s) ->
+ List.of(new Affects("contains", new Affects.ReplaceKeyword())),
+ (affects, schema) ->
new IntegerKeywordType(
JsonProvider.provider(),
MinContainsKeyword.NAME,
- value -> new MinContainsKeyword(a, value)
- ).createKeyword(s)
+ value -> new MinContainsKeyword(affects, value)
+ ).createKeyword(schema)
),
new BooleanKeywordType(jsonContext, UniqueItemsKeyword.NAME, UniqueItemsKeyword::new)
);
diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/DefaultJsonObjectSchemaTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/DefaultJsonObjectSchemaTest.java
index 8c15f1fe..d8b2e54f 100644
--- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/DefaultJsonObjectSchemaTest.java
+++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/DefaultJsonObjectSchemaTest.java
@@ -145,4 +145,12 @@ void should_return_empty_if_given_name_not_resolve_to_a_valid_schematype() {
void should_be_printable() {
assertThat(schema.printOn(new HashMapMedia()), allOf(hasEntry("type", "array"), hasKey("items")));
}
+
+ @Test
+ void should_has_a_nice_to_string() {
+ assertThat(
+ new DefaultJsonObjectSchema(Json.createObjectBuilder().add("type", "string").build()).toString(),
+ is("{\"type\":\"string\"}")
+ );
+ }
}
diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/DefaultJsonSubSchemaTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/DefaultJsonSubSchemaTest.java
index e70f3787..d7a55369 100644
--- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/DefaultJsonSubSchemaTest.java
+++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/DefaultJsonSubSchemaTest.java
@@ -147,4 +147,15 @@ void should_be_printable() {
hasEntry("type", "array")
);
}
+
+ @Test
+ void should_has_a_nice_to_string() {
+ assertThat(
+ new DefaultJsonSubSchema(
+ new DefaultJsonSchemaFactory().create(Json.createObjectBuilder().add("test", JsonValue.TRUE).build()),
+ new DefaultJsonSchemaFactory().create(Json.createObjectBuilder().add("type", "array").build())
+ ).toString(),
+ is("{\"type\":\"array\"}")
+ );
+ }
}
diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/EmptyJsonSchemaTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/EmptyJsonSchemaTest.java
index 93d6fd4a..8d106dd8 100644
--- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/EmptyJsonSchemaTest.java
+++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/EmptyJsonSchemaTest.java
@@ -45,4 +45,9 @@ void should_be_valid_for_everything(final JsonValue value) {
void should_be_printable() {
assertThat(new EmptyJsonSchema().printOn(new HashMapMedia()), anEmptyMap());
}
+
+ @Test
+ void should_has_a_nice_to_string() {
+ assertThat(new EmptyJsonSchema().toString(), is("{}"));
+ }
}
diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/FalseJsonSchemaTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/FalseJsonSchemaTest.java
index cdd8215c..496213e3 100644
--- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/FalseJsonSchemaTest.java
+++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/FalseJsonSchemaTest.java
@@ -28,6 +28,7 @@
import static org.hamcrest.Matchers.not;
import jakarta.json.JsonValue;
+import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ArgumentsSource;
@@ -38,4 +39,9 @@ class FalseJsonSchemaTest {
void should_be_invalid_for_everything(final JsonValue value) {
assertThat(new FalseJsonSchema().validator().isValid(value), is(not(true)));
}
+
+ @Test
+ void should_has_a_nice_to_string() {
+ assertThat(new FalseJsonSchema().toString(), is("false"));
+ }
}
diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/KeywordsTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/KeywordsTest.java
index 0f42ad66..19c40788 100644
--- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/KeywordsTest.java
+++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/KeywordsTest.java
@@ -29,12 +29,15 @@
import static org.hamcrest.Matchers.nullValue;
import static org.junit.jupiter.api.Assertions.assertThrows;
+import io.github.sebastiantoepfer.jsonschema.Vocabulary;
import io.github.sebastiantoepfer.jsonschema.core.vocab.core.CoreVocabulary;
import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.VocabularyDefinition;
import jakarta.json.spi.JsonProvider;
import java.net.URI;
import java.util.Collection;
import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
import org.junit.jupiter.api.Test;
class KeywordsTest {
@@ -42,7 +45,7 @@ class KeywordsTest {
@Test
void should_not_be_createbale_without_mandantory_core_vocabulary() {
final Collection vocabDefs = List.of(
- new VocabularyDefinition(new CoreVocabulary(JsonProvider.provider()).id(), false)
+ new TestVocabularyDefinition(new CoreVocabulary(JsonProvider.provider()).id(), false)
);
assertThrows(IllegalArgumentException.class, () -> new Keywords(vocabDefs));
}
@@ -50,7 +53,7 @@ void should_not_be_createbale_without_mandantory_core_vocabulary() {
@Test
void should_not_be_createbale_without_mandantory_base_vocabulary() {
final Collection vocabDefs = List.of(
- new VocabularyDefinition(new BasicVocabulary().id(), false)
+ new TestVocabularyDefinition(new BasicVocabulary().id(), false)
);
assertThrows(IllegalArgumentException.class, () -> new Keywords(vocabDefs));
}
@@ -58,8 +61,38 @@ void should_not_be_createbale_without_mandantory_base_vocabulary() {
@Test
void should_be_createbale_with_optional_vocabularies() {
assertThat(
- new Keywords(List.of(new VocabularyDefinition(URI.create("http://optinal"), false))),
+ new Keywords(List.of(new TestVocabularyDefinition(URI.create("http://optinal"), false))),
is(not(nullValue()))
);
}
+
+ private static final class TestVocabularyDefinition implements VocabularyDefinition {
+
+ private final URI id;
+ private final boolean required;
+
+ public TestVocabularyDefinition(final URI id) {
+ this(id, false);
+ }
+
+ public TestVocabularyDefinition(final URI id, final boolean required) {
+ this.id = id;
+ this.required = required;
+ }
+
+ @Override
+ public Optional findVocabulary() {
+ return Optional.empty();
+ }
+
+ @Override
+ public boolean hasid(URI id) {
+ return Objects.equals(this.id, id);
+ }
+
+ @Override
+ public boolean isRequired() {
+ return required;
+ }
+ }
}
diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/keyword/type/AffectedByTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/keyword/type/AffectedByTest.java
new file mode 100644
index 00000000..bce5b3ab
--- /dev/null
+++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/keyword/type/AffectedByTest.java
@@ -0,0 +1,60 @@
+/*
+ * The MIT License
+ *
+ * Copyright 2024 sebastian.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package io.github.sebastiantoepfer.jsonschema.core.keyword.type;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.contains;
+
+import java.util.List;
+import java.util.TreeSet;
+import nl.jqno.equalsverifier.EqualsVerifier;
+import org.junit.jupiter.api.Test;
+
+class AffectedByTest {
+
+ @Test
+ void should_fullfil_equals_contract() {
+ EqualsVerifier.forClass(AffectedBy.class).withNonnullFields("type", "name").verify();
+ }
+
+ @Test
+ void should_be_sorted_correctly() {
+ assertThat(
+ new TreeSet<>(
+ List.of(
+ new AffectedBy(AffectByType.REPLACE, "d"),
+ new AffectedBy(AffectByType.EXTENDS, "c"),
+ new AffectedBy(AffectByType.EXTENDS, "b"),
+ new AffectedBy(AffectByType.REPLACE, "a")
+ )
+ ),
+ contains(
+ new AffectedBy(AffectByType.EXTENDS, "b"),
+ new AffectedBy(AffectByType.EXTENDS, "c"),
+ new AffectedBy(AffectByType.REPLACE, "a"),
+ new AffectedBy(AffectByType.REPLACE, "d")
+ )
+ );
+ }
+}
diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/keyword/type/AffectsTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/keyword/type/AffectsTest.java
new file mode 100644
index 00000000..5e13cce3
--- /dev/null
+++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/keyword/type/AffectsTest.java
@@ -0,0 +1,99 @@
+/*
+ * The MIT License
+ *
+ * Copyright 2024 sebastian.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package io.github.sebastiantoepfer.jsonschema.core.keyword.type;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+
+import io.github.sebastiantoepfer.jsonschema.JsonSchemas;
+import jakarta.json.Json;
+import jakarta.json.JsonValue;
+import org.junit.jupiter.api.Test;
+
+class AffectsTest {
+
+ @Test
+ void should_handle_non_annotation_as_absence() {
+ assertThat(
+ new Affects("type", new Affects.ProvideDefaultValue(JsonValue.EMPTY_JSON_OBJECT))
+ .findAffectsKeywordIn(JsonSchemas.load(Json.createObjectBuilder().add("type", "number").build()))
+ .getKey()
+ .valueFor(JsonValue.FALSE),
+ is(JsonValue.EMPTY_JSON_OBJECT)
+ );
+ }
+
+ @Test
+ void should_return_original_annotation() {
+ assertThat(
+ new Affects("properties", new Affects.ProvideDefaultValue(JsonValue.EMPTY_JSON_OBJECT))
+ .findAffectsKeywordIn(
+ JsonSchemas.load(
+ Json.createObjectBuilder()
+ .add(
+ "properties",
+ Json.createObjectBuilder().add("test", Json.createObjectBuilder().add("type", "number"))
+ )
+ .build()
+ )
+ )
+ .getKey()
+ .valueFor(Json.createObjectBuilder().add("test", 1L).build()),
+ is(Json.createArrayBuilder().add("test").build())
+ );
+ }
+
+ @Test
+ void should_create_original_annotation() {
+ assertThat(
+ new Affects("properties", new Affects.ProvideDefaultValue(JsonValue.EMPTY_JSON_OBJECT))
+ .findAffectsKeywordIn(
+ JsonSchemas.load(
+ Json.createObjectBuilder()
+ .add(
+ "properties",
+ Json.createObjectBuilder().add("test", Json.createObjectBuilder().add("type", "number"))
+ )
+ .build()
+ )
+ )
+ .getValue()
+ .apply(new MockKeyword("test"))
+ .hasName("test"),
+ is(true)
+ );
+ }
+
+ @Test
+ void should_create_original_annotation_also_for_missing() {
+ assertThat(
+ new Affects("properties", new Affects.ProvideDefaultValue(JsonValue.EMPTY_JSON_OBJECT))
+ .findAffectsKeywordIn(JsonSchemas.load(JsonValue.TRUE))
+ .getValue()
+ .apply(new MockKeyword("test"))
+ .hasName("test"),
+ is(true)
+ );
+ }
+}
diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/keyword/type/MockKeyword.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/keyword/type/MockKeyword.java
new file mode 100644
index 00000000..35ba659b
--- /dev/null
+++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/keyword/type/MockKeyword.java
@@ -0,0 +1,80 @@
+/*
+ * The MIT License
+ *
+ * Copyright 2024 sebastian.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package io.github.sebastiantoepfer.jsonschema.core.keyword.type;
+
+import io.github.sebastiantoepfer.ddd.common.Media;
+import io.github.sebastiantoepfer.jsonschema.keyword.Annotation;
+import io.github.sebastiantoepfer.jsonschema.keyword.Applicator;
+import io.github.sebastiantoepfer.jsonschema.keyword.Assertion;
+import io.github.sebastiantoepfer.jsonschema.keyword.Identifier;
+import io.github.sebastiantoepfer.jsonschema.keyword.ReservedLocation;
+import jakarta.json.JsonValue;
+import java.net.URI;
+import java.util.Collection;
+import java.util.EnumSet;
+import java.util.Objects;
+
+final class MockKeyword implements Identifier, Assertion, Annotation, Applicator, ReservedLocation {
+
+ private final String name;
+
+ public MockKeyword(final String name) {
+ this.name = name;
+ }
+
+ @Override
+ public URI asUri() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public boolean isValidFor(final JsonValue instance) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public JsonValue valueFor(final JsonValue value) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public boolean applyTo(final JsonValue instance) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public Collection categories() {
+ return EnumSet.allOf(KeywordCategory.class);
+ }
+
+ @Override
+ public boolean hasName(final String name) {
+ return Objects.equals(this.name, name);
+ }
+
+ @Override
+ public > T printOn(final T media) {
+ return media.withValue(name, name);
+ }
+}
diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/keyword/type/ReplacingKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/keyword/type/ReplacingKeywordTest.java
new file mode 100644
index 00000000..0f7c1a87
--- /dev/null
+++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/keyword/type/ReplacingKeywordTest.java
@@ -0,0 +1,176 @@
+/*
+ * The MIT License
+ *
+ * Copyright 2024 sebastian.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package io.github.sebastiantoepfer.jsonschema.core.keyword.type;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.both;
+import static org.hamcrest.Matchers.empty;
+import static org.hamcrest.Matchers.hasItem;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
+import static org.hamcrest.Matchers.sameInstance;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia;
+import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
+import io.github.sebastiantoepfer.jsonschema.keyword.Keyword.KeywordCategory;
+import java.util.EnumSet;
+import org.hamcrest.Matcher;
+import org.hamcrest.Matchers;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.EnumSource;
+
+class ReplacingKeywordTest {
+
+ @Test
+ void should_not_be_createable_as_identifier_if_it_should_replace_it() {
+ final Keyword keyword = new ReplacingKeyword(
+ new MockKeyword("test"),
+ EnumSet.of(Keyword.KeywordCategory.IDENTIFIER)
+ );
+ assertThrows(UnsupportedOperationException.class, () -> keyword.asIdentifier());
+ }
+
+ @Test
+ void should_return_identifier_if_it_should_not_replaced() {
+ final Keyword keyword = new MockKeyword("test");
+ assertThat(
+ new ReplacingKeyword(
+ keyword,
+ EnumSet.complementOf(EnumSet.of(Keyword.KeywordCategory.IDENTIFIER))
+ ).asIdentifier(),
+ is(sameInstance(keyword))
+ );
+ }
+
+ @Test
+ void should_not_be_createable_as_assertion_if_it_should_replace_it() {
+ final Keyword keyword = new ReplacingKeyword(
+ new MockKeyword("test"),
+ EnumSet.of(Keyword.KeywordCategory.ASSERTION)
+ );
+ assertThrows(UnsupportedOperationException.class, () -> keyword.asAssertion());
+ }
+
+ @Test
+ void should_return_assertion_if_it_should_not_replaced() {
+ final Keyword keyword = new MockKeyword("test");
+ assertThat(
+ new ReplacingKeyword(
+ keyword,
+ EnumSet.complementOf(EnumSet.of(Keyword.KeywordCategory.ASSERTION))
+ ).asAssertion(),
+ is(sameInstance(keyword))
+ );
+ }
+
+ @Test
+ void should_not_be_createable_as_annotation_if_it_should_replace_it() {
+ final Keyword keyword = new ReplacingKeyword(
+ new MockKeyword("test"),
+ EnumSet.of(Keyword.KeywordCategory.ANNOTATION)
+ );
+ assertThrows(UnsupportedOperationException.class, () -> keyword.asAnnotation());
+ }
+
+ @Test
+ void should_return_annotation_if_it_should_not_replaced() {
+ final Keyword keyword = new MockKeyword("test");
+ assertThat(
+ new ReplacingKeyword(
+ keyword,
+ EnumSet.complementOf(EnumSet.of(Keyword.KeywordCategory.ANNOTATION))
+ ).asAnnotation(),
+ is(sameInstance(keyword))
+ );
+ }
+
+ @Test
+ void should_not_be_createable_as_applicator_if_it_should_replace_it() {
+ final Keyword keyword = new ReplacingKeyword(
+ new MockKeyword("test"),
+ EnumSet.of(Keyword.KeywordCategory.APPLICATOR)
+ );
+ assertThrows(UnsupportedOperationException.class, () -> keyword.asApplicator());
+ }
+
+ @Test
+ void should_return_applicator_if_it_should_not_replaced() {
+ final Keyword keyword = new MockKeyword("test");
+ assertThat(
+ new ReplacingKeyword(
+ keyword,
+ EnumSet.complementOf(EnumSet.of(Keyword.KeywordCategory.APPLICATOR))
+ ).asApplicator(),
+ is(sameInstance(keyword))
+ );
+ }
+
+ @Test
+ void should_not_be_createable_as_reserved_location_if_it_should_replace_it() {
+ final Keyword keyword = new ReplacingKeyword(
+ new MockKeyword("test"),
+ EnumSet.of(Keyword.KeywordCategory.RESERVED_LOCATION)
+ );
+ assertThrows(UnsupportedOperationException.class, () -> keyword.asReservedLocation());
+ }
+
+ @Test
+ void should_return_reserved_location_if_it_should_not_replaced() {
+ final Keyword keyword = new MockKeyword("test");
+ assertThat(
+ new ReplacingKeyword(
+ keyword,
+ EnumSet.complementOf(EnumSet.of(Keyword.KeywordCategory.RESERVED_LOCATION))
+ ).asReservedLocation(),
+ is(sameInstance(keyword))
+ );
+ }
+
+ @Test
+ void should_name_of_decoded_keyword() {
+ final Keyword keyword = new ReplacingKeyword(new MockKeyword("test"));
+
+ assertThat(keyword.hasName("test"), is(true));
+ assertThat(keyword.hasName("bunny"), is(false));
+ }
+
+ @Test
+ void should_print_as_decored_keyword() {
+ assertThat(
+ new ReplacingKeyword(new MockKeyword("test")).printOn(new HashMapMedia()),
+ Matchers.hasEntry("test", "test")
+ );
+ }
+
+ @ParameterizedTest
+ @EnumSource(KeywordCategory.class)
+ void should_not_return_replaced_keyword_category(final Keyword.KeywordCategory category) {
+ assertThat(
+ new ReplacingKeyword(new MockKeyword("test"), EnumSet.of(category)).categories(),
+ both(not(hasItem(category))).and((Matcher) is(not(empty())))
+ );
+ }
+}
diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/AdditionalPropertiesKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/AdditionalPropertiesKeywordTest.java
index 053791be..711ca283 100644
--- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/AdditionalPropertiesKeywordTest.java
+++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/AdditionalPropertiesKeywordTest.java
@@ -30,12 +30,12 @@
import static org.hamcrest.Matchers.is;
import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia;
-import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory;
-import io.github.sebastiantoepfer.jsonschema.core.keyword.type.SubSchemaKeywordType;
+import io.github.sebastiantoepfer.jsonschema.JsonSchemas;
import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
+import io.github.sebastiantoepfer.jsonschema.keyword.StaticAnnotation;
import jakarta.json.Json;
-import jakarta.json.JsonObject;
import jakarta.json.JsonValue;
+import java.util.List;
import org.hamcrest.Matcher;
import org.junit.jupiter.api.Test;
@@ -43,9 +43,7 @@ class AdditionalPropertiesKeywordTest {
@Test
void should_know_his_name() {
- final Keyword keyword = createKeywordFrom(
- Json.createObjectBuilder().add("additionalProperties", JsonValue.EMPTY_JSON_OBJECT).build()
- );
+ final Keyword keyword = new AdditionalPropertiesKeyword(List.of(), JsonSchemas.load(JsonValue.TRUE));
assertThat(keyword.hasName("additionalProperties"), is(true));
assertThat(keyword.hasName("test"), is(false));
}
@@ -53,11 +51,9 @@ void should_know_his_name() {
@Test
void should_be_valid_for_non_objects() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder()
- .add("properties", Json.createObjectBuilder().add("test", JsonValue.TRUE))
- .add("additionalProperties", JsonValue.FALSE)
- .build()
+ new AdditionalPropertiesKeyword(
+ List.of(new StaticAnnotation("properties", JsonValue.EMPTY_JSON_ARRAY)),
+ JsonSchemas.load(JsonValue.FALSE)
)
.asApplicator()
.applyTo(JsonValue.EMPTY_JSON_ARRAY),
@@ -68,11 +64,9 @@ void should_be_valid_for_non_objects() {
@Test
void should_not_valid_if_no_additionals_are_allow() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder()
- .add("properties", Json.createObjectBuilder().add("test", JsonValue.TRUE))
- .add("additionalProperties", JsonValue.FALSE)
- .build()
+ new AdditionalPropertiesKeyword(
+ List.of(new StaticAnnotation("properties", Json.createArrayBuilder().add("test").build())),
+ JsonSchemas.load(JsonValue.FALSE)
)
.asApplicator()
.applyTo(Json.createObjectBuilder().add("test", 1).add("foo", 1).build()),
@@ -83,11 +77,9 @@ void should_not_valid_if_no_additionals_are_allow() {
@Test
void should_valid_if_additionals_are_allow() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder()
- .add("properties", Json.createObjectBuilder().add("test", JsonValue.TRUE))
- .add("additionalProperties", JsonValue.TRUE)
- .build()
+ new AdditionalPropertiesKeyword(
+ List.of(new StaticAnnotation("properties", Json.createArrayBuilder().add("test").build())),
+ JsonSchemas.load(JsonValue.TRUE)
)
.asApplicator()
.applyTo(Json.createObjectBuilder().add("test", 1).add("foo", 1).build()),
@@ -98,11 +90,9 @@ void should_valid_if_additionals_are_allow() {
@Test
void should_valid_if_no_additionals_are_allow_and_no_additionals_their() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder()
- .add("properties", Json.createObjectBuilder().add("test", JsonValue.TRUE))
- .add("additionalProperties", JsonValue.FALSE)
- .build()
+ new AdditionalPropertiesKeyword(
+ List.of(new StaticAnnotation("properties", Json.createArrayBuilder().add("test").build())),
+ JsonSchemas.load(JsonValue.FALSE)
)
.asApplicator()
.applyTo(Json.createObjectBuilder().add("test", 1).build()),
@@ -113,8 +103,9 @@ void should_valid_if_no_additionals_are_allow_and_no_additionals_their() {
@Test
void should_be_an_applicator_and_an_annotation() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder().add("additionalProperties", JsonValue.TRUE).build()
+ new AdditionalPropertiesKeyword(
+ List.of(new StaticAnnotation("properties", JsonValue.EMPTY_JSON_ARRAY)),
+ JsonSchemas.load(JsonValue.FALSE)
).categories(),
containsInAnyOrder(Keyword.KeywordCategory.APPLICATOR, Keyword.KeywordCategory.ANNOTATION)
);
@@ -123,11 +114,9 @@ void should_be_an_applicator_and_an_annotation() {
@Test
void should_return_propertynames_which_will_be_validated() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder()
- .add("properties", Json.createObjectBuilder().add("test", JsonValue.TRUE))
- .add("additionalProperties", JsonValue.TRUE)
- .build()
+ new AdditionalPropertiesKeyword(
+ List.of(new StaticAnnotation("properties", Json.createArrayBuilder().add("test").build())),
+ JsonSchemas.load(JsonValue.TRUE)
)
.asAnnotation()
.valueFor(Json.createObjectBuilder().add("test", 1).add("foo", 1).build())
@@ -139,16 +128,10 @@ void should_return_propertynames_which_will_be_validated() {
@Test
void should_be_printable() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder().add("additionalProperties", JsonValue.EMPTY_JSON_OBJECT).build()
- ).printOn(new HashMapMedia()),
+ new AdditionalPropertiesKeyword(List.of(), JsonSchemas.load(JsonValue.EMPTY_JSON_OBJECT)).printOn(
+ new HashMapMedia()
+ ),
(Matcher) hasEntry(is("additionalProperties"), anEmptyMap())
);
}
-
- private static Keyword createKeywordFrom(final JsonObject json) {
- return new SubSchemaKeywordType("additionalProperties", AdditionalPropertiesKeyword::new).createKeyword(
- new DefaultJsonSchemaFactory().create(json)
- );
- }
}
diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/AllOfKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/AllOfKeywordTest.java
new file mode 100644
index 00000000..86bc7560
--- /dev/null
+++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/AllOfKeywordTest.java
@@ -0,0 +1,102 @@
+/*
+ * The MIT License
+ *
+ * Copyright 2024 sebastian.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package io.github.sebastiantoepfer.jsonschema.core.vocab.applicator;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.hasEntry;
+import static org.hamcrest.Matchers.hasItems;
+import static org.hamcrest.Matchers.hasKey;
+import static org.hamcrest.Matchers.is;
+
+import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia;
+import io.github.sebastiantoepfer.jsonschema.JsonSchemas;
+import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
+import jakarta.json.Json;
+import jakarta.json.JsonValue;
+import org.hamcrest.Matcher;
+import org.junit.jupiter.api.Test;
+
+class AllOfKeywordTest {
+
+ @Test
+ void should_know_his_name() {
+ final Keyword items = new AllOfKeyword(
+ Json.createArrayBuilder().add(JsonValue.TRUE).build().stream().map(JsonSchemas::load).toList()
+ );
+ assertThat(items.hasName("allOf"), is(true));
+ assertThat(items.hasName("test"), is(false));
+ }
+
+ @Test
+ void should_be_printable() {
+ assertThat(
+ new AllOfKeyword(
+ Json.createArrayBuilder()
+ .add(Json.createObjectBuilder().add("type", "number"))
+ .add(Json.createObjectBuilder().add("minimum", 18))
+ .build()
+ .stream()
+ .map(JsonSchemas::load)
+ .toList()
+ ).printOn(new HashMapMedia()),
+ (Matcher) hasEntry(is("allOf"), hasItems(hasKey("type"), hasKey("minimum")))
+ );
+ }
+
+ @Test
+ void should_be_valid_if_all_schemas_applies() {
+ assertThat(
+ new AllOfKeyword(
+ Json.createArrayBuilder()
+ .add(Json.createObjectBuilder().add("type", "number"))
+ .add(Json.createObjectBuilder().add("minimum", 18))
+ .build()
+ .stream()
+ .map(JsonSchemas::load)
+ .toList()
+ )
+ .asApplicator()
+ .applyTo(Json.createValue(25)),
+ is(true)
+ );
+ }
+
+ @Test
+ void should_be_invalid_if_any_schemas_not_apply() {
+ assertThat(
+ new AllOfKeyword(
+ Json.createArrayBuilder()
+ .add(Json.createObjectBuilder().add("type", "number"))
+ .add(Json.createObjectBuilder().add("minimum", 18))
+ .build()
+ .stream()
+ .map(JsonSchemas::load)
+ .toList()
+ )
+ .asApplicator()
+ .applyTo(Json.createValue(10)),
+ is(false)
+ );
+ }
+}
diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/AnyOfKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/AnyOfKeywordTest.java
new file mode 100644
index 00000000..f7fa853e
--- /dev/null
+++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/AnyOfKeywordTest.java
@@ -0,0 +1,106 @@
+/*
+ * The MIT License
+ *
+ * Copyright 2024 sebastian.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package io.github.sebastiantoepfer.jsonschema.core.vocab.applicator;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.hasEntry;
+import static org.hamcrest.Matchers.hasItem;
+import static org.hamcrest.Matchers.hasKey;
+import static org.hamcrest.Matchers.is;
+
+import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia;
+import io.github.sebastiantoepfer.jsonschema.JsonSchemas;
+import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
+import jakarta.json.Json;
+import jakarta.json.JsonValue;
+import java.util.List;
+import org.hamcrest.Matcher;
+import org.junit.jupiter.api.Test;
+
+class AnyOfKeywordTest {
+
+ @Test
+ void should_know_his_name() {
+ final Keyword items = new AnyOfKeyword(List.of(JsonSchemas.load(JsonValue.TRUE)));
+
+ assertThat(items.hasName("anyOf"), is(true));
+ assertThat(items.hasName("test"), is(false));
+ }
+
+ @Test
+ void should_be_printable() {
+ assertThat(
+ new AnyOfKeyword(
+ List.of(
+ JsonSchemas.load(
+ Json.createObjectBuilder()
+ .add(
+ "allOf",
+ Json.createArrayBuilder().add(Json.createObjectBuilder().add("type", "number"))
+ )
+ .build()
+ )
+ )
+ ).printOn(new HashMapMedia()),
+ (Matcher) hasEntry(is("anyOf"), hasItem((hasKey("allOf"))))
+ );
+ }
+
+ @Test
+ void should_be_valid_if_any_schemas_applies() {
+ assertThat(
+ new AnyOfKeyword(
+ Json.createArrayBuilder()
+ .add(JsonValue.FALSE)
+ .add(JsonValue.TRUE)
+ .add(JsonValue.FALSE)
+ .build()
+ .stream()
+ .map(JsonSchemas::load)
+ .toList()
+ )
+ .asApplicator()
+ .applyTo(Json.createValue(25)),
+ is(true)
+ );
+ }
+
+ @Test
+ void should_be_invalid_if_no_schemas_apply() {
+ assertThat(
+ new AnyOfKeyword(
+ Json.createArrayBuilder()
+ .add(JsonValue.FALSE)
+ .add(JsonValue.FALSE)
+ .build()
+ .stream()
+ .map(JsonSchemas::load)
+ .toList()
+ )
+ .asApplicator()
+ .applyTo(Json.createValue(10)),
+ is(false)
+ );
+ }
+}
diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/ContainsKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/ContainsKeywordTest.java
index e6ddbad0..f94a4c35 100644
--- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/ContainsKeywordTest.java
+++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/ContainsKeywordTest.java
@@ -30,14 +30,10 @@
import static org.hamcrest.Matchers.is;
import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia;
-import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory;
-import io.github.sebastiantoepfer.jsonschema.core.keyword.type.AffectedByKeywordType;
-import io.github.sebastiantoepfer.jsonschema.core.keyword.type.SubSchemaKeywordType;
+import io.github.sebastiantoepfer.jsonschema.JsonSchemas;
import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
import jakarta.json.Json;
-import jakarta.json.JsonObject;
import jakarta.json.JsonValue;
-import java.util.List;
import org.hamcrest.Matcher;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.Test;
@@ -47,19 +43,16 @@ class ContainsKeywordTest {
@Test
void should_be_printable() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder().add("contains", Json.createObjectBuilder().add("type", "number")).build()
- ).printOn(new HashMapMedia()),
+ new ContainsKeyword(JsonSchemas.load(Json.createObjectBuilder().add("type", "number").build())).printOn(
+ new HashMapMedia()
+ ),
(Matcher) hasEntry(is("contains"), hasEntry(is("type"), is("number")))
);
}
@Test
void should_know_his_name() {
- final Keyword enumKeyword = new ContainsKeyword(
- List.of(),
- new DefaultJsonSchemaFactory().create(JsonValue.TRUE)
- );
+ final Keyword enumKeyword = new ContainsKeyword(JsonSchemas.load(JsonValue.TRUE));
assertThat(enumKeyword.hasName("contains"), is(true));
assertThat(enumKeyword.hasName("test"), is(false));
@@ -68,8 +61,8 @@ void should_know_his_name() {
@Test
void should_be_an_applicator_and_annotation() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder().add("contains", Json.createObjectBuilder().add("type", "number")).build()
+ new ContainsKeyword(
+ JsonSchemas.load(Json.createObjectBuilder().add("type", "number").build())
).categories(),
Matchers.containsInAnyOrder(Keyword.KeywordCategory.ANNOTATION, Keyword.KeywordCategory.APPLICATOR)
);
@@ -78,36 +71,17 @@ void should_be_an_applicator_and_annotation() {
@Test
void should_apply_for_non_array() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder().add("contains", Json.createObjectBuilder().add("type", "number")).build()
- )
+ new ContainsKeyword(JsonSchemas.load(Json.createObjectBuilder().add("type", "number").build()))
.asApplicator()
.applyTo(JsonValue.EMPTY_JSON_OBJECT),
is(true)
);
}
- @Test
- void should_apply_to_empty_array_if_min_andor_max_provided() {
- assertThat(
- createKeywordFrom(
- Json.createObjectBuilder()
- .add("contains", Json.createObjectBuilder().add("type", "number"))
- .add("minContains", 0)
- .build()
- )
- .asApplicator()
- .applyTo(JsonValue.EMPTY_JSON_ARRAY),
- is(true)
- );
- }
-
@Test
void should_not_apply_to_empty_array_if_non_min_andor_max_is_provided() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder().add("contains", Json.createObjectBuilder().add("type", "number")).build()
- )
+ new ContainsKeyword(JsonSchemas.load(Json.createObjectBuilder().add("type", "number").build()))
.asApplicator()
.applyTo(JsonValue.EMPTY_JSON_ARRAY),
is(false)
@@ -117,9 +91,7 @@ void should_not_apply_to_empty_array_if_non_min_andor_max_is_provided() {
@Test
void should_apply_if_one_item_applies() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder().add("contains", Json.createObjectBuilder().add("type", "number")).build()
- )
+ new ContainsKeyword(JsonSchemas.load(Json.createObjectBuilder().add("type", "number").build()))
.asApplicator()
.applyTo(
Json.createArrayBuilder()
@@ -137,9 +109,7 @@ void should_apply_if_one_item_applies() {
@Test
void should_apply_if_all_item_applies() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder().add("contains", Json.createObjectBuilder().add("type", "string")).build()
- )
+ new ContainsKeyword(JsonSchemas.load(Json.createObjectBuilder().add("type", "string").build()))
.asApplicator()
.applyTo(Json.createArrayBuilder().add("foo").add("bar").add("baz").build()),
is(true)
@@ -149,9 +119,7 @@ void should_apply_if_all_item_applies() {
@Test
void should_not_apply_if_non_item_applies() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder().add("contains", Json.createObjectBuilder().add("type", "number")).build()
- )
+ new ContainsKeyword(JsonSchemas.load(Json.createObjectBuilder().add("type", "number").build()))
.asApplicator()
.applyTo(
Json.createArrayBuilder().add("foo").add(false).add(Json.createArrayBuilder().add("bar")).build()
@@ -163,9 +131,7 @@ void should_not_apply_if_non_item_applies() {
@Test
void should_return_false_for_non_array() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder().add("contains", Json.createObjectBuilder().add("type", "number")).build()
- )
+ new ContainsKeyword(JsonSchemas.load(Json.createObjectBuilder().add("type", "number").build()))
.asAnnotation()
.valueFor(JsonValue.EMPTY_JSON_OBJECT),
is(JsonValue.FALSE)
@@ -175,9 +141,7 @@ void should_return_false_for_non_array() {
@Test
void should_return_empty_array_if_no_item_applies() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder().add("contains", Json.createObjectBuilder().add("type", "number")).build()
- )
+ new ContainsKeyword(JsonSchemas.load(Json.createObjectBuilder().add("type", "number").build()))
.asAnnotation()
.valueFor(Json.createArrayBuilder().add("foo").build())
.asJsonArray(),
@@ -188,9 +152,7 @@ void should_return_empty_array_if_no_item_applies() {
@Test
void should_return_empty_array_for_empty_array() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder().add("contains", Json.createObjectBuilder().add("type", "number")).build()
- )
+ new ContainsKeyword(JsonSchemas.load(Json.createObjectBuilder().add("type", "number").build()))
.asAnnotation()
.valueFor(JsonValue.EMPTY_JSON_ARRAY)
.asJsonArray(),
@@ -201,9 +163,7 @@ void should_return_empty_array_for_empty_array() {
@Test
void should_return_matching_items() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder().add("contains", Json.createObjectBuilder().add("type", "number")).build()
- )
+ new ContainsKeyword(JsonSchemas.load(Json.createObjectBuilder().add("type", "number").build()))
.asAnnotation()
.valueFor(
Json.createArrayBuilder()
@@ -222,20 +182,10 @@ void should_return_matching_items() {
@Test
void should_return_true_if_all_item_applies() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder().add("contains", Json.createObjectBuilder().add("type", "string")).build()
- )
+ new ContainsKeyword(JsonSchemas.load(Json.createObjectBuilder().add("type", "string").build()))
.asAnnotation()
.valueFor(Json.createArrayBuilder().add("foo").add("bar").add("baz").build()),
is(JsonValue.TRUE)
);
}
-
- private static Keyword createKeywordFrom(final JsonObject json) {
- return new AffectedByKeywordType(
- "contains",
- List.of("minContains", "maxContains"),
- (a, schema) -> new SubSchemaKeywordType("contains", s -> new ContainsKeyword(a, s)).createKeyword(schema)
- ).createKeyword(new DefaultJsonSchemaFactory().create(json));
- }
}
diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/DependentSchemasKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/DependentSchemasKeywordTest.java
new file mode 100644
index 00000000..e0b1b7b4
--- /dev/null
+++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/DependentSchemasKeywordTest.java
@@ -0,0 +1,108 @@
+/*
+ * The MIT License
+ *
+ * Copyright 2023 sebastian.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package io.github.sebastiantoepfer.jsonschema.core.vocab.applicator;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.anEmptyMap;
+import static org.hamcrest.Matchers.hasEntry;
+import static org.hamcrest.Matchers.is;
+
+import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia;
+import io.github.sebastiantoepfer.jsonschema.JsonSchemas;
+import io.github.sebastiantoepfer.jsonschema.core.keyword.type.NamedJsonSchemas;
+import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
+import jakarta.json.Json;
+import jakarta.json.JsonValue;
+import java.util.Map;
+import org.hamcrest.Matcher;
+import org.junit.jupiter.api.Test;
+
+class DependentSchemasKeywordTest {
+
+ @Test
+ void should_know_his_name() {
+ final Keyword keyword = new DependentSchemasKeyword(new NamedJsonSchemas(Map.of()));
+
+ assertThat(keyword.hasName("dependentSchemas"), is(true));
+ assertThat(keyword.hasName("test"), is(false));
+ }
+
+ @Test
+ void should_be_printable() {
+ assertThat(
+ new DependentSchemasKeyword(new NamedJsonSchemas(Map.of("foo", JsonSchemas.load(JsonValue.TRUE)))).printOn(
+ new HashMapMedia()
+ ),
+ (Matcher) hasEntry(is("dependentSchemas"), hasEntry(is("foo"), anEmptyMap()))
+ );
+ }
+
+ @Test
+ void should_be_valid_for_non_object() {
+ assertThat(
+ new DependentSchemasKeyword(new NamedJsonSchemas(Map.of())).asApplicator().applyTo(JsonValue.FALSE),
+ is(true)
+ );
+ }
+
+ @Test
+ void should_be_valid_for_empty_object() {
+ assertThat(
+ new DependentSchemasKeyword(new NamedJsonSchemas(Map.of()))
+ .asApplicator()
+ .applyTo(JsonValue.EMPTY_JSON_OBJECT),
+ is(true)
+ );
+ }
+
+ @Test
+ void should_be_valid_if_property_not_present() {
+ assertThat(
+ new DependentSchemasKeyword(new NamedJsonSchemas(Map.of("test", JsonSchemas.load(JsonValue.FALSE))))
+ .asApplicator()
+ .applyTo(Json.createObjectBuilder().add("foo", 1).build()),
+ is(true)
+ );
+ }
+
+ @Test
+ void should_be_valid_if_property_is_present_and_schema_apply() {
+ assertThat(
+ new DependentSchemasKeyword(new NamedJsonSchemas(Map.of("test", JsonSchemas.load(JsonValue.TRUE))))
+ .asApplicator()
+ .applyTo(Json.createObjectBuilder().add("true", 1).build()),
+ is(true)
+ );
+ }
+
+ @Test
+ void should_be_invalid_if_property_is_present_and_schema_not_apply() {
+ assertThat(
+ new DependentSchemasKeyword(new NamedJsonSchemas(Map.of("test", JsonSchemas.load(JsonValue.FALSE))))
+ .asApplicator()
+ .applyTo(Json.createObjectBuilder().add("true", 1).build()),
+ is(true)
+ );
+ }
+}
diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/ItemsKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/ItemsKeywordTest.java
index a346d3c0..ef61862d 100644
--- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/ItemsKeywordTest.java
+++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/ItemsKeywordTest.java
@@ -27,22 +27,19 @@
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.is;
-import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory;
-import io.github.sebastiantoepfer.jsonschema.core.keyword.type.SubSchemaKeywordType;
+import io.github.sebastiantoepfer.jsonschema.JsonSchemas;
import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
+import io.github.sebastiantoepfer.jsonschema.keyword.StaticAnnotation;
import jakarta.json.Json;
-import jakarta.json.JsonObject;
import jakarta.json.JsonValue;
+import java.util.List;
import org.junit.jupiter.api.Test;
class ItemsKeywordTest {
@Test
void should_know_his_name() {
- final Keyword items = createKeywordFrom(
- Json.createObjectBuilder().add("items", JsonValue.EMPTY_JSON_OBJECT).build()
- );
-
+ final Keyword items = new ItemsKeyword(List.of(), JsonSchemas.load(JsonValue.TRUE));
assertThat(items.hasName("items"), is(true));
assertThat(items.hasName("test"), is(false));
}
@@ -50,9 +47,7 @@ void should_know_his_name() {
@Test
void should_be_invalid_if_items_does_not_match_schema() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder().add("items", Json.createObjectBuilder().add("type", "number")).build()
- )
+ new ItemsKeyword(List.of(), JsonSchemas.load(Json.createObjectBuilder().add("type", "number").build()))
.asApplicator()
.applyTo(Json.createArrayBuilder().add(1).add("invalid").add(2).build()),
is(false)
@@ -62,9 +57,7 @@ void should_be_invalid_if_items_does_not_match_schema() {
@Test
void should_be_valid_if_all_items_match_schema() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder().add("items", Json.createObjectBuilder().add("type", "number")).build()
- )
+ new ItemsKeyword(List.of(), JsonSchemas.load(Json.createObjectBuilder().add("type", "number").build()))
.asApplicator()
.applyTo(Json.createArrayBuilder().add(1).add(2).build()),
is(true)
@@ -74,9 +67,7 @@ void should_be_valid_if_all_items_match_schema() {
@Test
void should_be_applicator_and_annotation() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder().add("items", JsonValue.EMPTY_JSON_OBJECT).build()
- ).categories(),
+ new ItemsKeyword(List.of(), JsonSchemas.load(JsonValue.EMPTY_JSON_OBJECT)).categories(),
contains(Keyword.KeywordCategory.APPLICATOR, Keyword.KeywordCategory.ANNOTATION)
);
}
@@ -84,7 +75,7 @@ void should_be_applicator_and_annotation() {
@Test
void should_produces_true_if_is_applied_to_any_instance() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("items", JsonValue.EMPTY_JSON_OBJECT).build())
+ new ItemsKeyword(List.of(), JsonSchemas.load(JsonValue.TRUE))
.asAnnotation()
.valueFor(Json.createArrayBuilder().add(1).build()),
is(JsonValue.TRUE)
@@ -94,11 +85,9 @@ void should_produces_true_if_is_applied_to_any_instance() {
@Test
void should_return_false_if_not_applies_to_any_item() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder()
- .add("prefixItems", Json.createArrayBuilder().add(true))
- .add("items", JsonValue.FALSE)
- .build()
+ new ItemsKeyword(
+ List.of(new StaticAnnotation("prefixItems", JsonValue.TRUE)),
+ JsonSchemas.load(JsonValue.FALSE)
)
.asAnnotation()
.valueFor(Json.createArrayBuilder().add(1).build()),
@@ -109,11 +98,9 @@ void should_return_false_if_not_applies_to_any_item() {
@Test
void should_be_valid_if_invaliditem_is_already_checked_by_prefixItems() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder()
- .add("prefixItems", Json.createArrayBuilder().add(true).add(true))
- .add("items", Json.createObjectBuilder().add("type", "integer"))
- .build()
+ new ItemsKeyword(
+ List.of(new StaticAnnotation("prefixItems", JsonValue.TRUE)),
+ JsonSchemas.load(Json.createObjectBuilder().add("type", "integer").build())
)
.asApplicator()
.applyTo(Json.createArrayBuilder().add("1").add("2").add(1).build()),
@@ -124,21 +111,13 @@ void should_be_valid_if_invaliditem_is_already_checked_by_prefixItems() {
@Test
void should_be_invalid_if_invaliditem_is_not_already_checked_by_prefixItems() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder()
- .add("prefixItems", Json.createArrayBuilder().add(true))
- .add("items", Json.createObjectBuilder().add("type", "integer"))
- .build()
+ new ItemsKeyword(
+ List.of(new StaticAnnotation("prefixItems", Json.createValue(0))),
+ JsonSchemas.load(Json.createObjectBuilder().add("type", "integer").build())
)
.asApplicator()
.applyTo(Json.createArrayBuilder().add("1").add("2").add(1).build()),
is(false)
);
}
-
- private static Keyword createKeywordFrom(final JsonObject json) {
- return new SubSchemaKeywordType("items", ItemsKeyword::new).createKeyword(
- new DefaultJsonSchemaFactory().create(json)
- );
- }
}
diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/NotKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/NotKeywordTest.java
new file mode 100644
index 00000000..28cc6849
--- /dev/null
+++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/NotKeywordTest.java
@@ -0,0 +1,86 @@
+/*
+ * The MIT License
+ *
+ * Copyright 2024 sebastian.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package io.github.sebastiantoepfer.jsonschema.core.vocab.applicator;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.hasEntry;
+import static org.hamcrest.Matchers.hasKey;
+import static org.hamcrest.Matchers.is;
+
+import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia;
+import io.github.sebastiantoepfer.jsonschema.JsonSchemas;
+import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
+import jakarta.json.Json;
+import jakarta.json.JsonValue;
+import org.hamcrest.Matcher;
+import org.junit.jupiter.api.Test;
+
+class NotKeywordTest {
+
+ @Test
+ void should_know_his_name() {
+ final Keyword items = new NotKeyword(JsonSchemas.load(JsonValue.FALSE));
+
+ assertThat(items.hasName("not"), is(true));
+ assertThat(items.hasName("test"), is(false));
+ }
+
+ @Test
+ void should_be_printable() {
+ assertThat(
+ new NotKeyword(
+ JsonSchemas.load(
+ Json.createObjectBuilder()
+ .add(
+ "properties",
+ Json.createObjectBuilder().add("foo", Json.createObjectBuilder().add("type", "string"))
+ )
+ .add("required", Json.createArrayBuilder().add("foo"))
+ .build()
+ )
+ ).printOn(new HashMapMedia()),
+ (Matcher) hasEntry(is("not"), hasKey("properties"))
+ );
+ }
+
+ @Test
+ void should_be_valid_if_schema_not_apply() {
+ assertThat(
+ new NotKeyword(JsonSchemas.load(JsonValue.FALSE))
+ .asApplicator()
+ .applyTo(Json.createObjectBuilder().add("foo", "foo").build()),
+ is(true)
+ );
+ }
+
+ @Test
+ void should_be_invalid_if_schema_apply() {
+ assertThat(
+ new NotKeyword(JsonSchemas.load(JsonValue.TRUE))
+ .asApplicator()
+ .applyTo(Json.createObjectBuilder().add("foo", 3).add("bar", "bar").build()),
+ is(false)
+ );
+ }
+}
diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/OneOfKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/OneOfKeywordTest.java
new file mode 100644
index 00000000..62b9f8da
--- /dev/null
+++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/OneOfKeywordTest.java
@@ -0,0 +1,176 @@
+/*
+ * The MIT License
+ *
+ * Copyright 2024 sebastian.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package io.github.sebastiantoepfer.jsonschema.core.vocab.applicator;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.hasEntry;
+import static org.hamcrest.Matchers.hasItem;
+import static org.hamcrest.Matchers.hasKey;
+import static org.hamcrest.Matchers.is;
+
+import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia;
+import io.github.sebastiantoepfer.jsonschema.JsonSchemas;
+import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
+import jakarta.json.Json;
+import jakarta.json.JsonValue;
+import java.util.List;
+import org.hamcrest.Matcher;
+import org.junit.jupiter.api.Test;
+
+class OneOfKeywordTest {
+
+ @Test
+ void should_know_his_name() {
+ final Keyword items = new OneOfKeyword(List.of(JsonSchemas.load(JsonValue.TRUE)));
+
+ assertThat(items.hasName("oneOf"), is(true));
+ assertThat(items.hasName("test"), is(false));
+ }
+
+ @Test
+ void should_be_printable() {
+ assertThat(
+ new OneOfKeyword(
+ Json.createArrayBuilder()
+ .add(
+ Json.createObjectBuilder()
+ .add(
+ "properties",
+ Json.createObjectBuilder().add("foo", Json.createObjectBuilder().add("type", "string"))
+ )
+ .add("required", Json.createArrayBuilder().add("foo"))
+ )
+ .add(
+ Json.createObjectBuilder()
+ .add(
+ "properties",
+ Json.createObjectBuilder().add("bar", Json.createObjectBuilder().add("type", "number"))
+ )
+ .add("required", Json.createArrayBuilder().add("bar"))
+ )
+ .build()
+ .stream()
+ .map(JsonSchemas::load)
+ .toList()
+ ).printOn(new HashMapMedia()),
+ (Matcher) hasEntry(is("oneOf"), hasItem((hasKey("properties"))))
+ );
+ }
+
+ @Test
+ void should_be_valid_if_exactly_one_schema_applies() {
+ assertThat(
+ new OneOfKeyword(
+ Json.createArrayBuilder()
+ .add(
+ Json.createObjectBuilder()
+ .add(
+ "properties",
+ Json.createObjectBuilder().add("foo", Json.createObjectBuilder().add("type", "string"))
+ )
+ .add("required", Json.createArrayBuilder().add("foo"))
+ )
+ .add(
+ Json.createObjectBuilder()
+ .add(
+ "properties",
+ Json.createObjectBuilder().add("bar", Json.createObjectBuilder().add("type", "number"))
+ )
+ .add("required", Json.createArrayBuilder().add("bar"))
+ )
+ .build()
+ .stream()
+ .map(JsonSchemas::load)
+ .toList()
+ )
+ .asApplicator()
+ .applyTo(Json.createObjectBuilder().add("foo", "foo").build()),
+ is(true)
+ );
+ }
+
+ @Test
+ void should_be_invalid_if_none_schema_not_apply() {
+ assertThat(
+ new OneOfKeyword(
+ Json.createArrayBuilder()
+ .add(
+ Json.createObjectBuilder()
+ .add(
+ "properties",
+ Json.createObjectBuilder().add("foo", Json.createObjectBuilder().add("type", "string"))
+ )
+ .add("required", Json.createArrayBuilder().add("foo"))
+ )
+ .add(
+ Json.createObjectBuilder()
+ .add(
+ "properties",
+ Json.createObjectBuilder().add("bar", Json.createObjectBuilder().add("type", "number"))
+ )
+ .add("required", Json.createArrayBuilder().add("bar"))
+ )
+ .build()
+ .stream()
+ .map(JsonSchemas::load)
+ .toList()
+ )
+ .asApplicator()
+ .applyTo(Json.createObjectBuilder().add("foo", 3).add("bar", "bar").build()),
+ is(false)
+ );
+ }
+
+ @Test
+ void should_be_invalid_if_more_than_one_schema_apply() {
+ assertThat(
+ new OneOfKeyword(
+ Json.createArrayBuilder()
+ .add(
+ Json.createObjectBuilder()
+ .add(
+ "properties",
+ Json.createObjectBuilder().add("foo", Json.createObjectBuilder().add("type", "string"))
+ )
+ .add("required", Json.createArrayBuilder().add("foo"))
+ )
+ .add(
+ Json.createObjectBuilder()
+ .add(
+ "properties",
+ Json.createObjectBuilder().add("bar", Json.createObjectBuilder().add("type", "number"))
+ )
+ .add("required", Json.createArrayBuilder().add("bar"))
+ )
+ .build()
+ .stream()
+ .map(JsonSchemas::load)
+ .toList()
+ )
+ .asApplicator()
+ .applyTo(Json.createObjectBuilder().add("foo", "foo").add("bar", 33).build()),
+ is(false)
+ );
+ }
+}
diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/PatternPropertiesKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/PatternPropertiesKeywordTest.java
index 9d8dc219..f015d7c9 100644
--- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/PatternPropertiesKeywordTest.java
+++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/PatternPropertiesKeywordTest.java
@@ -27,18 +27,17 @@
import static org.hamcrest.Matchers.anEmptyMap;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.hasEntry;
-import static org.hamcrest.Matchers.hasEntry;
import static org.hamcrest.Matchers.is;
import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia;
-import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory;
-import io.github.sebastiantoepfer.jsonschema.core.keyword.type.NamedJsonSchemaKeywordType;
+import io.github.sebastiantoepfer.jsonschema.JsonSchemas;
+import io.github.sebastiantoepfer.jsonschema.core.keyword.type.NamedJsonSchemas;
import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
import jakarta.json.Json;
-import jakarta.json.JsonObject;
import jakarta.json.JsonString;
import jakarta.json.JsonValue;
import java.math.BigDecimal;
+import java.util.Map;
import org.hamcrest.Matcher;
import org.junit.jupiter.api.Test;
@@ -46,9 +45,7 @@ class PatternPropertiesKeywordTest {
@Test
void should_know_his_name() {
- final Keyword keyword = createKeywordFrom(
- Json.createObjectBuilder().add("patternProperties", JsonValue.EMPTY_JSON_OBJECT).build()
- );
+ final Keyword keyword = new PatternPropertiesKeyword(new NamedJsonSchemas(Map.of()));
assertThat(keyword.hasName("patternProperties"), is(true));
assertThat(keyword.hasName("test"), is(false));
@@ -57,9 +54,7 @@ void should_know_his_name() {
@Test
void should_be_an_applicator_and_an_annotation() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder().add("patternProperties", JsonValue.EMPTY_JSON_OBJECT).build()
- ).categories(),
+ new PatternPropertiesKeyword(new NamedJsonSchemas(Map.of())).categories(),
containsInAnyOrder(Keyword.KeywordCategory.APPLICATOR, Keyword.KeywordCategory.ANNOTATION)
);
}
@@ -67,9 +62,7 @@ void should_be_an_applicator_and_an_annotation() {
@Test
void should_be_valid_for_non_object() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("patternProperties", JsonValue.EMPTY_JSON_OBJECT).build())
- .asApplicator()
- .applyTo(JsonValue.FALSE),
+ new PatternPropertiesKeyword(new NamedJsonSchemas(Map.of())).asApplicator().applyTo(JsonValue.FALSE),
is(true)
);
}
@@ -77,7 +70,7 @@ void should_be_valid_for_non_object() {
@Test
void should_be_valid_for_empty_object() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("patternProperties", JsonValue.EMPTY_JSON_OBJECT).build())
+ new PatternPropertiesKeyword(new NamedJsonSchemas(Map.of()))
.asApplicator()
.applyTo(JsonValue.EMPTY_JSON_OBJECT),
is(true)
@@ -87,11 +80,7 @@ void should_be_valid_for_empty_object() {
@Test
void should_be_valid_if_properties_applies_to_his_schema() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder()
- .add("patternProperties", Json.createObjectBuilder().add("t.st", JsonValue.TRUE))
- .build()
- )
+ new PatternPropertiesKeyword(new NamedJsonSchemas(Map.of("t.st", JsonSchemas.load(JsonValue.TRUE))))
.asApplicator()
.applyTo(Json.createObjectBuilder().add("test", 1).build()),
is(true)
@@ -101,32 +90,20 @@ void should_be_valid_if_properties_applies_to_his_schema() {
@Test
void should_be_invalid_if_properties_not_applies_to_his_schema() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder()
- .add("patternProperties", Json.createObjectBuilder().add("t.st", JsonValue.FALSE))
- .build()
- )
+ new PatternPropertiesKeyword(new NamedJsonSchemas(Map.of("t.st", JsonSchemas.load(JsonValue.FALSE))))
.asApplicator()
.applyTo(Json.createObjectBuilder().add("test", 1).build()),
is(false)
);
}
- /*
- Attention can be falky.
- JsonObject is a map, so the properties occurred in random order.
- This means for this test it could be green without using all assertions.
- */
@Test
- void should_be_invalid_if_one_schema_doesn_apply() {
+ void should_be_invalid_if_one_schema_does_not_apply() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder()
- .add(
- "patternProperties",
- Json.createObjectBuilder().add("t.st", JsonValue.TRUE).add("t.*", JsonValue.FALSE)
- )
- .build()
+ new PatternPropertiesKeyword(
+ new NamedJsonSchemas(
+ Map.of("t.st", JsonSchemas.load(JsonValue.TRUE), "t.*", JsonSchemas.load(JsonValue.FALSE))
+ )
)
.asApplicator()
.applyTo(Json.createObjectBuilder().add("test", 1).build()),
@@ -137,11 +114,7 @@ void should_be_invalid_if_one_schema_doesn_apply() {
@Test
void should_be_valid_if_properties_not_covered() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder()
- .add("patternProperties", Json.createObjectBuilder().add("t.st", JsonValue.FALSE))
- .build()
- )
+ new PatternPropertiesKeyword(new NamedJsonSchemas(Map.of("t.st", JsonSchemas.load(JsonValue.FALSE))))
.asApplicator()
.applyTo(Json.createObjectBuilder().add("foo", 1).build()),
is(true)
@@ -151,11 +124,7 @@ void should_be_valid_if_properties_not_covered() {
@Test
void should_return_the_matching_property_names() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder()
- .add("patternProperties", Json.createObjectBuilder().add("f.o", JsonValue.TRUE))
- .build()
- )
+ new PatternPropertiesKeyword(new NamedJsonSchemas(Map.of("f.o", JsonSchemas.load(JsonValue.TRUE))))
.asAnnotation()
.valueFor(
Json.createObjectBuilder()
@@ -176,18 +145,10 @@ void should_return_the_matching_property_names() {
@Test
void should_be_printable() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder()
- .add("patternProperties", Json.createObjectBuilder().add("f.o", JsonValue.TRUE))
- .build()
- ).printOn(new HashMapMedia()),
+ new PatternPropertiesKeyword(new NamedJsonSchemas(Map.of("f.o", JsonSchemas.load(JsonValue.TRUE)))).printOn(
+ new HashMapMedia()
+ ),
(Matcher) hasEntry(is("patternProperties"), hasEntry(is("f.o"), anEmptyMap()))
);
}
-
- private static Keyword createKeywordFrom(final JsonObject json) {
- return new NamedJsonSchemaKeywordType("patternProperties", PatternPropertiesKeyword::new).createKeyword(
- new DefaultJsonSchemaFactory().create(json)
- );
- }
}
diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/PrefixItemsKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/PrefixItemsKeywordTest.java
index b625575e..9ba9728b 100644
--- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/PrefixItemsKeywordTest.java
+++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/PrefixItemsKeywordTest.java
@@ -31,12 +31,11 @@
import static org.hamcrest.Matchers.is;
import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia;
-import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory;
-import io.github.sebastiantoepfer.jsonschema.core.keyword.type.ArraySubSchemaKeywordType;
+import io.github.sebastiantoepfer.jsonschema.JsonSchemas;
import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
import jakarta.json.Json;
-import jakarta.json.JsonObject;
import jakarta.json.JsonValue;
+import java.util.List;
import org.hamcrest.Matcher;
import org.junit.jupiter.api.Test;
@@ -44,9 +43,7 @@ class PrefixItemsKeywordTest {
@Test
void should_know_his_name() {
- final Keyword items = createKeywordFrom(
- Json.createObjectBuilder().add("prefixItems", Json.createArrayBuilder().add(JsonValue.TRUE)).build()
- );
+ final Keyword items = new PrefixItemsKeyword(List.of(JsonSchemas.load(JsonValue.TRUE)));
assertThat(items.hasName("prefixItems"), is(true));
assertThat(items.hasName("test"), is(false));
@@ -55,9 +52,7 @@ void should_know_his_name() {
@Test
void should_return_zero_as_value() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder().add("prefixItems", Json.createArrayBuilder().add(JsonValue.TRUE)).build()
- )
+ new PrefixItemsKeyword(List.of(JsonSchemas.load(JsonValue.TRUE)))
.asAnnotation()
.valueFor(Json.createArrayBuilder().add(1).add(2).build()),
is(Json.createValue(0))
@@ -67,10 +62,14 @@ void should_return_zero_as_value() {
@Test
void should_retrun_true_if_is_applies_to_all_values() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder()
- .add("prefixItems", Json.createArrayBuilder().add(JsonValue.TRUE).add(JsonValue.TRUE))
+ new PrefixItemsKeyword(
+ Json.createArrayBuilder()
+ .add(JsonValue.TRUE)
+ .add(JsonValue.TRUE)
.build()
+ .stream()
+ .map(JsonSchemas::load)
+ .toList()
)
.asAnnotation()
.valueFor(Json.createArrayBuilder().add(1).add(2).build()),
@@ -81,9 +80,7 @@ void should_retrun_true_if_is_applies_to_all_values() {
@Test
void should_be_valid_for_non_arrays() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder().add("prefixItems", Json.createArrayBuilder().add(JsonValue.FALSE)).build()
- )
+ new PrefixItemsKeyword(List.of(JsonSchemas.load(JsonValue.FALSE)))
.asApplicator()
.applyTo(Json.createValue(1)),
is(true)
@@ -93,9 +90,7 @@ void should_be_valid_for_non_arrays() {
@Test
void should_be_valid_if_first_item_match_schema() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder().add("prefixItems", Json.createArrayBuilder().add(JsonValue.TRUE)).build()
- )
+ new PrefixItemsKeyword(List.of(JsonSchemas.load(JsonValue.TRUE)))
.asApplicator()
.applyTo(Json.createArrayBuilder().add(1).build()),
is(true)
@@ -105,10 +100,14 @@ void should_be_valid_if_first_item_match_schema() {
@Test
void should_be_invalid_if_second_item_does_not_match_schema() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder()
- .add("prefixItems", Json.createArrayBuilder().add(JsonValue.TRUE).add(JsonValue.FALSE))
+ new PrefixItemsKeyword(
+ Json.createArrayBuilder()
+ .add(JsonValue.TRUE)
+ .add(JsonValue.FALSE)
.build()
+ .stream()
+ .map(JsonSchemas::load)
+ .toList()
)
.asApplicator()
.applyTo(Json.createArrayBuilder().add(1).add(3).build()),
@@ -119,9 +118,7 @@ void should_be_invalid_if_second_item_does_not_match_schema() {
@Test
void should_be_applicator_and_annotation() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder().add("prefixItems", JsonValue.EMPTY_JSON_ARRAY).build()
- ).categories(),
+ new PrefixItemsKeyword(List.of(JsonSchemas.load(JsonValue.TRUE))).categories(),
containsInAnyOrder(Keyword.KeywordCategory.APPLICATOR, Keyword.KeywordCategory.ANNOTATION)
);
}
@@ -129,16 +126,8 @@ void should_be_applicator_and_annotation() {
@Test
void should_be_printable() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder().add("prefixItems", Json.createArrayBuilder().add(JsonValue.TRUE)).build()
- ).printOn(new HashMapMedia()),
+ new PrefixItemsKeyword(List.of(JsonSchemas.load(JsonValue.TRUE))).printOn(new HashMapMedia()),
(Matcher) hasEntry(is("prefixItems"), contains(anEmptyMap()))
);
}
-
- private static Keyword createKeywordFrom(final JsonObject json) {
- return new ArraySubSchemaKeywordType("prefixItems", PrefixItemsKeyword::new).createKeyword(
- new DefaultJsonSchemaFactory().create(json)
- );
- }
}
diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/PropertiesKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/PropertiesKeywordTest.java
index f3e88790..1d18e283 100644
--- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/PropertiesKeywordTest.java
+++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/PropertiesKeywordTest.java
@@ -30,11 +30,10 @@
import static org.hamcrest.Matchers.is;
import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia;
-import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory;
-import io.github.sebastiantoepfer.jsonschema.core.keyword.type.NamedJsonSchemaKeywordType;
+import io.github.sebastiantoepfer.jsonschema.JsonSchemas;
+import io.github.sebastiantoepfer.jsonschema.core.keyword.type.NamedJsonSchemas;
import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
import jakarta.json.Json;
-import jakarta.json.JsonObject;
import jakarta.json.JsonValue;
import java.util.Map;
import org.hamcrest.Matcher;
@@ -44,9 +43,7 @@ class PropertiesKeywordTest {
@Test
void should_be_know_his_name() {
- final Keyword keyword = createKeywordFrom(
- Json.createObjectBuilder().add("properties", JsonValue.EMPTY_JSON_OBJECT).build()
- );
+ final Keyword keyword = new PropertiesKeyword(new NamedJsonSchemas(Map.of()));
assertThat(keyword.hasName("properties"), is(true));
assertThat(keyword.hasName("test"), is(false));
@@ -55,9 +52,7 @@ void should_be_know_his_name() {
@Test
void should_be_an_applicator_and_annotation() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder().add("properties", JsonValue.EMPTY_JSON_OBJECT).build()
- ).categories(),
+ new PropertiesKeyword(new NamedJsonSchemas(Map.of())).categories(),
containsInAnyOrder(Keyword.KeywordCategory.APPLICATOR, Keyword.KeywordCategory.ANNOTATION)
);
}
@@ -65,9 +60,7 @@ void should_be_an_applicator_and_annotation() {
@Test
void should_be_valid_for_non_objects() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("properties", JsonValue.EMPTY_JSON_OBJECT).build())
- .asApplicator()
- .applyTo(JsonValue.EMPTY_JSON_ARRAY),
+ new PropertiesKeyword(new NamedJsonSchemas(Map.of())).asApplicator().applyTo(JsonValue.EMPTY_JSON_ARRAY),
is(true)
);
}
@@ -75,11 +68,7 @@ void should_be_valid_for_non_objects() {
@Test
void should_be_valid_if_properties_applies_to_his_schema() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder()
- .add("properties", Json.createObjectBuilder().add("test", JsonValue.TRUE))
- .build()
- )
+ new PropertiesKeyword(new NamedJsonSchemas(Map.of("test", JsonSchemas.load(JsonValue.TRUE))))
.asApplicator()
.applyTo(Json.createObjectBuilder().add("test", 1).build()),
is(true)
@@ -89,11 +78,7 @@ void should_be_valid_if_properties_applies_to_his_schema() {
@Test
void should_be_invalid_if_properties_not_applies_to_his_schema() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder()
- .add("properties", Json.createObjectBuilder().add("test", JsonValue.FALSE))
- .build()
- )
+ new PropertiesKeyword(new NamedJsonSchemas(Map.of("test", JsonSchemas.load(JsonValue.FALSE))))
.asApplicator()
.applyTo(Json.createObjectBuilder().add("test", 1).build()),
is(false)
@@ -103,11 +88,7 @@ void should_be_invalid_if_properties_not_applies_to_his_schema() {
@Test
void should_be_valid_for_empty_objects() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder()
- .add("properties", Json.createObjectBuilder().add("test", JsonValue.FALSE))
- .build()
- )
+ new PropertiesKeyword(new NamedJsonSchemas(Map.of("test", JsonSchemas.load(JsonValue.FALSE))))
.asApplicator()
.applyTo(JsonValue.EMPTY_JSON_OBJECT),
is(true)
@@ -117,10 +98,10 @@ void should_be_valid_for_empty_objects() {
@Test
void should_return_all_matched_propertynames() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder()
- .add("properties", Json.createObjectBuilder().add("test", true).add("foo", true))
- .build()
+ new PropertiesKeyword(
+ new NamedJsonSchemas(
+ Map.of("test", JsonSchemas.load(JsonValue.TRUE), "foo", JsonSchemas.load(JsonValue.TRUE))
+ )
)
.asAnnotation()
.valueFor(Json.createObjectBuilder().add("foo", 1).build())
@@ -134,20 +115,10 @@ void should_return_all_matched_propertynames() {
@Test
void should_be_printable() {
assertThat(
- ((Map) createKeywordFrom(
- Json.createObjectBuilder()
- .add("properties", Json.createObjectBuilder().add("test", JsonValue.TRUE))
- .build()
- )
+ ((Map) new PropertiesKeyword(new NamedJsonSchemas(Map.of("test", JsonSchemas.load(JsonValue.TRUE))))
.printOn(new HashMapMedia())
.get("properties")).get("test"),
(Matcher) anEmptyMap()
);
}
-
- private static Keyword createKeywordFrom(final JsonObject json) {
- return new NamedJsonSchemaKeywordType("properties", PropertiesKeyword::new).createKeyword(
- new DefaultJsonSchemaFactory().create(json)
- );
- }
}
diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/CommentKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/CommentKeywordTest.java
index a853cda2..625e81cf 100644
--- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/CommentKeywordTest.java
+++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/CommentKeywordTest.java
@@ -28,21 +28,14 @@
import static org.hamcrest.Matchers.is;
import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia;
-import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory;
-import io.github.sebastiantoepfer.jsonschema.core.keyword.type.StringKeywordType;
import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
-import jakarta.json.Json;
-import jakarta.json.JsonObject;
-import jakarta.json.spi.JsonProvider;
import org.junit.jupiter.api.Test;
class CommentKeywordTest {
@Test
void should_know_her_name() {
- final Keyword keyword = createKeywordFrom(
- Json.createObjectBuilder().add("$comment", Json.createValue("comment")).build()
- );
+ final Keyword keyword = new CommentKeyword("comment");
assertThat(keyword.hasName("$comment"), is(true));
assertThat(keyword.hasName("test"), is(false));
@@ -50,17 +43,6 @@ void should_know_her_name() {
@Test
void should_be_printable() {
- assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("$comment", Json.createValue("comment")).build()).printOn(
- new HashMapMedia()
- ),
- hasEntry("$comment", "comment")
- );
- }
-
- private static Keyword createKeywordFrom(final JsonObject json) {
- return new StringKeywordType(JsonProvider.provider(), "$comment", CommentKeyword::new).createKeyword(
- new DefaultJsonSchemaFactory().create(json)
- );
+ assertThat(new CommentKeyword("comment").printOn(new HashMapMedia()), hasEntry("$comment", "comment"));
}
}
diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/DefsKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/DefsKeywordTest.java
index 4dd22189..878f9d38 100644
--- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/DefsKeywordTest.java
+++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/DefsKeywordTest.java
@@ -29,12 +29,9 @@
import static org.hamcrest.Matchers.is;
import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia;
-import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory;
-import io.github.sebastiantoepfer.jsonschema.core.keyword.type.NamedJsonSchemaKeywordType;
+import io.github.sebastiantoepfer.jsonschema.core.keyword.type.NamedJsonSchemas;
import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
-import jakarta.json.Json;
-import jakarta.json.JsonObject;
-import jakarta.json.JsonValue;
+import java.util.Map;
import org.hamcrest.Matcher;
import org.junit.jupiter.api.Test;
@@ -42,9 +39,7 @@ class DefsKeywordTest {
@Test
void should_know_his_name() {
- final Keyword defs = createKeywordFrom(
- Json.createObjectBuilder().add("$defs", JsonValue.EMPTY_JSON_OBJECT).build()
- );
+ final Keyword defs = new DefsKeyword(new NamedJsonSchemas(Map.of()));
assertThat(defs.hasName("$defs"), is(true));
assertThat(defs.hasName("test"), is(false));
@@ -53,16 +48,8 @@ void should_know_his_name() {
@Test
void should_be_printable() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("$defs", JsonValue.EMPTY_JSON_OBJECT).build()).printOn(
- new HashMapMedia()
- ),
+ new DefsKeyword(new NamedJsonSchemas(Map.of())).printOn(new HashMapMedia()),
(Matcher) hasEntry(is("$defs"), anEmptyMap())
);
}
-
- private static Keyword createKeywordFrom(final JsonObject json) {
- return new NamedJsonSchemaKeywordType(DefsKeyword.NAME, DefsKeyword::new).createKeyword(
- new DefaultJsonSchemaFactory().create(json)
- );
- }
}
diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/DynamicRefKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/DynamicRefKeywordTest.java
index d909a1a9..5c708491 100644
--- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/DynamicRefKeywordTest.java
+++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/DynamicRefKeywordTest.java
@@ -28,13 +28,8 @@
import static org.hamcrest.Matchers.is;
import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia;
-import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory;
-import io.github.sebastiantoepfer.jsonschema.core.keyword.type.StringKeywordType;
import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
-import jakarta.json.Json;
-import jakarta.json.JsonObject;
import jakarta.json.JsonValue;
-import jakarta.json.spi.JsonProvider;
import java.net.URI;
import org.hamcrest.Matcher;
import org.junit.jupiter.api.Test;
@@ -43,37 +38,27 @@ class DynamicRefKeywordTest {
@Test
void should_create_keyword_with_name() {
- assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("$dynamicRef", "test").build()).hasName("$dynamicRef"),
- is(true)
- );
- }
-
- @Test
- void notFinischedYet() {
- final Keyword keyword = createKeywordFrom(Json.createObjectBuilder().add("$dynamicRef", "test").build());
+ final Keyword keyword = new DynamicRefKeyword(URI.create("test"));
assertThat(keyword.hasName("$dynamicRef"), is(true));
assertThat(keyword.hasName("$id"), is(false));
-
- assertThat(keyword.asApplicator().applyTo(JsonValue.TRUE), is(true));
}
@Test
void should_be_printable() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("$dynamicRef", "test").build()).printOn(
- new HashMapMedia()
- ),
+ new DynamicRefKeyword(URI.create("test")).printOn(new HashMapMedia()),
(Matcher) hasEntry(is("$dynamicRef"), is("test"))
);
}
- private static Keyword createKeywordFrom(final JsonObject json) {
- return new StringKeywordType(
- JsonProvider.provider(),
- DynamicRefKeyword.NAME,
- s -> new DynamicRefKeyword(URI.create(s))
- ).createKeyword(new DefaultJsonSchemaFactory().create(json));
+ @Test
+ void notFinischedYet() {
+ final Keyword keyword = new DynamicRefKeyword(URI.create("test"));
+
+ assertThat(keyword.hasName("$dynamicRef"), is(true));
+ assertThat(keyword.hasName("$id"), is(false));
+
+ assertThat(keyword.asApplicator().applyTo(JsonValue.TRUE), is(true));
}
}
diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/IdKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/IdKeywordTest.java
index 0e23f507..3d9cb8fc 100644
--- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/IdKeywordTest.java
+++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/IdKeywordTest.java
@@ -28,12 +28,7 @@
import static org.hamcrest.Matchers.is;
import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia;
-import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory;
-import io.github.sebastiantoepfer.jsonschema.core.keyword.type.StringKeywordType;
import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
-import jakarta.json.Json;
-import jakarta.json.JsonObject;
-import jakarta.json.spi.JsonProvider;
import java.net.URI;
import org.hamcrest.Matcher;
import org.junit.jupiter.api.Test;
@@ -42,7 +37,7 @@ class IdKeywordTest {
@Test
void should_know_his_name() {
- final Keyword id = createKeywordFrom(Json.createObjectBuilder().add("$id", Json.createValue("/test")).build());
+ final Keyword id = new IdKeyword(URI.create("/test"));
assertThat(id.hasName("$id"), is(true));
assertThat(id.hasName("test"), is(false));
@@ -51,13 +46,7 @@ void should_know_his_name() {
@Test
void should_retun_his_uri() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder()
- .add("$id", Json.createValue("https://json-schema.org/draft/2020-12/schema"))
- .build()
- )
- .asIdentifier()
- .asUri(),
+ new IdKeyword(URI.create("https://json-schema.org/draft/2020-12/schema")).asIdentifier().asUri(),
is(URI.create("https://json-schema.org/draft/2020-12/schema"))
);
}
@@ -65,18 +54,8 @@ void should_retun_his_uri() {
@Test
void should_be_printable() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder()
- .add("$id", Json.createValue("https://json-schema.org/draft/2020-12/schema"))
- .build()
- ).printOn(new HashMapMedia()),
+ new IdKeyword(URI.create("https://json-schema.org/draft/2020-12/schema")).printOn(new HashMapMedia()),
(Matcher) hasEntry(is("$id"), is("https://json-schema.org/draft/2020-12/schema"))
);
}
-
- private static Keyword createKeywordFrom(final JsonObject json) {
- return new StringKeywordType(JsonProvider.provider(), "$id", s -> new IdKeyword(URI.create(s))).createKeyword(
- new DefaultJsonSchemaFactory().create(json)
- );
- }
}
diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/RefKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/RefKeywordTest.java
index dc34c53c..0a1e9baf 100644
--- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/RefKeywordTest.java
+++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/RefKeywordTest.java
@@ -26,55 +26,45 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasEntry;
import static org.hamcrest.Matchers.is;
-import static org.junit.jupiter.api.Assertions.assertThrows;
import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia;
import io.github.sebastiantoepfer.jsonschema.JsonSchema;
-import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory;
-import io.github.sebastiantoepfer.jsonschema.core.keyword.type.StringKeywordType;
+import io.github.sebastiantoepfer.jsonschema.JsonSchemas;
import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
import jakarta.json.Json;
-import jakarta.json.JsonObject;
-import jakarta.json.JsonValue;
-import jakarta.json.spi.JsonProvider;
+import java.io.IOException;
import java.net.URI;
import org.hamcrest.Matcher;
import org.junit.jupiter.api.Test;
class RefKeywordTest {
- @Test
- void should_be_not_createable_from_non_string() {
- final RefKeywordType keywordType = new RefKeywordType(JsonProvider.provider());
- final JsonSchema schema = new DefaultJsonSchemaFactory()
- .create(Json.createObjectBuilder().add("$ref", JsonValue.TRUE).build());
- assertThrows(IllegalArgumentException.class, () -> keywordType.createKeyword(schema));
- }
-
@Test
void should_know_his_name() {
- final Keyword ref = new RefKeywordType(JsonProvider.provider()).createKeyword(
- new DefaultJsonSchemaFactory().create(Json.createObjectBuilder().add("$ref", Json.createValue("#")).build())
+ final Keyword ref = new RefKeyword(
+ JsonSchemas.load(Json.createObjectBuilder().add("$ref", Json.createValue("#")).build()),
+ URI.create("#"),
+ new SchemaRegistry.DefaultSchemaRegistry()
);
-
assertThat(ref.hasName("$ref"), is(true));
assertThat(ref.hasName("test"), is(false));
}
@Test
void should_use_local_referenced_schema_for_validation() {
- final Keyword keyword = new RefKeywordType(JsonProvider.provider()).createKeyword(
- new DefaultJsonSchemaFactory()
- .create(
- Json.createObjectBuilder()
- .add(
- "$defs",
- Json.createObjectBuilder()
- .add("positiveInteger", Json.createObjectBuilder().add("type", "integer"))
- )
- .add("$ref", Json.createValue("#/$defs/positiveInteger"))
- .build()
- )
+ final Keyword keyword = new RefKeyword(
+ JsonSchemas.load(
+ Json.createObjectBuilder()
+ .add(
+ "$defs",
+ Json.createObjectBuilder()
+ .add("positiveInteger", Json.createObjectBuilder().add("type", "integer"))
+ )
+ .add("$ref", Json.createValue("#/$defs/positiveInteger"))
+ .build()
+ ),
+ URI.create("#/$defs/positiveInteger"),
+ new SchemaRegistry.DefaultSchemaRegistry()
);
assertThat(keyword.asApplicator().applyTo(Json.createValue(1L)), is(true));
@@ -83,42 +73,44 @@ void should_use_local_referenced_schema_for_validation() {
@Test
void should_use_remote_referenced_schema_for_validation() {
- final Keyword keyword = new RefKeywordType(JsonProvider.provider()).createKeyword(
- new DefaultJsonSchemaFactory()
- .create(
- Json.createObjectBuilder()
- .add(
- "$defs",
+ final Keyword keyword = new RefKeyword(
+ JsonSchemas.load(
+ Json.createObjectBuilder().add("$ref", Json.createValue("https://schema.org/byMonth")).build()
+ ),
+ URI.create("https://schema.org/byMonth"),
+ new SchemaRegistry() {
+ @Override
+ public JsonSchema schemaForUrl(final URI uri) throws IOException {
+ if (uri.equals(URI.create("https://schema.org/byMonth"))) {
+ //hen egg issue -> we need more than core :(
+ return JsonSchemas.load(
Json.createObjectBuilder()
- .add("positiveInteger", Json.createObjectBuilder().add("type", "integer"))
- )
- .add("$ref", Json.createValue("#/$defs/positiveInteger"))
- .build()
- )
+ .add("type", "integer")
+ .add("minimum", 1)
+ .add("maximum", 12)
+ .build()
+ );
+ } else {
+ throw new IOException("can not retrieve remote schema!");
+ }
+ }
+ }
);
-
assertThat(keyword.asApplicator().applyTo(Json.createValue(1L)), is(true));
+ assertThat(keyword.asApplicator().applyTo(Json.createValue(12L)), is(true));
+ assertThat(keyword.asApplicator().applyTo(Json.createValue(0L)), is(false));
+ assertThat(keyword.asApplicator().applyTo(Json.createValue(13L)), is(false));
}
@Test
void should_be_printable() {
assertThat(
- new RefKeywordType(JsonProvider.provider())
- .createKeyword(
- new DefaultJsonSchemaFactory()
- .create(Json.createObjectBuilder().add("$ref", Json.createValue("#")).build())
- )
- .printOn(new HashMapMedia()),
+ new RefKeyword(
+ JsonSchemas.load(Json.createObjectBuilder().add("$ref", Json.createValue("#")).build()),
+ URI.create("#"),
+ new SchemaRegistry.DefaultSchemaRegistry()
+ ).printOn(new HashMapMedia()),
(Matcher) hasEntry(is("$ref"), is("#"))
);
}
-
- private static Keyword createKeywordFrom(final JsonObject json) {
- final JsonSchema schema = new DefaultJsonSchemaFactory().create(json);
- return new StringKeywordType(
- JsonProvider.provider(),
- "$ref",
- s -> new RefKeyword(schema, URI.create(s))
- ).createKeyword(schema);
- }
}
diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/RefKeywordTypeTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/RefKeywordTypeTest.java
index ab7ed341..5750e79d 100644
--- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/RefKeywordTypeTest.java
+++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/RefKeywordTypeTest.java
@@ -25,8 +25,16 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
+import static org.hamcrest.Matchers.nullValue;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import io.github.sebastiantoepfer.jsonschema.JsonSchema;
+import io.github.sebastiantoepfer.jsonschema.JsonSchemas;
+import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory;
import io.github.sebastiantoepfer.jsonschema.keyword.KeywordType;
+import jakarta.json.Json;
+import jakarta.json.JsonValue;
import jakarta.json.spi.JsonProvider;
import org.junit.jupiter.api.Test;
@@ -40,4 +48,24 @@ void should_know_the_keywords_name() {
assertThat(refKeywordType.hasName("ref"), is(false));
assertThat(refKeywordType.hasName("test"), is(false));
}
+
+ @Test
+ void should_be_not_createable_from_non_string() {
+ final RefKeywordType keywordType = new RefKeywordType(JsonProvider.provider());
+ final JsonSchema schema = new DefaultJsonSchemaFactory()
+ .create(Json.createObjectBuilder().add("$ref", JsonValue.TRUE).build());
+ assertThrows(IllegalArgumentException.class, () -> keywordType.createKeyword(schema));
+ }
+
+ @Test
+ void should_create_refkeyword() {
+ assertThat(
+ new RefKeywordType(JsonProvider.provider()).createKeyword(
+ JsonSchemas.load(
+ Json.createObjectBuilder().add("$ref", Json.createValue("#/$defs/positiveInteger")).build()
+ )
+ ),
+ is(not(nullValue()))
+ );
+ }
}
diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/SchemaKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/SchemaKeywordTest.java
index e2ff6c7f..cc3eb4b5 100644
--- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/SchemaKeywordTest.java
+++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/SchemaKeywordTest.java
@@ -28,12 +28,7 @@
import static org.hamcrest.Matchers.is;
import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia;
-import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory;
-import io.github.sebastiantoepfer.jsonschema.core.keyword.type.StringKeywordType;
import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
-import jakarta.json.Json;
-import jakarta.json.JsonObject;
-import jakarta.json.spi.JsonProvider;
import java.net.URI;
import org.hamcrest.Matcher;
import org.junit.jupiter.api.Test;
@@ -42,9 +37,7 @@ class SchemaKeywordTest {
@Test
void should_know_his_name() {
- final Keyword schema = createKeywordFrom(
- Json.createObjectBuilder().add("$schema", Json.createValue("/test")).build()
- );
+ final Keyword schema = new SchemaKeyword(URI.create("/test"));
assertThat(schema.hasName("$schema"), is(true));
assertThat(schema.hasName("test"), is(false));
@@ -53,13 +46,7 @@ void should_know_his_name() {
@Test
void should_retun_his_uri() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder()
- .add("$schema", Json.createValue("https://json-schema.org/draft/2020-12/schema"))
- .build()
- )
- .asIdentifier()
- .asUri(),
+ new SchemaKeyword(URI.create("https://json-schema.org/draft/2020-12/schema")).asIdentifier().asUri(),
is(URI.create("https://json-schema.org/draft/2020-12/schema"))
);
}
@@ -67,20 +54,8 @@ void should_retun_his_uri() {
@Test
void should_be_printable() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder()
- .add("$schema", Json.createValue("https://json-schema.org/draft/2020-12/schema"))
- .build()
- ).printOn(new HashMapMedia()),
+ new SchemaKeyword(URI.create("https://json-schema.org/draft/2020-12/schema")).printOn(new HashMapMedia()),
(Matcher) hasEntry(is("$schema"), is("https://json-schema.org/draft/2020-12/schema"))
);
}
-
- private static Keyword createKeywordFrom(final JsonObject json) {
- return new StringKeywordType(
- JsonProvider.provider(),
- "$schema",
- s -> new SchemaKeyword(URI.create(s))
- ).createKeyword(new DefaultJsonSchemaFactory().create(json));
- }
}
diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/SchemaRegistryTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/SchemaRegistryTest.java
new file mode 100644
index 00000000..9723eec0
--- /dev/null
+++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/SchemaRegistryTest.java
@@ -0,0 +1,42 @@
+/*
+ * The MIT License
+ *
+ * Copyright 2024 sebastian.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package io.github.sebastiantoepfer.jsonschema.core.vocab.core;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+
+import jakarta.json.JsonValue;
+import java.net.URI;
+import org.junit.jupiter.api.Test;
+
+class SchemaRegistryTest {
+
+ @Test
+ void should_return_false_schema() throws Exception {
+ assertThat(
+ new SchemaRegistry.DefaultSchemaRegistry().schemaForUrl(URI.create("test")).getValueType(),
+ is(JsonValue.ValueType.FALSE)
+ );
+ }
+}
diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/VocabularyKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/VocabularyKeywordTest.java
new file mode 100644
index 00000000..e0356c83
--- /dev/null
+++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/VocabularyKeywordTest.java
@@ -0,0 +1,190 @@
+/*
+ * The MIT License
+ *
+ * Copyright 2023 sebastian.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package io.github.sebastiantoepfer.jsonschema.core.vocab.core;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.allOf;
+import static org.hamcrest.Matchers.containsInAnyOrder;
+import static org.hamcrest.Matchers.either;
+import static org.hamcrest.Matchers.hasEntry;
+import static org.hamcrest.Matchers.is;
+
+import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia;
+import io.github.sebastiantoepfer.jsonschema.Vocabulary;
+import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
+import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.LazyVocabularies;
+import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.ListVocabulary;
+import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.VocabularyDefinition;
+import jakarta.json.Json;
+import jakarta.json.JsonValue;
+import java.net.URI;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.stream.Stream;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.TypeSafeMatcher;
+import org.junit.jupiter.api.Test;
+
+class VocabularyKeywordTest {
+
+ @Test
+ void should_created_keyword_should_know_his_name() {
+ final Keyword vocabulary = new VocabularyKeyword(JsonValue.EMPTY_JSON_OBJECT, Stream::empty);
+
+ assertThat(vocabulary.hasName("$vocabulary"), is(true));
+ assertThat(vocabulary.hasName("$id"), is(false));
+ }
+
+ @Test
+ void should_create_definitions() {
+ assertThat(
+ new VocabularyKeyword(
+ Json.createObjectBuilder()
+ .add("https://json-schema.org/draft/2020-12/vocab/core", true)
+ .add("http://openapi.org/test", false)
+ .build(),
+ Stream::empty
+ )
+ .definitions()
+ .toList(),
+ containsInAnyOrder(
+ new VocabularyDefinitionMatcher(URI.create("https://json-schema.org/draft/2020-12/vocab/core"), true),
+ new VocabularyDefinitionMatcher(URI.create("http://openapi.org/test"), false)
+ )
+ );
+ }
+
+ @Test
+ void should_be_printable() {
+ assertThat(
+ new VocabularyKeyword(
+ Json.createObjectBuilder()
+ .add("https://json-schema.org/draft/2020-12/vocab/core", true)
+ .add("http://openapi.org/test", false)
+ .build(),
+ Stream::empty
+ ).printOn(new HashMapMedia()),
+ (Matcher) hasEntry(
+ is("$vocabulary"),
+ allOf(
+ hasEntry("https://json-schema.org/draft/2020-12/vocab/core", true),
+ hasEntry("http://openapi.org/test", false)
+ )
+ )
+ );
+ }
+
+ @Test
+ void should_not_lazy_load_offical_vocabs() {
+ //security and peformance. it should not be possible to override keywords define by this module!
+ assertThat(
+ new VocabularyKeyword(
+ Json.createObjectBuilder().add("https://json-schema.org/draft/2020-12/vocab/core", true).build(),
+ Stream::empty
+ )
+ .definitions()
+ .map(VocabularyDefinition::findVocabulary)
+ .flatMap(Optional::stream)
+ .map(Vocabulary::id)
+ .toList(),
+ containsInAnyOrder(URI.create("https://json-schema.org/draft/2020-12/vocab/core"))
+ );
+ }
+
+ @Test
+ void should_provide_vocab_which_know_they_id() {
+ final VocabularyDefinition vocabDef = new VocabularyKeyword(
+ Json.createObjectBuilder().add("https://json-schema.org/draft/2020-12/vocab/core", true).build(),
+ Stream::empty
+ )
+ .definitions()
+ .findFirst()
+ .orElseThrow();
+
+ assertThat(vocabDef.hasid(URI.create("https://json-schema.org/draft/2020-12/vocab/core")), is(true));
+ assertThat(vocabDef.hasid(URI.create("http://openapi.org/test")), is(false));
+ }
+
+ @Test
+ void should_lazy_load_non_offical_vocabs() {
+ assertThat(
+ new VocabularyKeyword(
+ Json.createObjectBuilder()
+ .add("https://json-schema.org/draft/2020-12/vocab/core", true)
+ .add("http://openapi.org/test", false)
+ .build(),
+ () ->
+ Stream.of(
+ new LazyVocabularies() {
+ @Override
+ public Optional loadVocabularyWithId(final URI id) {
+ return Optional.of(new ListVocabulary(id, List.of()));
+ }
+ }
+ )
+ )
+ .definitions()
+ .map(VocabularyDefinition::findVocabulary)
+ .flatMap(Optional::stream)
+ .map(Vocabulary::id)
+ .toList(),
+ containsInAnyOrder(
+ URI.create("https://json-schema.org/draft/2020-12/vocab/core"),
+ URI.create("http://openapi.org/test")
+ )
+ );
+ }
+
+ private static class VocabularyDefinitionMatcher extends TypeSafeMatcher {
+
+ private final URI id;
+ private final Matcher required;
+
+ public VocabularyDefinitionMatcher(final URI id) {
+ this(id, null);
+ }
+
+ public VocabularyDefinitionMatcher(final URI id, final Boolean required) {
+ super(VocabularyDefinition.class);
+ this.id = Objects.requireNonNull(id);
+ this.required = required == null ? either(is(true)).or(is(false)) : is(required);
+ }
+
+ @Override
+ protected boolean matchesSafely(final VocabularyDefinition item) {
+ return item.hasid(id) && required.matches(item.isRequired());
+ }
+
+ @Override
+ public void describeTo(final Description description) {
+ description
+ .appendText("Vocabulary definition with id: ")
+ .appendValue(id)
+ .appendText(" and required: ")
+ .appendDescriptionOf(required);
+ }
+ }
+}
diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/VocabularyKeywordTypeTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/VocabularyKeywordTypeTest.java
deleted file mode 100644
index 3ee97e25..00000000
--- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/VocabularyKeywordTypeTest.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * The MIT License
- *
- * Copyright 2023 sebastian.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-package io.github.sebastiantoepfer.jsonschema.core.vocab.core;
-
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.allOf;
-import static org.hamcrest.Matchers.containsInAnyOrder;
-import static org.hamcrest.Matchers.hasEntry;
-import static org.hamcrest.Matchers.is;
-
-import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia;
-import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory;
-import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
-import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.VocabularyDefinition;
-import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.VocabularyDefinitions;
-import jakarta.json.Json;
-import jakarta.json.JsonValue;
-import java.net.URI;
-import org.hamcrest.Matcher;
-import org.junit.jupiter.api.Test;
-
-class VocabularyKeywordTypeTest {
-
- @Test
- void should_created_keyword_should_know_his_name() {
- final Keyword vocabulary = new VocabularyKeywordType()
- .createKeyword(
- new DefaultJsonSchemaFactory()
- .create(Json.createObjectBuilder().add("$vocabulary", JsonValue.EMPTY_JSON_OBJECT).build())
- );
-
- assertThat(vocabulary.hasName("$vocabulary"), is(true));
- assertThat(vocabulary.hasName("$id"), is(false));
- }
-
- @Test
- void should_create_definitions() {
- assertThat(
- ((VocabularyDefinitions) new VocabularyKeywordType()
- .createKeyword(
- new DefaultJsonSchemaFactory()
- .create(
- Json.createObjectBuilder()
- .add(
- "$vocabulary",
- Json.createObjectBuilder()
- .add("https://json-schema.org/draft/2020-12/vocab/core", true)
- .add("http://openapi.org/test", false)
- )
- .build()
- )
- )).definitions()
- .toList(),
- containsInAnyOrder(
- new VocabularyDefinition(URI.create("https://json-schema.org/draft/2020-12/vocab/core"), true),
- new VocabularyDefinition(URI.create("http://openapi.org/test"), false)
- )
- );
- }
-
- @Test
- void should_be_printable() {
- assertThat(
- new VocabularyKeywordType()
- .createKeyword(
- new DefaultJsonSchemaFactory()
- .create(
- Json.createObjectBuilder()
- .add(
- "$vocabulary",
- Json.createObjectBuilder()
- .add("https://json-schema.org/draft/2020-12/vocab/core", true)
- .add("http://openapi.org/test", false)
- )
- .build()
- )
- )
- .printOn(new HashMapMedia()),
- (Matcher) hasEntry(
- is("$vocabulary"),
- allOf(
- hasEntry("https://json-schema.org/draft/2020-12/vocab/core", true),
- hasEntry("http://openapi.org/test", false)
- )
- )
- );
- }
-}
diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/ConstKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/ConstKeywordTest.java
index 15edcad9..63d7f2e9 100644
--- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/ConstKeywordTest.java
+++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/ConstKeywordTest.java
@@ -29,11 +29,8 @@
import static org.hamcrest.Matchers.is;
import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia;
-import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory;
-import io.github.sebastiantoepfer.jsonschema.core.keyword.type.AnyKeywordType;
import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
import jakarta.json.Json;
-import jakarta.json.JsonObject;
import jakarta.json.JsonValue;
import jakarta.json.spi.JsonProvider;
import org.hamcrest.Matcher;
@@ -43,9 +40,7 @@ class ConstKeywordTest {
@Test
void should_know_his_name() {
- final Keyword enumKeyword = createKeywordFrom(
- Json.createObjectBuilder().add("const", JsonValue.EMPTY_JSON_ARRAY).build()
- );
+ final Keyword enumKeyword = new ConstKeyword(JsonProvider.provider(), JsonValue.EMPTY_JSON_ARRAY);
assertThat(enumKeyword.hasName("const"), is(true));
assertThat(enumKeyword.hasName("test"), is(false));
@@ -54,7 +49,7 @@ void should_know_his_name() {
@Test
void should_be_valid_for_same_string_value() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("const", Json.createValue("hello")).build())
+ new ConstKeyword(JsonProvider.provider(), Json.createValue("hello"))
.asAssertion()
.isValidFor(Json.createValue("hello")),
is(true)
@@ -64,7 +59,7 @@ void should_be_valid_for_same_string_value() {
@Test
void should_be_invalid_for_different_string_value() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("const", Json.createValue("hello")).build())
+ new ConstKeyword(JsonProvider.provider(), Json.createValue("hello"))
.asAssertion()
.isValidFor(Json.createValue("world")),
is(false)
@@ -74,7 +69,7 @@ void should_be_invalid_for_different_string_value() {
@Test
void should_be_valid_for_same_number_value() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("const", Json.createValue(3.14159)).build())
+ new ConstKeyword(JsonProvider.provider(), Json.createValue(3.14159))
.asAssertion()
.isValidFor(Json.createValue(3.14159)),
is(true)
@@ -84,7 +79,7 @@ void should_be_valid_for_same_number_value() {
@Test
void should_be_invalid_for_value_with_different_type() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("const", Json.createValue(3.14159)).build())
+ new ConstKeyword(JsonProvider.provider(), Json.createValue(3.14159))
.asAssertion()
.isValidFor(Json.createValue("pi")),
is(false)
@@ -94,10 +89,9 @@ void should_be_invalid_for_value_with_different_type() {
@Test
void should_be_valid_for_exact_object_structure() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder()
- .add("const", Json.createObjectBuilder().add("name", "John Doe").add("age", 31))
- .build()
+ new ConstKeyword(
+ JsonProvider.provider(),
+ Json.createObjectBuilder().add("name", "John Doe").add("age", 31).build()
)
.asAssertion()
.isValidFor(Json.createObjectBuilder().add("name", "John Doe").add("age", 31).build()),
@@ -108,10 +102,9 @@ void should_be_valid_for_exact_object_structure() {
@Test
void should_be_invalid_for_not_exact_object_structure() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder()
- .add("const", Json.createObjectBuilder().add("name", "John Doe").add("age", 31))
- .build()
+ new ConstKeyword(
+ JsonProvider.provider(),
+ Json.createObjectBuilder().add("name", "John Doe").add("age", 31).build()
)
.asAssertion()
.isValidFor(Json.createObjectBuilder().add("name", "Robert").add("age", 31).build()),
@@ -122,7 +115,7 @@ void should_be_invalid_for_not_exact_object_structure() {
@Test
void should_be_valid_for_decimal_without_scale_if_number_is_valid() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("const", 1).build())
+ new ConstKeyword(JsonProvider.provider(), Json.createValue(1))
.asAssertion()
.isValidFor(Json.createValue(1.0)),
is(true)
@@ -132,16 +125,11 @@ void should_be_valid_for_decimal_without_scale_if_number_is_valid() {
@Test
void should_be_printable() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder().add("const", Json.createArrayBuilder().add("TEST").add("VALID")).build()
+ new ConstKeyword(
+ JsonProvider.provider(),
+ Json.createArrayBuilder().add("TEST").add("VALID").build()
).printOn(new HashMapMedia()),
(Matcher) hasEntry(is("const"), containsInAnyOrder("TEST", "VALID"))
);
}
-
- private static Keyword createKeywordFrom(final JsonObject json) {
- return new AnyKeywordType(JsonProvider.provider(), "const", ConstKeyword::new).createKeyword(
- new DefaultJsonSchemaFactory().create(json)
- );
- }
}
diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/DependentRequiredKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/DependentRequiredKeywordTest.java
index 00a0e529..0a361c80 100644
--- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/DependentRequiredKeywordTest.java
+++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/DependentRequiredKeywordTest.java
@@ -30,8 +30,6 @@
import static org.junit.jupiter.api.Assertions.assertThrows;
import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia;
-import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory;
-import io.github.sebastiantoepfer.jsonschema.core.keyword.type.ObjectKeywordType;
import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
import jakarta.json.Json;
import jakarta.json.JsonObject;
@@ -62,9 +60,7 @@ void should_not_be_createable_with_object_contains_only_non_string_array_propert
@Test
void should_know_his_name() {
- final Keyword enumKeyword = createKeywordFrom(
- Json.createObjectBuilder().add("dependentRequired", JsonValue.EMPTY_JSON_OBJECT).build()
- );
+ final Keyword enumKeyword = new DependentRequiredKeyword(JsonValue.EMPTY_JSON_OBJECT);
assertThat(enumKeyword.hasName("dependentRequired"), is(true));
assertThat(enumKeyword.hasName("test"), is(false));
@@ -73,13 +69,8 @@ void should_know_his_name() {
@Test
void should_be_valid_if_both_properties_available() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder()
- .add(
- "dependentRequired",
- Json.createObjectBuilder().add("license", Json.createArrayBuilder().add("age"))
- )
- .build()
+ new DependentRequiredKeyword(
+ Json.createObjectBuilder().add("license", Json.createArrayBuilder().add("age")).build()
)
.asAssertion()
.isValidFor(
@@ -92,13 +83,8 @@ void should_be_valid_if_both_properties_available() {
@Test
void should_be_valid_if_required_properties_is_missing() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder()
- .add(
- "dependentRequired",
- Json.createObjectBuilder().add("license", Json.createArrayBuilder().add("age"))
- )
- .build()
+ new DependentRequiredKeyword(
+ Json.createObjectBuilder().add("license", Json.createArrayBuilder().add("age")).build()
)
.asAssertion()
.isValidFor(Json.createObjectBuilder().add("name", "John").add("license", "XYZ123").build()),
@@ -109,13 +95,8 @@ void should_be_valid_if_required_properties_is_missing() {
@Test
void should_be_valid_if_both_properties_are_missing() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder()
- .add(
- "dependentRequired",
- Json.createObjectBuilder().add("license", Json.createArrayBuilder().add("age"))
- )
- .build()
+ new DependentRequiredKeyword(
+ Json.createObjectBuilder().add("license", Json.createArrayBuilder().add("age")).build()
)
.asAssertion()
.isValidFor(Json.createObjectBuilder().add("name", "John").build()),
@@ -126,21 +107,10 @@ void should_be_valid_if_both_properties_are_missing() {
@Test
void should_be_printable() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder()
- .add(
- "dependentRequired",
- Json.createObjectBuilder().add("license", Json.createArrayBuilder().add("age"))
- )
- .build()
+ new DependentRequiredKeyword(
+ Json.createObjectBuilder().add("license", Json.createArrayBuilder().add("age")).build()
).printOn(new HashMapMedia()),
(Matcher) hasEntry(is("dependentRequired"), hasEntry(is("license"), contains("age")))
);
}
-
- private static Keyword createKeywordFrom(final JsonObject json) {
- return new ObjectKeywordType("dependentRequired", DependentRequiredKeyword::new).createKeyword(
- new DefaultJsonSchemaFactory().create(json)
- );
- }
}
diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/EnumKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/EnumKeywordTest.java
index cb7c6890..440da115 100644
--- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/EnumKeywordTest.java
+++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/EnumKeywordTest.java
@@ -29,11 +29,8 @@
import static org.hamcrest.Matchers.is;
import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia;
-import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory;
-import io.github.sebastiantoepfer.jsonschema.core.keyword.type.ArrayKeywordType;
import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
import jakarta.json.Json;
-import jakarta.json.JsonObject;
import jakarta.json.JsonValue;
import org.hamcrest.Matcher;
import org.junit.jupiter.api.Test;
@@ -42,9 +39,7 @@ class EnumKeywordTest {
@Test
void should_know_his_name() {
- final Keyword enumKeyword = createKeywordFrom(
- Json.createObjectBuilder().add("enum", JsonValue.EMPTY_JSON_ARRAY).build()
- );
+ final Keyword enumKeyword = new EnumKeyword(JsonValue.EMPTY_JSON_ARRAY);
assertThat(enumKeyword.hasName("enum"), is(true));
assertThat(enumKeyword.hasName("test"), is(false));
@@ -53,9 +48,7 @@ void should_know_his_name() {
@Test
void should_valid_for_string_value_which_is_in_array() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder().add("enum", Json.createArrayBuilder().add("TEST").add("VALID")).build()
- )
+ new EnumKeyword(Json.createArrayBuilder().add("TEST").add("VALID").build())
.asAssertion()
.isValidFor(Json.createValue("TEST")),
is(true)
@@ -65,9 +58,7 @@ void should_valid_for_string_value_which_is_in_array() {
@Test
void should_be_invalid_for_number_which_is_not_in_array() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder().add("enum", Json.createArrayBuilder().add("TEST").add("VALID")).build()
- )
+ new EnumKeyword(Json.createArrayBuilder().add("TEST").add("VALID").build())
.asAssertion()
.isValidFor(Json.createValue(2)),
is(false)
@@ -77,9 +68,7 @@ void should_be_invalid_for_number_which_is_not_in_array() {
@Test
void should_be_valid_for_decimal_without_scale_if_number_is_valid() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("enum", Json.createArrayBuilder().add(1)).build())
- .asAssertion()
- .isValidFor(Json.createValue(1.0)),
+ new EnumKeyword(Json.createArrayBuilder().add(1).build()).asAssertion().isValidFor(Json.createValue(1.0)),
is(true)
);
}
@@ -87,16 +76,8 @@ void should_be_valid_for_decimal_without_scale_if_number_is_valid() {
@Test
void should_be_printable() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder().add("enum", Json.createArrayBuilder().add("TEST").add("VALID")).build()
- ).printOn(new HashMapMedia()),
+ new EnumKeyword(Json.createArrayBuilder().add("TEST").add("VALID").build()).printOn(new HashMapMedia()),
(Matcher) hasEntry(is("enum"), containsInAnyOrder("TEST", "VALID"))
);
}
-
- private static Keyword createKeywordFrom(final JsonObject json) {
- return new ArrayKeywordType("enum", EnumKeyword::new).createKeyword(
- new DefaultJsonSchemaFactory().create(json)
- );
- }
}
diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/ExclusiveMaximumKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/ExclusiveMaximumKeywordTest.java
index 9242c0a2..b1b51d47 100644
--- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/ExclusiveMaximumKeywordTest.java
+++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/ExclusiveMaximumKeywordTest.java
@@ -28,13 +28,9 @@
import static org.hamcrest.Matchers.is;
import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia;
-import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory;
-import io.github.sebastiantoepfer.jsonschema.core.keyword.type.NumberKeywordType;
import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
import jakarta.json.Json;
-import jakarta.json.JsonObject;
import jakarta.json.JsonValue;
-import jakarta.json.spi.JsonProvider;
import java.math.BigDecimal;
import org.hamcrest.Matcher;
import org.junit.jupiter.api.Test;
@@ -43,9 +39,7 @@ class ExclusiveMaximumKeywordTest {
@Test
void should_know_his_name() {
- final Keyword maximum = createKeywordFrom(
- Json.createObjectBuilder().add("exclusiveMaximum", Json.createValue(1)).build()
- );
+ final Keyword maximum = new ExclusiveMaximumKeyword(BigDecimal.valueOf(1));
assertThat(maximum.hasName("exclusiveMaximum"), is(true));
assertThat(maximum.hasName("test"), is(false));
@@ -54,9 +48,7 @@ void should_know_his_name() {
@Test
void should_be_valid_for_non_number_values() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("exclusiveMaximum", Json.createValue(1)).build())
- .asAssertion()
- .isValidFor(JsonValue.EMPTY_JSON_OBJECT),
+ new ExclusiveMaximumKeyword(BigDecimal.valueOf(1)).asAssertion().isValidFor(JsonValue.EMPTY_JSON_OBJECT),
is(true)
);
}
@@ -64,9 +56,7 @@ void should_be_valid_for_non_number_values() {
@Test
void should_be_invalid_for_greater_numbers() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("exclusiveMaximum", Json.createValue(10)).build())
- .asAssertion()
- .isValidFor(Json.createValue(11)),
+ new ExclusiveMaximumKeyword(BigDecimal.valueOf(10)).asAssertion().isValidFor(Json.createValue(11)),
is(false)
);
}
@@ -74,9 +64,7 @@ void should_be_invalid_for_greater_numbers() {
@Test
void should_be_invalid_for_equals_numbers() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("exclusiveMaximum", Json.createValue(10)).build())
- .asAssertion()
- .isValidFor(Json.createValue(10)),
+ new ExclusiveMaximumKeyword(BigDecimal.valueOf(10)).asAssertion().isValidFor(Json.createValue(10)),
is(false)
);
}
@@ -84,9 +72,7 @@ void should_be_invalid_for_equals_numbers() {
@Test
void shhould_be_valid_for_smaller_numbers() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("exclusiveMaximum", Json.createValue(10)).build())
- .asAssertion()
- .isValidFor(Json.createValue(9)),
+ new ExclusiveMaximumKeyword(BigDecimal.valueOf(10)).asAssertion().isValidFor(Json.createValue(9)),
is(true)
);
}
@@ -94,18 +80,8 @@ void shhould_be_valid_for_smaller_numbers() {
@Test
void should_be_printable() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("exclusiveMaximum", Json.createValue(10)).build()).printOn(
- new HashMapMedia()
- ),
+ new ExclusiveMaximumKeyword(BigDecimal.valueOf(10)).printOn(new HashMapMedia()),
(Matcher) hasEntry(is("exclusiveMaximum"), is(BigDecimal.valueOf(10)))
);
}
-
- private static Keyword createKeywordFrom(final JsonObject json) {
- return new NumberKeywordType(
- JsonProvider.provider(),
- "exclusiveMaximum",
- ExclusiveMaximumKeyword::new
- ).createKeyword(new DefaultJsonSchemaFactory().create(json));
- }
}
diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/ExclusiveMinimumKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/ExclusiveMinimumKeywordTest.java
index c6ca0db8..d19d4185 100644
--- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/ExclusiveMinimumKeywordTest.java
+++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/ExclusiveMinimumKeywordTest.java
@@ -28,13 +28,9 @@
import static org.hamcrest.Matchers.is;
import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia;
-import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory;
-import io.github.sebastiantoepfer.jsonschema.core.keyword.type.NumberKeywordType;
import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
import jakarta.json.Json;
-import jakarta.json.JsonObject;
import jakarta.json.JsonValue;
-import jakarta.json.spi.JsonProvider;
import java.math.BigDecimal;
import org.hamcrest.Matcher;
import org.junit.jupiter.api.Test;
@@ -43,9 +39,7 @@ class ExclusiveMinimumKeywordTest {
@Test
void should_know_his_name() {
- final Keyword minimum = createKeywordFrom(
- Json.createObjectBuilder().add("exclusiveMinimum", Json.createValue(1)).build()
- );
+ final Keyword minimum = new ExclusiveMinimumKeyword(BigDecimal.valueOf(1));
assertThat(minimum.hasName("exclusiveMinimum"), is(true));
assertThat(minimum.hasName("test"), is(false));
@@ -54,9 +48,7 @@ void should_know_his_name() {
@Test
void should_be_valid_for_non_number_values() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("exclusiveMinimum", Json.createValue(1)).build())
- .asAssertion()
- .isValidFor(JsonValue.EMPTY_JSON_OBJECT),
+ new ExclusiveMinimumKeyword(BigDecimal.valueOf(1)).asAssertion().isValidFor(JsonValue.EMPTY_JSON_OBJECT),
is(true)
);
}
@@ -64,9 +56,7 @@ void should_be_valid_for_non_number_values() {
@Test
void should_be_invalid_for_smaller_numbers() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("exclusiveMinimum", Json.createValue(0)).build())
- .asAssertion()
- .isValidFor(Json.createValue(-1)),
+ new ExclusiveMinimumKeyword(BigDecimal.valueOf(0)).asAssertion().isValidFor(Json.createValue(-1)),
is(false)
);
}
@@ -74,9 +64,7 @@ void should_be_invalid_for_smaller_numbers() {
@Test
void should_be_invalid_for_equals_numbers() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("exclusiveMinimum", Json.createValue(0)).build())
- .asAssertion()
- .isValidFor(Json.createValue(0)),
+ new ExclusiveMinimumKeyword(BigDecimal.valueOf(0)).asAssertion().isValidFor(Json.createValue(0)),
is(false)
);
}
@@ -84,9 +72,7 @@ void should_be_invalid_for_equals_numbers() {
@Test
void shhould_be_valid_for_greater_numbers() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("exclusiveMinimum", Json.createValue(0)).build())
- .asAssertion()
- .isValidFor(Json.createValue(1)),
+ new ExclusiveMinimumKeyword(BigDecimal.valueOf(0)).asAssertion().isValidFor(Json.createValue(1)),
is(true)
);
}
@@ -94,18 +80,8 @@ void shhould_be_valid_for_greater_numbers() {
@Test
void should_be_printable() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("exclusiveMinimum", Json.createValue(0)).build()).printOn(
- new HashMapMedia()
- ),
+ new ExclusiveMinimumKeyword(BigDecimal.valueOf(0)).printOn(new HashMapMedia()),
(Matcher) hasEntry(is("exclusiveMinimum"), is(BigDecimal.valueOf(0)))
);
}
-
- private static Keyword createKeywordFrom(final JsonObject json) {
- return new NumberKeywordType(
- JsonProvider.provider(),
- "exclusiveMinimum",
- ExclusiveMinimumKeyword::new
- ).createKeyword(new DefaultJsonSchemaFactory().create(json));
- }
}
diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MaxContainsKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MaxContainsKeywordTest.java
index 2b7a3861..4b1c889b 100644
--- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MaxContainsKeywordTest.java
+++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MaxContainsKeywordTest.java
@@ -28,16 +28,12 @@
import static org.hamcrest.Matchers.is;
import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia;
-import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory;
-import io.github.sebastiantoepfer.jsonschema.core.keyword.type.AffectsKeywordType;
-import io.github.sebastiantoepfer.jsonschema.core.keyword.type.IntegerKeywordType;
import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
import io.github.sebastiantoepfer.jsonschema.keyword.StaticAnnotation;
import jakarta.json.Json;
-import jakarta.json.JsonObject;
import jakarta.json.JsonValue;
-import jakarta.json.spi.JsonProvider;
import java.math.BigInteger;
+import java.util.List;
import org.hamcrest.Matcher;
import org.junit.jupiter.api.Test;
@@ -45,7 +41,7 @@ class MaxContainsKeywordTest {
@Test
void should_know_his_name() {
- final Keyword enumKeyword = new MaxContainsKeyword(new StaticAnnotation("", JsonValue.NULL), BigInteger.ONE);
+ final Keyword enumKeyword = new MaxContainsKeyword(List.of(), BigInteger.ONE);
assertThat(enumKeyword.hasName("maxContains"), is(true));
assertThat(enumKeyword.hasName("test"), is(false));
}
@@ -53,7 +49,7 @@ void should_know_his_name() {
@Test
void should_be_printable() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("maxContains", 2).build()).printOn(new HashMapMedia()),
+ new MaxContainsKeyword(List.of(), BigInteger.valueOf(2)).printOn(new HashMapMedia()),
(Matcher) hasEntry(is("maxContains"), is(BigInteger.valueOf(2)))
);
}
@@ -61,31 +57,19 @@ void should_be_printable() {
@Test
void should_be_valid_for_non_arrays() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("maxContains", 2).build())
+ new MaxContainsKeyword(List.of(), BigInteger.valueOf(2))
.asAssertion()
.isValidFor(JsonValue.EMPTY_JSON_OBJECT),
is(true)
);
}
- @Test
- void should_be_valid_if_no_contains_is_present() {
- assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("maxContains", 2).build())
- .asAssertion()
- .isValidFor(Json.createArrayBuilder().add("foo").build()),
- is(true)
- );
- }
-
@Test
void should_be_valid_if_contains_applies_to_exact_count() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder()
- .add("contains", Json.createObjectBuilder().add("type", "string"))
- .add("maxContains", 2)
- .build()
+ new MaxContainsKeyword(
+ List.of(new StaticAnnotation("contains", Json.createArrayBuilder().add(0).add(1).build())),
+ BigInteger.valueOf(2)
)
.asAssertion()
.isValidFor(Json.createArrayBuilder().add("foo").add("bar").add(1).build()),
@@ -96,11 +80,9 @@ void should_be_valid_if_contains_applies_to_exact_count() {
@Test
void should_be_valid_if_contains_applies_to_less_items() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder()
- .add("contains", Json.createObjectBuilder().add("type", "string"))
- .add("maxContains", 2)
- .build()
+ new MaxContainsKeyword(
+ List.of(new StaticAnnotation("contains", Json.createArrayBuilder().add(0).build())),
+ BigInteger.valueOf(2)
)
.asAssertion()
.isValidFor(Json.createArrayBuilder().add("foo").add(2).add(3).build()),
@@ -111,11 +93,9 @@ void should_be_valid_if_contains_applies_to_less_items() {
@Test
void should_be_valid_for_empty_arrays() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder()
- .add("contains", Json.createObjectBuilder().add("type", "string"))
- .add("maxContains", 2)
- .build()
+ new MaxContainsKeyword(
+ List.of(new StaticAnnotation("contains", JsonValue.EMPTY_JSON_ARRAY)),
+ BigInteger.valueOf(2)
)
.asAssertion()
.isValidFor(JsonValue.EMPTY_JSON_ARRAY),
@@ -126,11 +106,9 @@ void should_be_valid_for_empty_arrays() {
@Test
void should_be_invalid_if_contains_applies_to_more_items() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder()
- .add("contains", Json.createObjectBuilder().add("type", "string"))
- .add("maxContains", 2)
- .build()
+ new MaxContainsKeyword(
+ List.of(new StaticAnnotation("contains", Json.createArrayBuilder().add(0).add(1).add(3).build())),
+ BigInteger.valueOf(2)
)
.asAssertion()
.isValidFor(Json.createArrayBuilder().add("foo").add("bar").add(1).add("baz").build()),
@@ -141,12 +119,7 @@ void should_be_invalid_if_contains_applies_to_more_items() {
@Test
void should_be_valid_if_contains_applies_to_all_and_less_items_in_array() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder()
- .add("contains", Json.createObjectBuilder().add("type", "string"))
- .add("maxContains", 2)
- .build()
- )
+ new MaxContainsKeyword(List.of(new StaticAnnotation("contains", JsonValue.TRUE)), BigInteger.valueOf(2))
.asAssertion()
.isValidFor(Json.createArrayBuilder().add("foo").build()),
is(true)
@@ -156,12 +129,7 @@ void should_be_valid_if_contains_applies_to_all_and_less_items_in_array() {
@Test
void should_be_valid_if_contains_applies_to_all_and_exact_items_count_in_array() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder()
- .add("contains", Json.createObjectBuilder().add("type", "string"))
- .add("maxContains", 2)
- .build()
- )
+ new MaxContainsKeyword(List.of(new StaticAnnotation("contains", JsonValue.TRUE)), BigInteger.valueOf(2))
.asAssertion()
.isValidFor(Json.createArrayBuilder().add("foo").add("bar").build()),
is(true)
@@ -171,28 +139,10 @@ void should_be_valid_if_contains_applies_to_all_and_exact_items_count_in_array()
@Test
void should_be_invalid_if_contains_applies_to_all_and_more_items_in_array() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder()
- .add("contains", Json.createObjectBuilder().add("type", "string"))
- .add("maxContains", 2)
- .build()
- )
+ new MaxContainsKeyword(List.of(new StaticAnnotation("contains", JsonValue.TRUE)), BigInteger.valueOf(2))
.asAssertion()
.isValidFor(Json.createArrayBuilder().add("foo").add("bar").add("baz").build()),
is(false)
);
}
-
- private static Keyword createKeywordFrom(final JsonObject json) {
- return new AffectsKeywordType(
- "maxContains",
- "contains",
- (a, s) ->
- new IntegerKeywordType(
- JsonProvider.provider(),
- "maxContains",
- value -> new MaxContainsKeyword(a, value)
- ).createKeyword(s)
- ).createKeyword(new DefaultJsonSchemaFactory().create(json));
- }
}
diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MaxItemsKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MaxItemsKeywordTest.java
index 182a3360..de931481 100644
--- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MaxItemsKeywordTest.java
+++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MaxItemsKeywordTest.java
@@ -28,13 +28,9 @@
import static org.hamcrest.Matchers.is;
import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia;
-import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory;
-import io.github.sebastiantoepfer.jsonschema.core.keyword.type.IntegerKeywordType;
import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
import jakarta.json.Json;
-import jakarta.json.JsonObject;
import jakarta.json.JsonValue;
-import jakarta.json.spi.JsonProvider;
import java.math.BigInteger;
import org.hamcrest.Matcher;
import org.junit.jupiter.api.Test;
@@ -43,9 +39,7 @@ class MaxItemsKeywordTest {
@Test
void should_know_his_name() {
- final Keyword keyword = createKeywordFrom(
- Json.createObjectBuilder().add("maxItems", Json.createValue(1)).build()
- );
+ final Keyword keyword = new MaxItemsKeyword(BigInteger.valueOf(1));
assertThat(keyword.hasName("maxItems"), is(true));
assertThat(keyword.hasName("test"), is(false));
@@ -54,9 +48,7 @@ void should_know_his_name() {
@Test
void should_be_valid_for_non_arrays() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("maxItems", Json.createValue(2)).build())
- .asAssertion()
- .isValidFor(JsonValue.EMPTY_JSON_OBJECT),
+ new MaxItemsKeyword(BigInteger.valueOf(2)).asAssertion().isValidFor(JsonValue.EMPTY_JSON_OBJECT),
is(true)
);
}
@@ -64,7 +56,7 @@ void should_be_valid_for_non_arrays() {
@Test
void should_be_valid_for_array_with_same_size() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("maxItems", Json.createValue(2)).build())
+ new MaxItemsKeyword(BigInteger.valueOf(2))
.asAssertion()
.isValidFor(Json.createArrayBuilder().add(1).add(2).build()),
is(true)
@@ -74,7 +66,7 @@ void should_be_valid_for_array_with_same_size() {
@Test
void should_be_valid_for_array_with_smaller_size() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("maxItems", Json.createValue(2)).build())
+ new MaxItemsKeyword(BigInteger.valueOf(2))
.asAssertion()
.isValidFor(Json.createArrayBuilder().add(1).build()),
is(true)
@@ -84,7 +76,7 @@ void should_be_valid_for_array_with_smaller_size() {
@Test
void should_be_invalid_for_array_with_greather_size() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("maxItems", Json.createValue(2)).build())
+ new MaxItemsKeyword(BigInteger.valueOf(2))
.asAssertion()
.isValidFor(Json.createArrayBuilder().add(1).add(2).add(3).build()),
is(false)
@@ -94,16 +86,8 @@ void should_be_invalid_for_array_with_greather_size() {
@Test
void should_be_printable() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("maxItems", Json.createValue(2)).build()).printOn(
- new HashMapMedia()
- ),
+ new MaxItemsKeyword(BigInteger.valueOf(2)).printOn(new HashMapMedia()),
(Matcher) hasEntry(is("maxItems"), is(BigInteger.valueOf(2)))
);
}
-
- private static Keyword createKeywordFrom(final JsonObject json) {
- return new IntegerKeywordType(JsonProvider.provider(), "maxItems", MaxItemsKeyword::new).createKeyword(
- new DefaultJsonSchemaFactory().create(json)
- );
- }
}
diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MaxLengthKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MaxLengthKeywordTest.java
index 886a2ef8..b995e9bb 100644
--- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MaxLengthKeywordTest.java
+++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MaxLengthKeywordTest.java
@@ -28,13 +28,9 @@
import static org.hamcrest.Matchers.is;
import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia;
-import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory;
-import io.github.sebastiantoepfer.jsonschema.core.keyword.type.IntegerKeywordType;
import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
import jakarta.json.Json;
-import jakarta.json.JsonObject;
import jakarta.json.JsonValue;
-import jakarta.json.spi.JsonProvider;
import java.math.BigInteger;
import org.hamcrest.Matcher;
import org.junit.jupiter.api.Test;
@@ -43,7 +39,7 @@ class MaxLengthKeywordTest {
@Test
void should_know_his_name() {
- final Keyword keyword = createKeywordFrom(Json.createObjectBuilder().add("maxLength", 1).build());
+ final Keyword keyword = new MaxLengthKeyword(BigInteger.valueOf(1));
assertThat(keyword.hasName("test"), is(false));
assertThat(keyword.hasName("maxLength"), is(true));
@@ -52,9 +48,7 @@ void should_know_his_name() {
@Test
void should_be_valid_for_non_string_values() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("maxLength", Json.createValue(2)).build())
- .asAssertion()
- .isValidFor(JsonValue.EMPTY_JSON_ARRAY),
+ new MaxLengthKeyword(BigInteger.valueOf(2)).asAssertion().isValidFor(JsonValue.EMPTY_JSON_ARRAY),
is(true)
);
}
@@ -62,9 +56,7 @@ void should_be_valid_for_non_string_values() {
@Test
void should_be_invalid_for_longer_string() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("maxLength", Json.createValue(2)).build())
- .asAssertion()
- .isValidFor(Json.createValue("1234")),
+ new MaxLengthKeyword(BigInteger.valueOf(2)).asAssertion().isValidFor(Json.createValue("1234")),
is(false)
);
}
@@ -72,9 +64,7 @@ void should_be_invalid_for_longer_string() {
@Test
void should_be_valid_for_string_with_length_is_equal() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("maxLength", Json.createValue(2)).build())
- .asAssertion()
- .isValidFor(Json.createValue("12")),
+ new MaxLengthKeyword(BigInteger.valueOf(2)).asAssertion().isValidFor(Json.createValue("12")),
is(true)
);
}
@@ -82,9 +72,7 @@ void should_be_valid_for_string_with_length_is_equal() {
@Test
void should_ne_valid_for_string_with_is_shorter() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("maxLength", Json.createValue(2)).build())
- .asAssertion()
- .isValidFor(Json.createValue("1")),
+ new MaxLengthKeyword(BigInteger.valueOf(2)).asAssertion().isValidFor(Json.createValue("1")),
is(true)
);
}
@@ -92,16 +80,8 @@ void should_ne_valid_for_string_with_is_shorter() {
@Test
void should_be_printable() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("maxLength", Json.createValue(2)).build()).printOn(
- new HashMapMedia()
- ),
+ new MaxLengthKeyword(BigInteger.valueOf(2)).printOn(new HashMapMedia()),
(Matcher) hasEntry(is("maxLength"), is(BigInteger.valueOf(2L)))
);
}
-
- private static Keyword createKeywordFrom(final JsonObject json) {
- return new IntegerKeywordType(JsonProvider.provider(), "maxLength", MaxLengthKeyword::new).createKeyword(
- new DefaultJsonSchemaFactory().create(json)
- );
- }
}
diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MaxPropertiesKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MaxPropertiesKeywordTest.java
index b82c2400..aad33a35 100644
--- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MaxPropertiesKeywordTest.java
+++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MaxPropertiesKeywordTest.java
@@ -28,13 +28,9 @@
import static org.hamcrest.Matchers.is;
import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia;
-import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory;
-import io.github.sebastiantoepfer.jsonschema.core.keyword.type.IntegerKeywordType;
import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
import jakarta.json.Json;
-import jakarta.json.JsonObject;
import jakarta.json.JsonValue;
-import jakarta.json.spi.JsonProvider;
import java.math.BigInteger;
import org.hamcrest.Matcher;
import org.junit.jupiter.api.Test;
@@ -43,7 +39,7 @@ class MaxPropertiesKeywordTest {
@Test
void should_know_his_name() {
- final Keyword enumKeyword = createKeywordFrom(Json.createObjectBuilder().add("maxProperties", 2).build());
+ final Keyword enumKeyword = new MaxPropertiesKeyword(BigInteger.valueOf(2));
assertThat(enumKeyword.hasName("maxProperties"), is(true));
assertThat(enumKeyword.hasName("test"), is(false));
@@ -52,7 +48,7 @@ void should_know_his_name() {
@Test
void should_be_printable() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("maxProperties", 2).build()).printOn(new HashMapMedia()),
+ new MaxPropertiesKeyword(BigInteger.valueOf(2)).printOn(new HashMapMedia()),
(Matcher) hasEntry(is("maxProperties"), is(BigInteger.valueOf(2)))
);
}
@@ -60,9 +56,7 @@ void should_be_printable() {
@Test
void should_be_valid_for_non_objects() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("maxProperties", 2).build())
- .asAssertion()
- .isValidFor(JsonValue.EMPTY_JSON_ARRAY),
+ new MaxPropertiesKeyword(BigInteger.valueOf(2)).asAssertion().isValidFor(JsonValue.EMPTY_JSON_ARRAY),
is(true)
);
}
@@ -70,7 +64,7 @@ void should_be_valid_for_non_objects() {
@Test
void should_be_valid_for_less_properties() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("maxProperties", 2).build())
+ new MaxPropertiesKeyword(BigInteger.valueOf(2))
.asAssertion()
.isValidFor(Json.createObjectBuilder().add("foo", 3).build()),
is(true)
@@ -80,7 +74,7 @@ void should_be_valid_for_less_properties() {
@Test
void should_be_valid_exact_properties_count() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("maxProperties", 2).build())
+ new MaxPropertiesKeyword(BigInteger.valueOf(2))
.asAssertion()
.isValidFor(Json.createObjectBuilder().add("foo", 3).add("bar", "hi").build()),
is(true)
@@ -90,18 +84,10 @@ void should_be_valid_exact_properties_count() {
@Test
void should_be_invalid_for_more_properties() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("maxProperties", 2).build())
+ new MaxPropertiesKeyword(BigInteger.valueOf(2))
.asAssertion()
.isValidFor(Json.createObjectBuilder().add("foo", 3).add("bar", "hi").add("baz", true).build()),
is(false)
);
}
-
- private static Keyword createKeywordFrom(final JsonObject json) {
- return new IntegerKeywordType(
- JsonProvider.provider(),
- "maxProperties",
- MaxPropertiesKeyword::new
- ).createKeyword(new DefaultJsonSchemaFactory().create(json));
- }
}
diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MaximumKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MaximumKeywordTest.java
index 10bbd699..9e57fc3f 100644
--- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MaximumKeywordTest.java
+++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MaximumKeywordTest.java
@@ -28,13 +28,9 @@
import static org.hamcrest.Matchers.is;
import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia;
-import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory;
-import io.github.sebastiantoepfer.jsonschema.core.keyword.type.NumberKeywordType;
import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
import jakarta.json.Json;
-import jakarta.json.JsonObject;
import jakarta.json.JsonValue;
-import jakarta.json.spi.JsonProvider;
import java.math.BigDecimal;
import org.hamcrest.Matcher;
import org.junit.jupiter.api.Test;
@@ -43,9 +39,7 @@ class MaximumKeywordTest {
@Test
void should_know_his_name() {
- final Keyword maximum = createKeywordFrom(
- Json.createObjectBuilder().add("maximum", Json.createValue(1)).build()
- );
+ final Keyword maximum = new MaximumKeyword(BigDecimal.valueOf(1));
assertThat(maximum.hasName("maximum"), is(true));
assertThat(maximum.hasName("test"), is(false));
@@ -54,9 +48,7 @@ void should_know_his_name() {
@Test
void should_be_valid_for_non_number_values() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("maximum", Json.createValue(1)).build())
- .asAssertion()
- .isValidFor(JsonValue.EMPTY_JSON_OBJECT),
+ new MaximumKeyword(BigDecimal.valueOf(1)).asAssertion().isValidFor(JsonValue.EMPTY_JSON_OBJECT),
is(true)
);
}
@@ -64,46 +56,26 @@ void should_be_valid_for_non_number_values() {
@Test
void should_be_invalid_for_greater_numbers() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("maximum", Json.createValue(10)).build())
- .asAssertion()
- .isValidFor(Json.createValue(11)),
+ new MaximumKeyword(BigDecimal.valueOf(10)).asAssertion().isValidFor(Json.createValue(11)),
is(false)
);
}
@Test
void should_be_valid_for_equals_numbers() {
- assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("maximum", Json.createValue(10)).build())
- .asAssertion()
- .isValidFor(Json.createValue(10)),
- is(true)
- );
+ assertThat(new MaximumKeyword(BigDecimal.valueOf(10)).asAssertion().isValidFor(Json.createValue(10)), is(true));
}
@Test
void shhould_be_valid_for_smaller_numbers() {
- assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("maximum", Json.createValue(10)).build())
- .asAssertion()
- .isValidFor(Json.createValue(9)),
- is(true)
- );
+ assertThat(new MaximumKeyword(BigDecimal.valueOf(10)).asAssertion().isValidFor(Json.createValue(9)), is(true));
}
@Test
void should_be_printable() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("maximum", Json.createValue(10)).build()).printOn(
- new HashMapMedia()
- ),
+ new MaximumKeyword(BigDecimal.valueOf(10)).printOn(new HashMapMedia()),
(Matcher) hasEntry(is("maximum"), is(BigDecimal.valueOf(10)))
);
}
-
- private static Keyword createKeywordFrom(final JsonObject json) {
- return new NumberKeywordType(JsonProvider.provider(), "maximum", MaximumKeyword::new).createKeyword(
- new DefaultJsonSchemaFactory().create(json)
- );
- }
}
diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MinContainsKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MinContainsKeywordTest.java
index 682bcab6..aaf6f2e0 100644
--- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MinContainsKeywordTest.java
+++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MinContainsKeywordTest.java
@@ -28,16 +28,12 @@
import static org.hamcrest.Matchers.is;
import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia;
-import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory;
-import io.github.sebastiantoepfer.jsonschema.core.keyword.type.AffectsKeywordType;
-import io.github.sebastiantoepfer.jsonschema.core.keyword.type.IntegerKeywordType;
import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
import io.github.sebastiantoepfer.jsonschema.keyword.StaticAnnotation;
import jakarta.json.Json;
-import jakarta.json.JsonObject;
import jakarta.json.JsonValue;
-import jakarta.json.spi.JsonProvider;
import java.math.BigInteger;
+import java.util.List;
import org.hamcrest.Matcher;
import org.junit.jupiter.api.Test;
@@ -45,7 +41,7 @@ class MinContainsKeywordTest {
@Test
void should_know_his_name() {
- final Keyword enumKeyword = new MinContainsKeyword(new StaticAnnotation("", JsonValue.NULL), BigInteger.ONE);
+ final Keyword enumKeyword = new MinContainsKeyword(List.of(), BigInteger.ONE);
assertThat(enumKeyword.hasName("minContains"), is(true));
assertThat(enumKeyword.hasName("test"), is(false));
@@ -54,7 +50,7 @@ void should_know_his_name() {
@Test
void should_be_printable() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("minContains", 2).build()).printOn(new HashMapMedia()),
+ new MinContainsKeyword(List.of(), BigInteger.valueOf(2)).printOn(new HashMapMedia()),
(Matcher) hasEntry(is("minContains"), is(BigInteger.valueOf(2)))
);
}
@@ -62,31 +58,19 @@ void should_be_printable() {
@Test
void should_be_valid_for_non_arrays() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("minContains", 2).build())
+ new MinContainsKeyword(List.of(), BigInteger.valueOf(2))
.asAssertion()
.isValidFor(JsonValue.EMPTY_JSON_OBJECT),
is(true)
);
}
- @Test
- void should_be_valid_if_no_contains_is_present() {
- assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("minContains", 2).build())
- .asAssertion()
- .isValidFor(Json.createArrayBuilder().add("foo").build()),
- is(true)
- );
- }
-
@Test
void should_be_valid_if_contains_applies_to_exact_count() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder()
- .add("contains", Json.createObjectBuilder().add("type", "string"))
- .add("minContains", 2)
- .build()
+ new MinContainsKeyword(
+ List.of(new StaticAnnotation("contains", Json.createArrayBuilder().add(0).add(1).build())),
+ BigInteger.valueOf(2)
)
.asAssertion()
.isValidFor(Json.createArrayBuilder().add("foo").add("bar").add(1).build()),
@@ -97,11 +81,9 @@ void should_be_valid_if_contains_applies_to_exact_count() {
@Test
void should_be_valid_if_contains_applies_to_more_items() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder()
- .add("contains", Json.createObjectBuilder().add("type", "string"))
- .add("minContains", 2)
- .build()
+ new MinContainsKeyword(
+ List.of(new StaticAnnotation("contains", Json.createArrayBuilder().add(0).add(3).add(4).build())),
+ BigInteger.valueOf(2)
)
.asAssertion()
.isValidFor(Json.createArrayBuilder().add("foo").add(2).add(3).add("bar").add("baz").build()),
@@ -112,11 +94,9 @@ void should_be_valid_if_contains_applies_to_more_items() {
@Test
void should_be_valid_for_empty_arrays() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder()
- .add("contains", Json.createObjectBuilder().add("const", 1))
- .add("minContains", 0)
- .build()
+ new MinContainsKeyword(
+ List.of(new StaticAnnotation("contains", Json.createArrayBuilder().build())),
+ BigInteger.valueOf(0)
)
.asAssertion()
.isValidFor(JsonValue.EMPTY_JSON_ARRAY),
@@ -127,11 +107,9 @@ void should_be_valid_for_empty_arrays() {
@Test
void should_be_invalid_if_contains_applies_to_less_items() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder()
- .add("contains", Json.createObjectBuilder().add("type", "string"))
- .add("minContains", 2)
- .build()
+ new MinContainsKeyword(
+ List.of(new StaticAnnotation("contains", Json.createArrayBuilder().add(0).build())),
+ BigInteger.valueOf(2)
)
.asAssertion()
.isValidFor(Json.createArrayBuilder().add("foo").add(1).build()),
@@ -142,12 +120,7 @@ void should_be_invalid_if_contains_applies_to_less_items() {
@Test
void should_be_valid_if_contains_applies_to_all_and_more_items_in_array() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder()
- .add("contains", Json.createObjectBuilder().add("type", "string"))
- .add("minContains", 2)
- .build()
- )
+ new MinContainsKeyword(List.of(new StaticAnnotation("contains", JsonValue.TRUE)), BigInteger.valueOf(2))
.asAssertion()
.isValidFor(Json.createArrayBuilder().add("foo").add("bar").add("baz").build()),
is(true)
@@ -157,12 +130,7 @@ void should_be_valid_if_contains_applies_to_all_and_more_items_in_array() {
@Test
void should_be_valid_if_contains_applies_to_all_and_exact_items_count_in_array() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder()
- .add("contains", Json.createObjectBuilder().add("type", "string"))
- .add("minContains", 2)
- .build()
- )
+ new MinContainsKeyword(List.of(new StaticAnnotation("contains", JsonValue.TRUE)), BigInteger.valueOf(2))
.asAssertion()
.isValidFor(Json.createArrayBuilder().add("foo").add("bar").build()),
is(true)
@@ -172,28 +140,10 @@ void should_be_valid_if_contains_applies_to_all_and_exact_items_count_in_array()
@Test
void should_be_invalid_if_contains_applies_to_all_and_less_items_in_array() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder()
- .add("contains", Json.createObjectBuilder().add("type", "string"))
- .add("minContains", 2)
- .build()
- )
+ new MinContainsKeyword(List.of(new StaticAnnotation("contains", JsonValue.TRUE)), BigInteger.valueOf(2))
.asAssertion()
.isValidFor(Json.createArrayBuilder().add("foo").build()),
is(false)
);
}
-
- private static Keyword createKeywordFrom(final JsonObject json) {
- return new AffectsKeywordType(
- "minContains",
- "contains",
- (a, s) ->
- new IntegerKeywordType(
- JsonProvider.provider(),
- "minContains",
- value -> new MinContainsKeyword(a, value)
- ).createKeyword(s)
- ).createKeyword(new DefaultJsonSchemaFactory().create(json));
- }
}
diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MinItemsKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MinItemsKeywordTest.java
index 1af26aa0..e25711f8 100644
--- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MinItemsKeywordTest.java
+++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MinItemsKeywordTest.java
@@ -28,13 +28,9 @@
import static org.hamcrest.Matchers.is;
import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia;
-import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory;
-import io.github.sebastiantoepfer.jsonschema.core.keyword.type.IntegerKeywordType;
import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
import jakarta.json.Json;
-import jakarta.json.JsonObject;
import jakarta.json.JsonValue;
-import jakarta.json.spi.JsonProvider;
import java.math.BigInteger;
import org.hamcrest.Matcher;
import org.junit.jupiter.api.Test;
@@ -43,9 +39,7 @@ class MinItemsKeywordTest {
@Test
void should_be_know_his_name() {
- final Keyword minItems = createKeywordFrom(
- Json.createObjectBuilder().add("minItems", Json.createValue(1)).build()
- );
+ final Keyword minItems = new MinItemsKeyword(BigInteger.valueOf(1));
assertThat(minItems.hasName("minItems"), is(true));
assertThat(minItems.hasName("test"), is(false));
@@ -54,9 +48,7 @@ void should_be_know_his_name() {
@Test
void should_be_valid_for_non_arrays() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("minItems", Json.createValue(1)).build())
- .asAssertion()
- .isValidFor(JsonValue.EMPTY_JSON_OBJECT),
+ new MinItemsKeyword(BigInteger.valueOf(1)).asAssertion().isValidFor(JsonValue.EMPTY_JSON_OBJECT),
is(true)
);
}
@@ -64,7 +56,7 @@ void should_be_valid_for_non_arrays() {
@Test
void should_be_valid_for_arrays_with_equals_size() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("minItems", Json.createValue(1)).build())
+ new MinItemsKeyword(BigInteger.valueOf(1))
.asAssertion()
.isValidFor(Json.createArrayBuilder().add(1).build()),
is(true)
@@ -74,7 +66,7 @@ void should_be_valid_for_arrays_with_equals_size() {
@Test
void should_be_valid_for_arrays_with_greater_size() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("minItems", Json.createValue(1)).build())
+ new MinItemsKeyword(BigInteger.valueOf(1))
.asAssertion()
.isValidFor(Json.createArrayBuilder().add(1).add(2).build()),
is(true)
@@ -84,9 +76,7 @@ void should_be_valid_for_arrays_with_greater_size() {
@Test
void should_be_invalid_for_arrays_with_smaller_size() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("minItems", Json.createValue(1)).build())
- .asAssertion()
- .isValidFor(Json.createArrayBuilder().build()),
+ new MinItemsKeyword(BigInteger.valueOf(1)).asAssertion().isValidFor(Json.createArrayBuilder().build()),
is(false)
);
}
@@ -94,16 +84,8 @@ void should_be_invalid_for_arrays_with_smaller_size() {
@Test
void should_be_printable() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("minItems", Json.createValue(1)).build()).printOn(
- new HashMapMedia()
- ),
+ new MinItemsKeyword(BigInteger.valueOf(1)).printOn(new HashMapMedia()),
(Matcher) hasEntry(is("minItems"), is(BigInteger.valueOf(1)))
);
}
-
- private static Keyword createKeywordFrom(final JsonObject json) {
- return new IntegerKeywordType(JsonProvider.provider(), "minItems", MinItemsKeyword::new).createKeyword(
- new DefaultJsonSchemaFactory().create(json)
- );
- }
}
diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MinLengthKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MinLengthKeywordTest.java
index 798ca931..d5b21c30 100644
--- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MinLengthKeywordTest.java
+++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MinLengthKeywordTest.java
@@ -28,13 +28,9 @@
import static org.hamcrest.Matchers.is;
import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia;
-import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory;
-import io.github.sebastiantoepfer.jsonschema.core.keyword.type.IntegerKeywordType;
import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
import jakarta.json.Json;
-import jakarta.json.JsonObject;
import jakarta.json.JsonValue;
-import jakarta.json.spi.JsonProvider;
import java.math.BigInteger;
import org.hamcrest.Matcher;
import org.junit.jupiter.api.Test;
@@ -43,9 +39,7 @@ class MinLengthKeywordTest {
@Test
void should_know_his_name() {
- final Keyword keyword = createKeywordFrom(
- Json.createObjectBuilder().add("minLength", Json.createValue(1)).build()
- );
+ final Keyword keyword = new MinLengthKeyword(BigInteger.valueOf(1));
assertThat(keyword.hasName("test"), is(false));
assertThat(keyword.hasName("minLength"), is(true));
@@ -54,9 +48,7 @@ void should_know_his_name() {
@Test
void should_be_invalid_with_shorter_string() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("minLength", Json.createValue(2)).build())
- .asAssertion()
- .isValidFor(Json.createValue("A")),
+ new MinLengthKeyword(BigInteger.valueOf(2)).asAssertion().isValidFor(Json.createValue("A")),
is(false)
);
}
@@ -64,9 +56,7 @@ void should_be_invalid_with_shorter_string() {
@Test
void should_be_valid_with_string_with_equal_length() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("minLength", Json.createValue(2)).build())
- .asAssertion()
- .isValidFor(Json.createValue("AB")),
+ new MinLengthKeyword(BigInteger.valueOf(2)).asAssertion().isValidFor(Json.createValue("AB")),
is(true)
);
}
@@ -74,9 +64,7 @@ void should_be_valid_with_string_with_equal_length() {
@Test
void should_be_valid_with_string_that_is_longer() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("minLength", Json.createValue(2)).build())
- .asAssertion()
- .isValidFor(Json.createValue("ABC")),
+ new MinLengthKeyword(BigInteger.valueOf(2)).asAssertion().isValidFor(Json.createValue("ABC")),
is(true)
);
}
@@ -84,9 +72,7 @@ void should_be_valid_with_string_that_is_longer() {
@Test
void should_be_valid_for_non_string_values() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("minLength", Json.createValue(2)).build())
- .asAssertion()
- .isValidFor(JsonValue.EMPTY_JSON_ARRAY),
+ new MinLengthKeyword(BigInteger.valueOf(2)).asAssertion().isValidFor(JsonValue.EMPTY_JSON_ARRAY),
is(true)
);
}
@@ -94,16 +80,8 @@ void should_be_valid_for_non_string_values() {
@Test
void should_be_printable() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("minLength", Json.createValue(2)).build()).printOn(
- new HashMapMedia()
- ),
+ new MinLengthKeyword(BigInteger.valueOf(2)).printOn(new HashMapMedia()),
(Matcher) hasEntry(is("minLength"), is(BigInteger.valueOf(2L)))
);
}
-
- private static Keyword createKeywordFrom(final JsonObject json) {
- return new IntegerKeywordType(JsonProvider.provider(), "minLength", MinLengthKeyword::new).createKeyword(
- new DefaultJsonSchemaFactory().create(json)
- );
- }
}
diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MinPropertiesKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MinPropertiesKeywordTest.java
index 9f7597af..1af6fa00 100644
--- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MinPropertiesKeywordTest.java
+++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MinPropertiesKeywordTest.java
@@ -28,13 +28,9 @@
import static org.hamcrest.Matchers.is;
import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia;
-import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory;
-import io.github.sebastiantoepfer.jsonschema.core.keyword.type.IntegerKeywordType;
import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
import jakarta.json.Json;
-import jakarta.json.JsonObject;
import jakarta.json.JsonValue;
-import jakarta.json.spi.JsonProvider;
import java.math.BigInteger;
import org.hamcrest.Matcher;
import org.junit.jupiter.api.Test;
@@ -43,7 +39,7 @@ class MinPropertiesKeywordTest {
@Test
void should_know_his_name() {
- final Keyword enumKeyword = createKeywordFrom(Json.createObjectBuilder().add("minProperties", 1).build());
+ final Keyword enumKeyword = new MinPropertiesKeyword(BigInteger.valueOf(1));
assertThat(enumKeyword.hasName("minProperties"), is(true));
assertThat(enumKeyword.hasName("test"), is(false));
@@ -52,7 +48,7 @@ void should_know_his_name() {
@Test
void should_be_printable() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("minProperties", 1).build()).printOn(new HashMapMedia()),
+ new MinPropertiesKeyword(BigInteger.valueOf(1)).printOn(new HashMapMedia()),
(Matcher) hasEntry(is("minProperties"), is(BigInteger.valueOf(1)))
);
}
@@ -60,9 +56,7 @@ void should_be_printable() {
@Test
void should_be_valid_for_non_objects() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("minProperties", 1).build())
- .asAssertion()
- .isValidFor(JsonValue.EMPTY_JSON_ARRAY),
+ new MinPropertiesKeyword(BigInteger.valueOf(1)).asAssertion().isValidFor(JsonValue.EMPTY_JSON_ARRAY),
is(true)
);
}
@@ -70,7 +64,7 @@ void should_be_valid_for_non_objects() {
@Test
void should_be_valid_for_excat_properties_count() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("minProperties", 1).build())
+ new MinPropertiesKeyword(BigInteger.valueOf(1))
.asAssertion()
.isValidFor(Json.createObjectBuilder().add("foo", 1).build()),
is(true)
@@ -80,7 +74,7 @@ void should_be_valid_for_excat_properties_count() {
@Test
void should_be_valid_for_more_properties() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("minProperties", 1).build())
+ new MinPropertiesKeyword(BigInteger.valueOf(1))
.asAssertion()
.isValidFor(Json.createObjectBuilder().add("foo", 1).add("bar", "hi").build()),
is(true)
@@ -90,18 +84,10 @@ void should_be_valid_for_more_properties() {
@Test
void should_be_invalid_for_less_properties() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("minProperties", 2).build())
+ new MinPropertiesKeyword(BigInteger.valueOf(2))
.asAssertion()
.isValidFor(Json.createObjectBuilder().add("foo", 1).build()),
is(false)
);
}
-
- private static Keyword createKeywordFrom(final JsonObject json) {
- return new IntegerKeywordType(
- JsonProvider.provider(),
- "minProperties",
- MinPropertiesKeyword::new
- ).createKeyword(new DefaultJsonSchemaFactory().create(json));
- }
}
diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MinimumKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MinimumKeywordTest.java
index 456a9784..b40b6f82 100644
--- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MinimumKeywordTest.java
+++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MinimumKeywordTest.java
@@ -28,13 +28,9 @@
import static org.hamcrest.Matchers.is;
import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia;
-import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory;
-import io.github.sebastiantoepfer.jsonschema.core.keyword.type.NumberKeywordType;
import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
import jakarta.json.Json;
-import jakarta.json.JsonObject;
import jakarta.json.JsonValue;
-import jakarta.json.spi.JsonProvider;
import java.math.BigDecimal;
import org.hamcrest.Matcher;
import org.junit.jupiter.api.Test;
@@ -43,9 +39,7 @@ class MinimumKeywordTest {
@Test
void should_know_his_name() {
- final Keyword minimum = createKeywordFrom(
- Json.createObjectBuilder().add("minimum", Json.createValue(1)).build()
- );
+ final Keyword minimum = new MinimumKeyword(BigDecimal.valueOf(1));
assertThat(minimum.hasName("minimum"), is(true));
assertThat(minimum.hasName("test"), is(false));
@@ -54,56 +48,31 @@ void should_know_his_name() {
@Test
void should_be_valid_for_non_number_values() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("minimum", Json.createValue(1)).build())
- .asAssertion()
- .isValidFor(JsonValue.EMPTY_JSON_OBJECT),
+ new MinimumKeyword(BigDecimal.valueOf(1)).asAssertion().isValidFor(JsonValue.EMPTY_JSON_OBJECT),
is(true)
);
}
@Test
void should_be_invalid_for_smaller_numbers() {
- assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("minimum", Json.createValue(0)).build())
- .asAssertion()
- .isValidFor(Json.createValue(-1)),
- is(false)
- );
+ assertThat(new MinimumKeyword(BigDecimal.valueOf(0)).asAssertion().isValidFor(Json.createValue(-1)), is(false));
}
@Test
void should_be_valid_for_equals_numbers() {
- assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("minimum", Json.createValue(0)).build())
- .asAssertion()
- .isValidFor(Json.createValue(0)),
- is(true)
- );
+ assertThat(new MinimumKeyword(BigDecimal.valueOf(0)).asAssertion().isValidFor(Json.createValue(0)), is(true));
}
@Test
void shhould_be_valid_for_greater_numbers() {
- assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("minimum", Json.createValue(0)).build())
- .asAssertion()
- .isValidFor(Json.createValue(1)),
- is(true)
- );
+ assertThat(new MinimumKeyword(BigDecimal.valueOf(0)).asAssertion().isValidFor(Json.createValue(1)), is(true));
}
@Test
void should_be_printable() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("minimum", Json.createValue(0)).build()).printOn(
- new HashMapMedia()
- ),
+ new MinimumKeyword(BigDecimal.valueOf(0)).printOn(new HashMapMedia()),
(Matcher) hasEntry(is("minimum"), is(BigDecimal.valueOf(0)))
);
}
-
- private static Keyword createKeywordFrom(final JsonObject json) {
- return new NumberKeywordType(JsonProvider.provider(), "minimum", MinimumKeyword::new).createKeyword(
- new DefaultJsonSchemaFactory().create(json)
- );
- }
}
diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MultipleOfKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MultipleOfKeywordTest.java
index ee677364..9f3a405c 100644
--- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MultipleOfKeywordTest.java
+++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/MultipleOfKeywordTest.java
@@ -28,13 +28,9 @@
import static org.hamcrest.Matchers.is;
import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia;
-import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory;
-import io.github.sebastiantoepfer.jsonschema.core.keyword.type.NumberKeywordType;
import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
import jakarta.json.Json;
-import jakarta.json.JsonObject;
import jakarta.json.JsonValue;
-import jakarta.json.spi.JsonProvider;
import java.math.BigDecimal;
import org.hamcrest.Matcher;
import org.junit.jupiter.api.Test;
@@ -43,9 +39,7 @@ class MultipleOfKeywordTest {
@Test
void should_know_his_name() {
- final Keyword multipleOf = createKeywordFrom(
- Json.createObjectBuilder().add("multipleOf", Json.createValue(10)).build()
- );
+ final Keyword multipleOf = new MultipleOfKeyword(BigDecimal.valueOf(10));
assertThat(multipleOf.hasName("multipleOf"), is(true));
assertThat(multipleOf.hasName("test"), is(false));
@@ -54,9 +48,7 @@ void should_know_his_name() {
@Test
void should_be_valid_for_non_number_values() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("multipleOf", Json.createValue(10)).build())
- .asAssertion()
- .isValidFor(JsonValue.EMPTY_JSON_OBJECT),
+ new MultipleOfKeyword(BigDecimal.valueOf(10)).asAssertion().isValidFor(JsonValue.EMPTY_JSON_OBJECT),
is(true)
);
}
@@ -64,9 +56,7 @@ void should_be_valid_for_non_number_values() {
@Test
void should_be_valid_for_a_multipleOf() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("multipleOf", Json.createValue(1.5)).build())
- .asAssertion()
- .isValidFor(Json.createValue(4.5)),
+ new MultipleOfKeyword(BigDecimal.valueOf(1.5)).asAssertion().isValidFor(Json.createValue(4.5)),
is(true)
);
}
@@ -74,9 +64,7 @@ void should_be_valid_for_a_multipleOf() {
@Test
void should_be_invalid_for_non_multipleOf() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("multipleOf", Json.createValue(2)).build())
- .asAssertion()
- .isValidFor(Json.createValue(7)),
+ new MultipleOfKeyword(BigDecimal.valueOf(2)).asAssertion().isValidFor(Json.createValue(7)),
is(false)
);
}
@@ -84,11 +72,7 @@ void should_be_invalid_for_non_multipleOf() {
@Test
void should_be_valid_for_any_int_if_multipleOf_is_1en8() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder().add("multipleOf", Json.createValue(new BigDecimal("1e-8"))).build()
- )
- .asAssertion()
- .isValidFor(Json.createValue(12391239123L)),
+ new MultipleOfKeyword(new BigDecimal("1e-8")).asAssertion().isValidFor(Json.createValue(12391239123L)),
is(true)
);
}
@@ -96,16 +80,8 @@ void should_be_valid_for_any_int_if_multipleOf_is_1en8() {
@Test
void should_be_printable() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("multipleOf", Json.createValue(2)).build()).printOn(
- new HashMapMedia()
- ),
+ new MultipleOfKeyword(BigDecimal.valueOf(2)).printOn(new HashMapMedia()),
(Matcher) hasEntry(is("multipleOf"), is(new BigDecimal(2)))
);
}
-
- private static Keyword createKeywordFrom(final JsonObject json) {
- return new NumberKeywordType(JsonProvider.provider(), "multipleOf", MultipleOfKeyword::new).createKeyword(
- new DefaultJsonSchemaFactory().create(json)
- );
- }
}
diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/PatternKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/PatternKeywordTest.java
index 817ff41a..96250f0e 100644
--- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/PatternKeywordTest.java
+++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/PatternKeywordTest.java
@@ -28,13 +28,9 @@
import static org.hamcrest.Matchers.is;
import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia;
-import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory;
-import io.github.sebastiantoepfer.jsonschema.core.keyword.type.StringKeywordType;
import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
import jakarta.json.Json;
-import jakarta.json.JsonObject;
import jakarta.json.JsonValue;
-import jakarta.json.spi.JsonProvider;
import org.hamcrest.Matcher;
import org.junit.jupiter.api.Test;
@@ -42,9 +38,7 @@ class PatternKeywordTest {
@Test
void should_be_know_his_name() {
- final Keyword pattern = createKeywordFrom(
- Json.createObjectBuilder().add("pattern", Json.createValue("a")).build()
- );
+ final Keyword pattern = new PatternKeyword("a");
assertThat(pattern.hasName("pattern"), is(true));
assertThat(pattern.hasName("test"), is(false));
@@ -52,22 +46,13 @@ void should_be_know_his_name() {
@Test
void should_be_valid_for_non_string_value() {
- assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("pattern", Json.createValue("a")).build())
- .asAssertion()
- .isValidFor(JsonValue.TRUE),
- is(true)
- );
+ assertThat(new PatternKeyword("a").asAssertion().isValidFor(JsonValue.TRUE), is(true));
}
@Test
void should_be_invalid_for_non_matching_value() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder()
- .add("pattern", Json.createValue("^(\\([0-9]{3}\\))?[0-9]{3}-[0-9]{4}$"))
- .build()
- )
+ new PatternKeyword("^(\\([0-9]{3}\\))?[0-9]{3}-[0-9]{4}$")
.asAssertion()
.isValidFor(Json.createValue("(888)555-1212 ext. 532")),
is(false)
@@ -77,11 +62,7 @@ void should_be_invalid_for_non_matching_value() {
@Test
void should_be_valid_matching_value() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder()
- .add("pattern", Json.createValue("^(\\([0-9]{3}\\))?[0-9]{3}-[0-9]{4}$"))
- .build()
- )
+ new PatternKeyword("^(\\([0-9]{3}\\))?[0-9]{3}-[0-9]{4}$")
.asAssertion()
.isValidFor(Json.createValue("(888)555-1212")),
is(true)
@@ -91,18 +72,8 @@ void should_be_valid_matching_value() {
@Test
void should_be_printable() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder()
- .add("pattern", Json.createValue("^(\\([0-9]{3}\\))?[0-9]{3}-[0-9]{4}$"))
- .build()
- ).printOn(new HashMapMedia()),
+ new PatternKeyword("^(\\([0-9]{3}\\))?[0-9]{3}-[0-9]{4}$").printOn(new HashMapMedia()),
(Matcher) hasEntry(is("pattern"), is("^(\\([0-9]{3}\\))?[0-9]{3}-[0-9]{4}$"))
);
}
-
- private static Keyword createKeywordFrom(final JsonObject json) {
- return new StringKeywordType(JsonProvider.provider(), "pattern", PatternKeyword::new).createKeyword(
- new DefaultJsonSchemaFactory().create(json)
- );
- }
}
diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/RequiredKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/RequiredKeywordTest.java
index f832e374..35374374 100644
--- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/RequiredKeywordTest.java
+++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/RequiredKeywordTest.java
@@ -29,14 +29,11 @@
import static org.hamcrest.Matchers.is;
import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia;
-import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory;
-import io.github.sebastiantoepfer.jsonschema.core.keyword.type.StringArrayKeywordType;
import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
import jakarta.json.Json;
-import jakarta.json.JsonObject;
import jakarta.json.JsonValue;
-import jakarta.json.spi.JsonProvider;
import java.math.BigDecimal;
+import java.util.List;
import org.hamcrest.Matcher;
import org.junit.jupiter.api.Test;
@@ -44,9 +41,7 @@ class RequiredKeywordTest {
@Test
void should_know_his_name() {
- final Keyword required = createKeywordFrom(
- Json.createObjectBuilder().add("required", JsonValue.EMPTY_JSON_ARRAY).build()
- );
+ final Keyword required = new RequiredKeyword(List.of());
assertThat(required.hasName("required"), is(true));
assertThat(required.hasName("test"), is(false));
@@ -55,9 +50,7 @@ void should_know_his_name() {
@Test
void should_invalid_if_not_all_properties_in_the_instance() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder().add("required", Json.createArrayBuilder().add("foo").add("bar")).build()
- )
+ new RequiredKeyword(List.of("foo", "bar"))
.asAssertion()
.isValidFor(Json.createObjectBuilder().add("foo", BigDecimal.ONE).build()),
is(false)
@@ -67,11 +60,7 @@ void should_invalid_if_not_all_properties_in_the_instance() {
@Test
void should_valid_for_non_objects() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder().add("required", Json.createArrayBuilder().add("foo").add("bar")).build()
- )
- .asAssertion()
- .isValidFor(JsonValue.EMPTY_JSON_ARRAY),
+ new RequiredKeyword(List.of("foo", "bar")).asAssertion().isValidFor(JsonValue.EMPTY_JSON_ARRAY),
is(true)
);
}
@@ -79,9 +68,7 @@ void should_valid_for_non_objects() {
@Test
void should_valid_if_all_properties_are_in_the_instance() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder().add("required", Json.createArrayBuilder().add("foo").add("bar")).build()
- )
+ new RequiredKeyword(List.of("foo", "bar"))
.asAssertion()
.isValidFor(Json.createObjectBuilder().add("foo", BigDecimal.ONE).add("bar", "test").build()),
is(true)
@@ -91,16 +78,8 @@ void should_valid_if_all_properties_are_in_the_instance() {
@Test
void should_be_printable() {
assertThat(
- createKeywordFrom(
- Json.createObjectBuilder().add("required", Json.createArrayBuilder().add("foo").add("bar")).build()
- ).printOn(new HashMapMedia()),
+ new RequiredKeyword(List.of("foo", "bar")).printOn(new HashMapMedia()),
(Matcher) hasEntry(is("required"), containsInAnyOrder("foo", "bar"))
);
}
-
- private static Keyword createKeywordFrom(final JsonObject json) {
- return new StringArrayKeywordType(JsonProvider.provider(), "required", RequiredKeyword::new).createKeyword(
- new DefaultJsonSchemaFactory().create(json)
- );
- }
}
diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/UniqueItemsKeywordTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/UniqueItemsKeywordTest.java
index 86db461c..9904d662 100644
--- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/UniqueItemsKeywordTest.java
+++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/UniqueItemsKeywordTest.java
@@ -28,13 +28,9 @@
import static org.hamcrest.Matchers.is;
import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia;
-import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory;
-import io.github.sebastiantoepfer.jsonschema.core.keyword.type.BooleanKeywordType;
import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
import jakarta.json.Json;
-import jakarta.json.JsonObject;
import jakarta.json.JsonValue;
-import jakarta.json.spi.JsonProvider;
import java.io.StringReader;
import java.math.BigDecimal;
import org.hamcrest.Matcher;
@@ -44,9 +40,7 @@ class UniqueItemsKeywordTest {
@Test
void should_know_his_name() {
- final Keyword keyword = createKeywordFrom(
- Json.createObjectBuilder().add("uniqueItems", JsonValue.FALSE).build()
- );
+ final Keyword keyword = new UniqueItemsKeyword(false);
assertThat(keyword.hasName("uniqueItems"), is(true));
assertThat(keyword.hasName("test"), is(false));
@@ -55,9 +49,7 @@ void should_know_his_name() {
@Test
void should_be_valid_for_uniqueItems() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("uniqueItems", JsonValue.TRUE).build())
- .asAssertion()
- .isValidFor(Json.createArrayBuilder().add("1").add("2").build()),
+ new UniqueItemsKeyword(true).asAssertion().isValidFor(Json.createArrayBuilder().add("1").add("2").build()),
is(true)
);
}
@@ -65,9 +57,7 @@ void should_be_valid_for_uniqueItems() {
@Test
void should_be_valid_for_non_uniqueItems_if_false() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("uniqueItems", JsonValue.FALSE).build())
- .asAssertion()
- .isValidFor(Json.createArrayBuilder().add("1").add("1").build()),
+ new UniqueItemsKeyword(false).asAssertion().isValidFor(Json.createArrayBuilder().add("1").add("1").build()),
is(true)
);
}
@@ -75,27 +65,20 @@ void should_be_valid_for_non_uniqueItems_if_false() {
@Test
void should_be_invalid_for_non_uniqueItems() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("uniqueItems", JsonValue.TRUE).build())
- .asAssertion()
- .isValidFor(Json.createArrayBuilder().add("1").add("1").build()),
+ new UniqueItemsKeyword(true).asAssertion().isValidFor(Json.createArrayBuilder().add("1").add("1").build()),
is(false)
);
}
@Test
void should_be_valid_for_non_arrays() {
- assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("uniqueItems", JsonValue.FALSE).build())
- .asAssertion()
- .isValidFor(JsonValue.EMPTY_JSON_OBJECT),
- is(true)
- );
+ assertThat(new UniqueItemsKeyword(false).asAssertion().isValidFor(JsonValue.EMPTY_JSON_OBJECT), is(true));
}
@Test
void should_be_invalid_if_numbers_mathematically_unequal() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("uniqueItems", JsonValue.TRUE).build())
+ new UniqueItemsKeyword(true)
.asAssertion()
.isValidFor(Json.createReader(new StringReader("[1.0,1.00,1]")).readArray()),
is(false)
@@ -126,16 +109,8 @@ void pitests_say_i_must_write_this_tests() {
@Test
void should_be_printable() {
assertThat(
- createKeywordFrom(Json.createObjectBuilder().add("uniqueItems", JsonValue.TRUE).build()).printOn(
- new HashMapMedia()
- ),
+ new UniqueItemsKeyword(true).printOn(new HashMapMedia()),
(Matcher) hasEntry(is("uniqueItems"), is(true))
);
}
-
- private static Keyword createKeywordFrom(final JsonObject json) {
- return new BooleanKeywordType(JsonProvider.provider(), "uniqueItems", UniqueItemsKeyword::new).createKeyword(
- new DefaultJsonSchemaFactory().create(json)
- );
- }
}
diff --git a/pom.xml b/pom.xml
index ad3cb22e..aa0ec438 100644
--- a/pom.xml
+++ b/pom.xml
@@ -13,7 +13,7 @@
io.github.sebastian-toepfer.json-schema
json-schema
- 0.2.1
+ 0.3.0-SNAPSHOT
Json Schema
pom
diff --git a/vocabulary-spi/pom.xml b/vocabulary-spi/pom.xml
index 9074e0eb..e36b01b3 100644
--- a/vocabulary-spi/pom.xml
+++ b/vocabulary-spi/pom.xml
@@ -8,7 +8,7 @@
io.github.sebastian-toepfer.json-schema
json-schema
- 0.2.1
+ 0.3.0-SNAPSHOT
json-schema-vocabulary-spi
@@ -42,6 +42,11 @@
hamcrest-optional
test
+
+ nl.jqno.equalsverifier
+ equalsverifier
+ test
+
jakarta.json
diff --git a/vocabulary-spi/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/LazyVocabularyDefinition.java b/vocabulary-spi/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/LazyVocabularyDefinition.java
new file mode 100644
index 00000000..de1a4e2a
--- /dev/null
+++ b/vocabulary-spi/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/LazyVocabularyDefinition.java
@@ -0,0 +1,102 @@
+/*
+ * The MIT License
+ *
+ * Copyright 2024 sebastian.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package io.github.sebastiantoepfer.jsonschema.vocabulary.spi;
+
+import io.github.sebastiantoepfer.jsonschema.Vocabulary;
+import java.net.URI;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.function.Supplier;
+import java.util.stream.Stream;
+
+public final class LazyVocabularyDefinition implements VocabularyDefinition {
+
+ private final URI id;
+ private final boolean required;
+ private final Supplier> lazyVocabularies;
+
+ public LazyVocabularyDefinition(
+ final URI id,
+ final boolean required,
+ final Supplier> lazyVocabularies
+ ) {
+ this.id = Objects.requireNonNull(id);
+ this.required = required;
+ this.lazyVocabularies = Objects.requireNonNull(lazyVocabularies);
+ }
+
+ @Override
+ public Optional findVocabulary() {
+ final Optional result = lazyVocabularies
+ .get()
+ .map(loader -> loader.loadVocabularyWithId(id))
+ .flatMap(Optional::stream)
+ .findFirst();
+ if (result.isEmpty() && isRequired()) {
+ throw new IllegalStateException("can not find required vocabulary: " + id);
+ }
+ return result;
+ }
+
+ @Override
+ public boolean hasid(final URI id) {
+ return Objects.equals(this.id, id);
+ }
+
+ @Override
+ public boolean isRequired() {
+ return required;
+ }
+
+ @Override
+ public String toString() {
+ return "LazyVocabularyDefinition{" + "id=" + id + ", required=" + required + '}';
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 3;
+ hash = 59 * hash + Objects.hashCode(this.id);
+ hash = 59 * hash + (this.required ? 1 : 0);
+ return hash;
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final LazyVocabularyDefinition other = (LazyVocabularyDefinition) obj;
+ if (this.required != other.required) {
+ return false;
+ }
+ return Objects.equals(this.id, other.id);
+ }
+}
diff --git a/vocabulary-spi/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/DefaultVocabulary.java b/vocabulary-spi/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/ListVocabulary.java
similarity index 89%
rename from vocabulary-spi/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/DefaultVocabulary.java
rename to vocabulary-spi/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/ListVocabulary.java
index 2d551ff6..4228a577 100644
--- a/vocabulary-spi/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/DefaultVocabulary.java
+++ b/vocabulary-spi/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/ListVocabulary.java
@@ -32,16 +32,16 @@
import java.util.Objects;
import java.util.Optional;
-public final class DefaultVocabulary implements Vocabulary {
+public final class ListVocabulary implements Vocabulary {
private final URI id;
private final List keywords;
- public DefaultVocabulary(final URI id, final KeywordType... keywortds) {
+ public ListVocabulary(final URI id, final KeywordType... keywortds) {
this(id, Arrays.asList(keywortds));
}
- public DefaultVocabulary(final URI id, final Collection keywords) {
+ public ListVocabulary(final URI id, final Collection keywords) {
this.id = Objects.requireNonNull(id);
this.keywords = List.copyOf(keywords);
}
diff --git a/vocabulary-spi/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/ServiceLoaderLazyVocabulariesSupplier.java b/vocabulary-spi/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/ServiceLoaderLazyVocabulariesSupplier.java
new file mode 100644
index 00000000..93774c89
--- /dev/null
+++ b/vocabulary-spi/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/ServiceLoaderLazyVocabulariesSupplier.java
@@ -0,0 +1,36 @@
+/*
+ * The MIT License
+ *
+ * Copyright 2024 sebastian.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package io.github.sebastiantoepfer.jsonschema.vocabulary.spi;
+
+import java.util.ServiceLoader;
+import java.util.function.Supplier;
+import java.util.stream.Stream;
+
+public final class ServiceLoaderLazyVocabulariesSupplier implements Supplier> {
+
+ @Override
+ public Stream get() {
+ return ServiceLoader.load(LazyVocabularies.class).stream().map(ServiceLoader.Provider::get);
+ }
+}
diff --git a/vocabulary-spi/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/VocabularyDefinition.java b/vocabulary-spi/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/VocabularyDefinition.java
index a14c7d61..d53c3574 100644
--- a/vocabulary-spi/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/VocabularyDefinition.java
+++ b/vocabulary-spi/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/VocabularyDefinition.java
@@ -26,19 +26,11 @@
import io.github.sebastiantoepfer.jsonschema.Vocabulary;
import java.net.URI;
import java.util.Optional;
-import java.util.ServiceLoader;
-public record VocabularyDefinition(URI id, boolean required) {
- public Optional findVocabulary() {
- final Optional result = ServiceLoader.load(LazyVocabularies.class)
- .stream()
- .map(ServiceLoader.Provider::get)
- .map(loader -> loader.loadVocabularyWithId(id))
- .flatMap(Optional::stream)
- .findFirst();
- if (result.isEmpty() && required) {
- throw new IllegalStateException("can not find required vocabulary: " + id);
- }
- return result;
- }
+public interface VocabularyDefinition {
+ Optional findVocabulary();
+
+ boolean hasid(URI id);
+
+ boolean isRequired();
}
diff --git a/vocabulary-spi/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/VocabularyDefinitions.java b/vocabulary-spi/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/VocabularyDefinitions.java
index fe9dd85f..d9822afd 100644
--- a/vocabulary-spi/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/VocabularyDefinitions.java
+++ b/vocabulary-spi/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/VocabularyDefinitions.java
@@ -23,8 +23,9 @@
*/
package io.github.sebastiantoepfer.jsonschema.vocabulary.spi;
+import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
import java.util.stream.Stream;
-public interface VocabularyDefinitions {
+public interface VocabularyDefinitions extends Keyword {
Stream definitions();
}
diff --git a/vocabulary-spi/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/VocabularyDefinitionTest.java b/vocabulary-spi/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/LazyVocabularyDefinitionTest.java
similarity index 60%
rename from vocabulary-spi/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/VocabularyDefinitionTest.java
rename to vocabulary-spi/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/LazyVocabularyDefinitionTest.java
index dd582c88..72d6ab4d 100644
--- a/vocabulary-spi/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/VocabularyDefinitionTest.java
+++ b/vocabulary-spi/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/LazyVocabularyDefinitionTest.java
@@ -26,24 +26,41 @@
import static com.github.npathai.hamcrestopt.OptionalMatchers.isEmpty;
import static com.github.npathai.hamcrestopt.OptionalMatchers.isPresentAndIs;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertThrows;
import io.github.sebastiantoepfer.jsonschema.Vocabulary;
import java.net.URI;
+import java.util.stream.Stream;
+import nl.jqno.equalsverifier.EqualsVerifier;
+import nl.jqno.equalsverifier.Warning;
import org.junit.jupiter.api.Test;
-class VocabularyDefinitionTest {
+class LazyVocabularyDefinitionTest {
+
+ @Test
+ void verifyEqualsContract() {
+ EqualsVerifier.forClass(LazyVocabularyDefinition.class).suppress(Warning.ALL_FIELDS_SHOULD_BE_USED).verify();
+ }
@Test
void should_throw_illegal_state_if_a_required_vocabulary_can_not_be_loaded() {
- final VocabularyDefinition vocabDef = new VocabularyDefinition(URI.create("https://invalid"), true);
+ final VocabularyDefinition vocabDef = new LazyVocabularyDefinition(
+ URI.create("https://invalid"),
+ true,
+ () -> Stream.empty()
+ );
assertThrows(IllegalStateException.class, () -> vocabDef.findVocabulary());
}
@Test
void should_find_mandatory_core_vocabulary() {
assertThat(
- new VocabularyDefinition(URI.create("https://json-schema.org/draft/2020-12/vocab/core"), true)
+ new LazyVocabularyDefinition(
+ URI.create("https://json-schema.org/draft/2020-12/vocab/core"),
+ true,
+ new ServiceLoaderLazyVocabulariesSupplier()
+ )
.findVocabulary()
.map(Vocabulary::id),
isPresentAndIs(URI.create("https://json-schema.org/draft/2020-12/vocab/core"))
@@ -53,8 +70,22 @@ void should_find_mandatory_core_vocabulary() {
@Test
void should_retrun_empty_for_optional_vocabulary_which_can_not_be_loaded() {
assertThat(
- new VocabularyDefinition(URI.create("https://invalid"), false).findVocabulary().map(Vocabulary::id),
+ new LazyVocabularyDefinition(URI.create("https://invalid"), false, () -> Stream.empty())
+ .findVocabulary()
+ .map(Vocabulary::id),
isEmpty()
);
}
+
+ @Test
+ void should_know_this_id() {
+ final LazyVocabularyDefinition vocbDef = new LazyVocabularyDefinition(
+ URI.create("https://json-schema.org/draft/2020-12/vocab/core"),
+ false,
+ () -> Stream.empty()
+ );
+
+ assertThat(vocbDef.hasid(URI.create("https://json-schema.org/draft/2020-12/vocab/core")), is(true));
+ assertThat(vocbDef.hasid(URI.create("https://invalid")), is(false));
+ }
}
diff --git a/vocabulary-spi/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/DefaultVocabularyTest.java b/vocabulary-spi/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/ListVocabularyTest.java
similarity index 86%
rename from vocabulary-spi/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/DefaultVocabularyTest.java
rename to vocabulary-spi/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/ListVocabularyTest.java
index bcc681e4..96f08877 100644
--- a/vocabulary-spi/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/DefaultVocabularyTest.java
+++ b/vocabulary-spi/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/ListVocabularyTest.java
@@ -34,12 +34,12 @@
import java.net.URI;
import org.junit.jupiter.api.Test;
-class DefaultVocabularyTest {
+class ListVocabularyTest {
@Test
void should_return_the_id() {
assertThat(
- new DefaultVocabulary(URI.create("http::/localhots/vocab")).id(),
+ new ListVocabulary(URI.create("http::/localhots/vocab")).id(),
is(URI.create("http::/localhots/vocab"))
);
}
@@ -47,10 +47,9 @@ void should_return_the_id() {
@Test
void should_return_empty_if_requested_keyword_is_unknown() {
assertThat(
- new DefaultVocabulary(
- URI.create("http://localhost"),
- new SimpleTestKeywordType("name")
- ).findKeywordTypeByName("test"),
+ new ListVocabulary(URI.create("http://localhost"), new SimpleTestKeywordType("name")).findKeywordTypeByName(
+ "test"
+ ),
isEmpty()
);
}
@@ -59,7 +58,7 @@ void should_return_empty_if_requested_keyword_is_unknown() {
void should_return_requested_keyword_if_is_it_known() {
final KeywordType testKeywordType = new SimpleTestKeywordType("test");
assertThat(
- new DefaultVocabulary(URI.create("http://localhost"), testKeywordType).findKeywordTypeByName("test"),
+ new ListVocabulary(URI.create("http://localhost"), testKeywordType).findKeywordTypeByName("test"),
isPresentAndIs(testKeywordType)
);
}