From e83b7ae917901fd9869a1f75c2c0114296d5cdc1 Mon Sep 17 00:00:00 2001
From: Sebastian Toepfer <61313468+sebastian-toepfer@users.noreply.github.com>
Date: Tue, 26 Sep 2023 21:26:20 +0200
Subject: [PATCH] add support for items keyword
---
core/pom.xml | 10 +++
.../core/vocab/basic/BasicVocabulary.java | 3 +-
.../core/vocab/basic/ItemsKeywordType.java | 82 +++++++++++++++++++
.../vocab/basic/ItemsKeywordTypeTest.java | 65 +++++++++++++++
4 files changed, 159 insertions(+), 1 deletion(-)
create mode 100644 core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/basic/ItemsKeywordType.java
create mode 100644 core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/basic/ItemsKeywordTypeTest.java
diff --git a/core/pom.xml b/core/pom.xml
index e5e55021..53dc2efd 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -167,6 +167,16 @@
**/tests/draft2019-09/multipleOf.json
**/tests/draft2020-12/multipleOf.json
**/tests/draft-next/multipleOf.json
+
+
diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/basic/BasicVocabulary.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/basic/BasicVocabulary.java
index 0616c530..ec37ea62 100644
--- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/basic/BasicVocabulary.java
+++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/basic/BasicVocabulary.java
@@ -46,7 +46,8 @@ public BasicVocabulary() {
new ExclusiveMinimumKeywordType(),
new MaximumKeywordType(),
new ExclusiveMaximumKeywordType(),
- new MultipleOfKeywordType()
+ new MultipleOfKeywordType(),
+ new ItemsKeywordType()
);
}
diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/basic/ItemsKeywordType.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/basic/ItemsKeywordType.java
new file mode 100644
index 00000000..98a39bfc
--- /dev/null
+++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/basic/ItemsKeywordType.java
@@ -0,0 +1,82 @@
+/*
+ * 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.basic;
+
+import io.github.sebastiantoepfer.jsonschema.ConstraintViolation;
+import io.github.sebastiantoepfer.jsonschema.InstanceType;
+import io.github.sebastiantoepfer.jsonschema.JsonSchema;
+import io.github.sebastiantoepfer.jsonschema.JsonSchemas;
+import io.github.sebastiantoepfer.jsonschema.Validator;
+import io.github.sebastiantoepfer.jsonschema.core.vocab.ConstraintAssertion;
+import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
+import io.github.sebastiantoepfer.jsonschema.keyword.KeywordType;
+import jakarta.json.JsonArray;
+import jakarta.json.JsonValue;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+final class ItemsKeywordType implements KeywordType {
+
+ @Override
+ public String name() {
+ return "items";
+ }
+
+ @Override
+ public Keyword createKeyword(final JsonValue value) {
+ return new ItemsKeyword(JsonSchemas.load(value));
+ }
+
+ private class ItemsKeyword implements ConstraintAssertion {
+
+ private final JsonSchema schema;
+
+ public ItemsKeyword(final JsonSchema schema) {
+ this.schema = schema;
+ }
+
+ @Override
+ public boolean hasName(final String name) {
+ return Objects.equals(name(), name);
+ }
+
+ @Override
+ public Collection violationsBy(final JsonValue value) {
+ final Collection result;
+ if (!InstanceType.ARRAY.isInstance(value) || matchesSchema(value.asJsonArray())) {
+ result = Collections.emptyList();
+ } else {
+ result = List.of(new ConstraintViolation());
+ }
+ return result;
+ }
+
+ private boolean matchesSchema(final JsonArray items) {
+ final Validator itemValidator = schema.validator();
+ return items.stream().map(itemValidator::validate).allMatch(Collection::isEmpty);
+ }
+ }
+}
diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/basic/ItemsKeywordTypeTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/basic/ItemsKeywordTypeTest.java
new file mode 100644
index 00000000..20a37d63
--- /dev/null
+++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/basic/ItemsKeywordTypeTest.java
@@ -0,0 +1,65 @@
+/*
+ * 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.basic;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+
+import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
+import jakarta.json.Json;
+import jakarta.json.JsonValue;
+import org.junit.jupiter.api.Test;
+
+class ItemsKeywordTypeTest {
+
+ @Test
+ void should_know_his_name() {
+ final Keyword items = new ItemsKeywordType().createKeyword(JsonValue.EMPTY_JSON_OBJECT);
+
+ assertThat(items.hasName("items"), is(true));
+ assertThat(items.hasName("test"), is(false));
+ }
+
+ @Test
+ void should_be_invalid_if_items_does_not_match_schema() {
+ assertThat(
+ new ItemsKeywordType()
+ .createKeyword(Json.createObjectBuilder().add("type", "number").build())
+ .asAssertion()
+ .isValidFor(Json.createArrayBuilder().add(1).add("invalid").add(2).build()),
+ is(false)
+ );
+ }
+
+ @Test
+ void should_be_valid_if_all_items_match_schema() {
+ assertThat(
+ new ItemsKeywordType()
+ .createKeyword(Json.createObjectBuilder().add("type", "number").build())
+ .asAssertion()
+ .isValidFor(Json.createArrayBuilder().add(1).add(2).build()),
+ is(true)
+ );
+ }
+}