diff --git a/api/pom.xml b/api/pom.xml new file mode 100644 index 00000000..d9d19f5c --- /dev/null +++ b/api/pom.xml @@ -0,0 +1,49 @@ + + + 4.0.0 + + + io.github.sebastian-toepfer.json-schema + json-schema + 0.1.0-SNAPSHOT + + + json-schema-api + Json Schema :: api + + + + org.junit.jupiter + junit-jupiter-api + test + + + org.junit.jupiter + junit-jupiter-params + test + + + org.junit.jupiter + junit-jupiter-engine + test + + + + org.hamcrest + hamcrest + test + + + + jakarta.json + jakarta.json-api + provided + + + + org.eclipse.parsson + parsson + test + + + diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/ConstraintViolation.java b/api/src/main/java/io/github/sebastiantoepfer/jsonschema/ConstraintViolation.java similarity index 95% rename from core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/ConstraintViolation.java rename to api/src/main/java/io/github/sebastiantoepfer/jsonschema/ConstraintViolation.java index ca12797f..06a3d018 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/ConstraintViolation.java +++ b/api/src/main/java/io/github/sebastiantoepfer/jsonschema/ConstraintViolation.java @@ -21,6 +21,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.github.sebastiantoepfer.jsonschema.core; +package io.github.sebastiantoepfer.jsonschema; public final class ConstraintViolation {} diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/InstanceType.java b/api/src/main/java/io/github/sebastiantoepfer/jsonschema/InstanceType.java similarity index 97% rename from core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/InstanceType.java rename to api/src/main/java/io/github/sebastiantoepfer/jsonschema/InstanceType.java index 31bd7b50..ffac968d 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/InstanceType.java +++ b/api/src/main/java/io/github/sebastiantoepfer/jsonschema/InstanceType.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.github.sebastiantoepfer.jsonschema.core; +package io.github.sebastiantoepfer.jsonschema; import jakarta.json.JsonNumber; import jakarta.json.JsonValue; diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/JsonSchema.java b/api/src/main/java/io/github/sebastiantoepfer/jsonschema/JsonSchema.java similarity index 96% rename from core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/JsonSchema.java rename to api/src/main/java/io/github/sebastiantoepfer/jsonschema/JsonSchema.java index 3c1a07ab..98ffbcb4 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/JsonSchema.java +++ b/api/src/main/java/io/github/sebastiantoepfer/jsonschema/JsonSchema.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.github.sebastiantoepfer.jsonschema.core; +package io.github.sebastiantoepfer.jsonschema; import jakarta.json.JsonValue; diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/JsonSchemas.java b/api/src/main/java/io/github/sebastiantoepfer/jsonschema/JsonSchemas.java similarity index 93% rename from core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/JsonSchemas.java rename to api/src/main/java/io/github/sebastiantoepfer/jsonschema/JsonSchemas.java index df60a3bf..68fecd04 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/JsonSchemas.java +++ b/api/src/main/java/io/github/sebastiantoepfer/jsonschema/JsonSchemas.java @@ -21,9 +21,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.github.sebastiantoepfer.jsonschema.core; +package io.github.sebastiantoepfer.jsonschema; -import io.github.sebastiantoepfer.jsonschema.core.spi.JsonSchemaFactory; +import io.github.sebastiantoepfer.jsonschema.spi.JsonSchemaFactory; import jakarta.json.Json; import jakarta.json.JsonReader; import jakarta.json.JsonValue; diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/Validator.java b/api/src/main/java/io/github/sebastiantoepfer/jsonschema/Validator.java similarity index 96% rename from core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/Validator.java rename to api/src/main/java/io/github/sebastiantoepfer/jsonschema/Validator.java index acb54a1d..26c6305e 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/Validator.java +++ b/api/src/main/java/io/github/sebastiantoepfer/jsonschema/Validator.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.github.sebastiantoepfer.jsonschema.core; +package io.github.sebastiantoepfer.jsonschema; import jakarta.json.Json; import jakarta.json.JsonReader; diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/Vocabulary.java b/api/src/main/java/io/github/sebastiantoepfer/jsonschema/Vocabulary.java similarity index 91% rename from core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/Vocabulary.java rename to api/src/main/java/io/github/sebastiantoepfer/jsonschema/Vocabulary.java index abe04c48..62f22a24 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/Vocabulary.java +++ b/api/src/main/java/io/github/sebastiantoepfer/jsonschema/Vocabulary.java @@ -21,9 +21,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.github.sebastiantoepfer.jsonschema.core; +package io.github.sebastiantoepfer.jsonschema; -import io.github.sebastiantoepfer.jsonschema.core.keyword.KeywordType; +import io.github.sebastiantoepfer.jsonschema.keyword.KeywordType; import java.net.URI; import java.util.Optional; diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/Annotation.java b/api/src/main/java/io/github/sebastiantoepfer/jsonschema/keyword/Annotation.java similarity index 96% rename from core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/Annotation.java rename to api/src/main/java/io/github/sebastiantoepfer/jsonschema/keyword/Annotation.java index 08efb16c..f7e2ae47 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/Annotation.java +++ b/api/src/main/java/io/github/sebastiantoepfer/jsonschema/keyword/Annotation.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.github.sebastiantoepfer.jsonschema.core.keyword; +package io.github.sebastiantoepfer.jsonschema.keyword; import jakarta.json.JsonValue; import java.util.Collection; diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/Applicator.java b/api/src/main/java/io/github/sebastiantoepfer/jsonschema/keyword/Applicator.java similarity index 96% rename from core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/Applicator.java rename to api/src/main/java/io/github/sebastiantoepfer/jsonschema/keyword/Applicator.java index c72ef964..6fefab8c 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/Applicator.java +++ b/api/src/main/java/io/github/sebastiantoepfer/jsonschema/keyword/Applicator.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.github.sebastiantoepfer.jsonschema.core.keyword; +package io.github.sebastiantoepfer.jsonschema.keyword; import jakarta.json.JsonValue; import java.util.Collection; diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/Assertion.java b/api/src/main/java/io/github/sebastiantoepfer/jsonschema/keyword/Assertion.java similarity index 96% rename from core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/Assertion.java rename to api/src/main/java/io/github/sebastiantoepfer/jsonschema/keyword/Assertion.java index 08f674fc..2def625a 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/Assertion.java +++ b/api/src/main/java/io/github/sebastiantoepfer/jsonschema/keyword/Assertion.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.github.sebastiantoepfer.jsonschema.core.keyword; +package io.github.sebastiantoepfer.jsonschema.keyword; import jakarta.json.JsonValue; import java.util.Collection; diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/DefaultAnnotation.java b/api/src/main/java/io/github/sebastiantoepfer/jsonschema/keyword/DefaultAnnotation.java similarity index 97% rename from core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/DefaultAnnotation.java rename to api/src/main/java/io/github/sebastiantoepfer/jsonschema/keyword/DefaultAnnotation.java index 53729a5f..52ba76c3 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/DefaultAnnotation.java +++ b/api/src/main/java/io/github/sebastiantoepfer/jsonschema/keyword/DefaultAnnotation.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.github.sebastiantoepfer.jsonschema.core.keyword; +package io.github.sebastiantoepfer.jsonschema.keyword; import jakarta.json.JsonValue; import java.util.Objects; diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/Identifier.java b/api/src/main/java/io/github/sebastiantoepfer/jsonschema/keyword/Identifier.java similarity index 96% rename from core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/Identifier.java rename to api/src/main/java/io/github/sebastiantoepfer/jsonschema/keyword/Identifier.java index 16818b10..e947d35e 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/Identifier.java +++ b/api/src/main/java/io/github/sebastiantoepfer/jsonschema/keyword/Identifier.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.github.sebastiantoepfer.jsonschema.core.keyword; +package io.github.sebastiantoepfer.jsonschema.keyword; import java.net.URI; import java.util.Collection; diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/Keyword.java b/api/src/main/java/io/github/sebastiantoepfer/jsonschema/keyword/Keyword.java similarity index 97% rename from core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/Keyword.java rename to api/src/main/java/io/github/sebastiantoepfer/jsonschema/keyword/Keyword.java index 9b4b9b15..40e55913 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/Keyword.java +++ b/api/src/main/java/io/github/sebastiantoepfer/jsonschema/keyword/Keyword.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.github.sebastiantoepfer.jsonschema.core.keyword; +package io.github.sebastiantoepfer.jsonschema.keyword; import java.util.Collection; diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/KeywordType.java b/api/src/main/java/io/github/sebastiantoepfer/jsonschema/keyword/KeywordType.java similarity index 95% rename from core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/KeywordType.java rename to api/src/main/java/io/github/sebastiantoepfer/jsonschema/keyword/KeywordType.java index 85f08a56..edb6a275 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/KeywordType.java +++ b/api/src/main/java/io/github/sebastiantoepfer/jsonschema/keyword/KeywordType.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.github.sebastiantoepfer.jsonschema.core.keyword; +package io.github.sebastiantoepfer.jsonschema.keyword; import jakarta.json.JsonValue; import java.util.Objects; diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/ReservedLocation.java b/api/src/main/java/io/github/sebastiantoepfer/jsonschema/keyword/ReservedLocation.java similarity index 96% rename from core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/ReservedLocation.java rename to api/src/main/java/io/github/sebastiantoepfer/jsonschema/keyword/ReservedLocation.java index fec1a07d..0f8956e8 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/ReservedLocation.java +++ b/api/src/main/java/io/github/sebastiantoepfer/jsonschema/keyword/ReservedLocation.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.github.sebastiantoepfer.jsonschema.core.keyword; +package io.github.sebastiantoepfer.jsonschema.keyword; import java.util.Collection; import java.util.Set; diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/spi/JsonSchemaFactory.java b/api/src/main/java/io/github/sebastiantoepfer/jsonschema/spi/JsonSchemaFactory.java similarity index 91% rename from core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/spi/JsonSchemaFactory.java rename to api/src/main/java/io/github/sebastiantoepfer/jsonschema/spi/JsonSchemaFactory.java index b0f1180d..81a0d245 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/spi/JsonSchemaFactory.java +++ b/api/src/main/java/io/github/sebastiantoepfer/jsonschema/spi/JsonSchemaFactory.java @@ -21,9 +21,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.github.sebastiantoepfer.jsonschema.core.spi; +package io.github.sebastiantoepfer.jsonschema.spi; -import io.github.sebastiantoepfer.jsonschema.core.JsonSchema; +import io.github.sebastiantoepfer.jsonschema.JsonSchema; import jakarta.json.JsonValue; public interface JsonSchemaFactory { diff --git a/api/src/main/java/module-info.java b/api/src/main/java/module-info.java new file mode 100644 index 00000000..9ead3edd --- /dev/null +++ b/api/src/main/java/module-info.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +module io.github.sebastiantoepfer.jsonschema { + exports io.github.sebastiantoepfer.jsonschema; + exports io.github.sebastiantoepfer.jsonschema.keyword; + exports io.github.sebastiantoepfer.jsonschema.spi; + + requires jakarta.json; +} diff --git a/api/src/test/java/io/github/sebastiantoepfer/jsonschema/FakeJsonSchemaFactory.java b/api/src/test/java/io/github/sebastiantoepfer/jsonschema/FakeJsonSchemaFactory.java new file mode 100644 index 00000000..c294fd20 --- /dev/null +++ b/api/src/test/java/io/github/sebastiantoepfer/jsonschema/FakeJsonSchemaFactory.java @@ -0,0 +1,45 @@ +/* + * 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; + +import io.github.sebastiantoepfer.jsonschema.spi.JsonSchemaFactory; +import jakarta.json.JsonValue; + +public final class FakeJsonSchemaFactory implements JsonSchemaFactory { + + @Override + public JsonSchema create(final JsonValue schema) { + return new JsonSchema() { + @Override + public Validator validator() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public JsonValue.ValueType getValueType() { + throw new UnsupportedOperationException("Not supported yet."); + } + }; + } +} diff --git a/api/src/test/java/io/github/sebastiantoepfer/jsonschema/InstanceTypeTest.java b/api/src/test/java/io/github/sebastiantoepfer/jsonschema/InstanceTypeTest.java new file mode 100644 index 00000000..7a45e2f4 --- /dev/null +++ b/api/src/test/java/io/github/sebastiantoepfer/jsonschema/InstanceTypeTest.java @@ -0,0 +1,75 @@ +/* + * 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; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +import jakarta.json.Json; +import jakarta.json.JsonValue; +import java.util.stream.Stream; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +class InstanceTypeTest { + + @ParameterizedTest + @MethodSource("provideWithValidCombinations") + void should_be_true_if_instancetype_is_correct(final InstanceType instanceType, final JsonValue value) { + assertThat(instanceType.isInstance(value), is(true)); + } + + static Stream provideWithValidCombinations() { + return Stream.of( + Arguments.of(InstanceType.NULL, JsonValue.NULL), + Arguments.of(InstanceType.BOOLEAN, JsonValue.FALSE), + Arguments.of(InstanceType.BOOLEAN, JsonValue.TRUE), + Arguments.of(InstanceType.OBJECT, JsonValue.EMPTY_JSON_OBJECT), + Arguments.of(InstanceType.ARRAY, JsonValue.EMPTY_JSON_ARRAY), + Arguments.of(InstanceType.NUMBER, Json.createValue(23L)), + Arguments.of(InstanceType.INTEGER, Json.createValue(23L)), + Arguments.of(InstanceType.INTEGER, Json.createValue(0.0)) + ); + } + + @ParameterizedTest + @MethodSource("provideWithInvalidCombinations") + void should_be_false_if_instancetype_is_correct(final InstanceType instanceType, final JsonValue value) { + assertThat(instanceType.isInstance(value), is(false)); + } + + static Stream provideWithInvalidCombinations() { + return Stream.of( + Arguments.of(InstanceType.NULL, JsonValue.TRUE), + Arguments.of(InstanceType.BOOLEAN, JsonValue.EMPTY_JSON_OBJECT), + Arguments.of(InstanceType.BOOLEAN, JsonValue.EMPTY_JSON_ARRAY), + Arguments.of(InstanceType.OBJECT, JsonValue.EMPTY_JSON_ARRAY), + Arguments.of(InstanceType.ARRAY, JsonValue.TRUE), + Arguments.of(InstanceType.NUMBER, Json.createValue("string")), + Arguments.of(InstanceType.INTEGER, Json.createValue(23.2)), + Arguments.of(InstanceType.INTEGER, Json.createValue("test")) + ); + } +} diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/impl/keyword/TypeTest.java b/api/src/test/java/io/github/sebastiantoepfer/jsonschema/JsonSchemasTest.java similarity index 77% rename from core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/impl/keyword/TypeTest.java rename to api/src/test/java/io/github/sebastiantoepfer/jsonschema/JsonSchemasTest.java index 500b1734..49d64128 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/impl/keyword/TypeTest.java +++ b/api/src/test/java/io/github/sebastiantoepfer/jsonschema/JsonSchemasTest.java @@ -21,23 +21,19 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.github.sebastiantoepfer.jsonschema.core.impl.keyword; +package io.github.sebastiantoepfer.jsonschema; 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 jakarta.json.Json; import org.junit.jupiter.api.Test; -class TypeTest { +class JsonSchemasTest { @Test - void should_know_his_name() { - assertThat(new Type(Json.createValue("string")).hasName("type"), is(true)); - } - - @Test - void should_know_other_names() { - assertThat(new Type(Json.createValue("string")).hasName("id"), is(false)); + void should_return_a_schema() { + assertThat(JsonSchemas.load("{}"), is(not(nullValue()))); } } diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/keyword/AnnotationTest.java b/api/src/test/java/io/github/sebastiantoepfer/jsonschema/keyword/AnnotationTest.java similarity index 97% rename from core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/keyword/AnnotationTest.java rename to api/src/test/java/io/github/sebastiantoepfer/jsonschema/keyword/AnnotationTest.java index e0967efc..a1998142 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/keyword/AnnotationTest.java +++ b/api/src/test/java/io/github/sebastiantoepfer/jsonschema/keyword/AnnotationTest.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.github.sebastiantoepfer.jsonschema.core.keyword; +package io.github.sebastiantoepfer.jsonschema.keyword; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/keyword/ApplicatorTest.java b/api/src/test/java/io/github/sebastiantoepfer/jsonschema/keyword/ApplicatorTest.java similarity index 97% rename from core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/keyword/ApplicatorTest.java rename to api/src/test/java/io/github/sebastiantoepfer/jsonschema/keyword/ApplicatorTest.java index 0d7b786e..85a2aabd 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/keyword/ApplicatorTest.java +++ b/api/src/test/java/io/github/sebastiantoepfer/jsonschema/keyword/ApplicatorTest.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.github.sebastiantoepfer.jsonschema.core.keyword; +package io.github.sebastiantoepfer.jsonschema.keyword; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/keyword/AssertionTest.java b/api/src/test/java/io/github/sebastiantoepfer/jsonschema/keyword/AssertionTest.java similarity index 97% rename from core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/keyword/AssertionTest.java rename to api/src/test/java/io/github/sebastiantoepfer/jsonschema/keyword/AssertionTest.java index 1a354692..63322eb5 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/keyword/AssertionTest.java +++ b/api/src/test/java/io/github/sebastiantoepfer/jsonschema/keyword/AssertionTest.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.github.sebastiantoepfer.jsonschema.core.keyword; +package io.github.sebastiantoepfer.jsonschema.keyword; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/keyword/DefaultAnnotationTest.java b/api/src/test/java/io/github/sebastiantoepfer/jsonschema/keyword/DefaultAnnotationTest.java similarity index 96% rename from core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/keyword/DefaultAnnotationTest.java rename to api/src/test/java/io/github/sebastiantoepfer/jsonschema/keyword/DefaultAnnotationTest.java index 753d1796..775cbb66 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/keyword/DefaultAnnotationTest.java +++ b/api/src/test/java/io/github/sebastiantoepfer/jsonschema/keyword/DefaultAnnotationTest.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.github.sebastiantoepfer.jsonschema.core.keyword; +package io.github.sebastiantoepfer.jsonschema.keyword; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/keyword/IdentifierTest.java b/api/src/test/java/io/github/sebastiantoepfer/jsonschema/keyword/IdentifierTest.java similarity index 94% rename from core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/keyword/IdentifierTest.java rename to api/src/test/java/io/github/sebastiantoepfer/jsonschema/keyword/IdentifierTest.java index cd492ea8..36085e82 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/keyword/IdentifierTest.java +++ b/api/src/test/java/io/github/sebastiantoepfer/jsonschema/keyword/IdentifierTest.java @@ -21,12 +21,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.github.sebastiantoepfer.jsonschema.core.keyword; +package io.github.sebastiantoepfer.jsonschema.keyword; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; -import io.github.sebastiantoepfer.jsonschema.core.keyword.Keyword.KeywordCategory; +import io.github.sebastiantoepfer.jsonschema.keyword.Keyword.KeywordCategory; import java.net.URI; import org.hamcrest.Matchers; import org.junit.jupiter.api.Test; diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/keyword/KeywordTypeTest.java b/api/src/test/java/io/github/sebastiantoepfer/jsonschema/keyword/KeywordTypeTest.java similarity index 96% rename from core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/keyword/KeywordTypeTest.java rename to api/src/test/java/io/github/sebastiantoepfer/jsonschema/keyword/KeywordTypeTest.java index 6a3d95df..028e7290 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/keyword/KeywordTypeTest.java +++ b/api/src/test/java/io/github/sebastiantoepfer/jsonschema/keyword/KeywordTypeTest.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.github.sebastiantoepfer.jsonschema.core.keyword; +package io.github.sebastiantoepfer.jsonschema.keyword; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/keyword/ReservedLocationTest.java b/api/src/test/java/io/github/sebastiantoepfer/jsonschema/keyword/ReservedLocationTest.java similarity index 97% rename from core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/keyword/ReservedLocationTest.java rename to api/src/test/java/io/github/sebastiantoepfer/jsonschema/keyword/ReservedLocationTest.java index a85dbc02..22cca4aa 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/keyword/ReservedLocationTest.java +++ b/api/src/test/java/io/github/sebastiantoepfer/jsonschema/keyword/ReservedLocationTest.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.github.sebastiantoepfer.jsonschema.core.keyword; +package io.github.sebastiantoepfer.jsonschema.keyword; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; diff --git a/api/src/test/resources/META-INF/services/io.github.sebastiantoepfer.jsonschema.spi.JsonSchemaFactory b/api/src/test/resources/META-INF/services/io.github.sebastiantoepfer.jsonschema.spi.JsonSchemaFactory new file mode 100644 index 00000000..78479819 --- /dev/null +++ b/api/src/test/resources/META-INF/services/io.github.sebastiantoepfer.jsonschema.spi.JsonSchemaFactory @@ -0,0 +1 @@ +io.github.sebastiantoepfer.jsonschema.FakeJsonSchemaFactory diff --git a/core/pom.xml b/core/pom.xml index 86e23439..2300dc22 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -14,14 +14,19 @@ - org.junit.jupiter - junit-jupiter-api - test + ${project.groupId} + json-schema-api + ${project.version} ${project.groupId} - json-schema-testsuite-junit-platform-engine + json-schema-vocabulary-spi ${project.version} + + + + org.junit.jupiter + junit-jupiter-api test @@ -29,6 +34,11 @@ junit-jupiter-engine test + + org.junit.jupiter + junit-jupiter-params + test + org.hamcrest @@ -46,6 +56,12 @@ jakarta.json-api provided + + + org.eclipse.parsson + parsson + test + @@ -104,6 +120,24 @@ + + + org.apache.maven.plugins + maven-surefire-plugin + + + run-jsonschema-testsuite + + test + + + + **/JsonTestSuiteIT.java + + + + + diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/spi/AbstractJsonValueSchema.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/AbstractJsonValueSchema.java similarity index 93% rename from core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/spi/AbstractJsonValueSchema.java rename to core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/AbstractJsonValueSchema.java index 2f92fa8c..09a7ea53 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/spi/AbstractJsonValueSchema.java +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/AbstractJsonValueSchema.java @@ -21,9 +21,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.github.sebastiantoepfer.jsonschema.core.impl.spi; +package io.github.sebastiantoepfer.jsonschema.core; -import io.github.sebastiantoepfer.jsonschema.core.JsonSchema; +import io.github.sebastiantoepfer.jsonschema.JsonSchema; import jakarta.json.JsonArray; import jakarta.json.JsonObject; import jakarta.json.JsonValue; diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/spi/DefaultJsonSchema.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/DefaultJsonSchema.java similarity index 61% rename from core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/spi/DefaultJsonSchema.java rename to core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/DefaultJsonSchema.java index 74790bab..ebe4f145 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/spi/DefaultJsonSchema.java +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/DefaultJsonSchema.java @@ -21,22 +21,28 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.github.sebastiantoepfer.jsonschema.core.impl.spi; +package io.github.sebastiantoepfer.jsonschema.core; import static java.util.stream.Collectors.collectingAndThen; import static java.util.stream.Collectors.toList; -import io.github.sebastiantoepfer.jsonschema.core.Validator; -import io.github.sebastiantoepfer.jsonschema.core.impl.constraint.AllOfConstraint; -import io.github.sebastiantoepfer.jsonschema.core.impl.constraint.Constraint; -import io.github.sebastiantoepfer.jsonschema.core.impl.keyword.Keywords; +import io.github.sebastiantoepfer.jsonschema.Validator; +import io.github.sebastiantoepfer.jsonschema.core.constraint.AllOfConstraint; +import io.github.sebastiantoepfer.jsonschema.core.constraint.Constraint; +import io.github.sebastiantoepfer.jsonschema.core.vocab.core.VocabularyKeywordType; +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.util.Collection; -public final class DefaultJsonSchema extends AbstractJsonValueSchema { +final class DefaultJsonSchema extends AbstractJsonValueSchema { + + private final Keywords keywords; public DefaultJsonSchema(final JsonObject value) { super(value); + keywords = new Keywords(vocabulary()); } @Override @@ -44,11 +50,21 @@ public Validator validator() { return asJsonObject() .entrySet() .stream() - .map(Keywords::createKeywordFor) + .map(keywords::createKeywordFor) .filter(Constraint.class::isInstance) .map(k -> (Constraint) k) .collect( collectingAndThen(toList(), constraints -> new DefaultValidator(new AllOfConstraint<>(constraints))) ); } + + private Collection vocabulary() { + return new KeywordSearch(new VocabularyKeywordType()) + .searchForKeywordIn(asJsonObject()) + .filter(VocabularyDefinitions.class::isInstance) + .map(VocabularyDefinitions.class::cast) + .stream() + .flatMap(VocabularyDefinitions::definitions) + .toList(); + } } diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/spi/DefaultJsonSchemaFactory.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/DefaultJsonSchemaFactory.java similarity index 89% rename from core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/spi/DefaultJsonSchemaFactory.java rename to core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/DefaultJsonSchemaFactory.java index 5b8ea7d5..49bf94c9 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/spi/DefaultJsonSchemaFactory.java +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/DefaultJsonSchemaFactory.java @@ -21,10 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.github.sebastiantoepfer.jsonschema.core.impl.spi; +package io.github.sebastiantoepfer.jsonschema.core; -import io.github.sebastiantoepfer.jsonschema.core.JsonSchema; -import io.github.sebastiantoepfer.jsonschema.core.spi.JsonSchemaFactory; +import io.github.sebastiantoepfer.jsonschema.JsonSchema; +import io.github.sebastiantoepfer.jsonschema.spi.JsonSchemaFactory; import jakarta.json.JsonValue; public final class DefaultJsonSchemaFactory implements JsonSchemaFactory { diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/spi/DefaultValidator.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/DefaultValidator.java similarity index 85% rename from core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/spi/DefaultValidator.java rename to core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/DefaultValidator.java index 61890a42..62d35a2e 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/spi/DefaultValidator.java +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/DefaultValidator.java @@ -21,11 +21,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.github.sebastiantoepfer.jsonschema.core.impl.spi; +package io.github.sebastiantoepfer.jsonschema.core; -import io.github.sebastiantoepfer.jsonschema.core.ConstraintViolation; -import io.github.sebastiantoepfer.jsonschema.core.Validator; -import io.github.sebastiantoepfer.jsonschema.core.impl.constraint.Constraint; +import io.github.sebastiantoepfer.jsonschema.ConstraintViolation; +import io.github.sebastiantoepfer.jsonschema.Validator; +import io.github.sebastiantoepfer.jsonschema.core.constraint.Constraint; import jakarta.json.JsonValue; import java.util.Collection; import java.util.Objects; diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/spi/EmptyJsonSchema.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/EmptyJsonSchema.java similarity index 87% rename from core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/spi/EmptyJsonSchema.java rename to core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/EmptyJsonSchema.java index 8db7d282..17a2e73b 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/spi/EmptyJsonSchema.java +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/EmptyJsonSchema.java @@ -21,10 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.github.sebastiantoepfer.jsonschema.core.impl.spi; +package io.github.sebastiantoepfer.jsonschema.core; -import io.github.sebastiantoepfer.jsonschema.core.Validator; -import io.github.sebastiantoepfer.jsonschema.core.impl.constraint.NoConstraint; +import io.github.sebastiantoepfer.jsonschema.Validator; +import io.github.sebastiantoepfer.jsonschema.core.constraint.NoConstraint; import jakarta.json.JsonValue; final class EmptyJsonSchema extends AbstractJsonValueSchema { diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/spi/FalseJsonSchema.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/FalseJsonSchema.java similarity index 87% rename from core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/spi/FalseJsonSchema.java rename to core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/FalseJsonSchema.java index 48b4eaa8..eee71fe6 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/spi/FalseJsonSchema.java +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/FalseJsonSchema.java @@ -21,10 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.github.sebastiantoepfer.jsonschema.core.impl.spi; +package io.github.sebastiantoepfer.jsonschema.core; -import io.github.sebastiantoepfer.jsonschema.core.Validator; -import io.github.sebastiantoepfer.jsonschema.core.impl.constraint.UnfulfillableConstraint; +import io.github.sebastiantoepfer.jsonschema.Validator; +import io.github.sebastiantoepfer.jsonschema.core.constraint.UnfulfillableConstraint; import jakarta.json.JsonValue; final class FalseJsonSchema extends AbstractJsonValueSchema { diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/KeywordSearch.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/KeywordSearch.java new file mode 100644 index 00000000..5c5c9325 --- /dev/null +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/KeywordSearch.java @@ -0,0 +1,43 @@ +/* + * 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; + +import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; +import io.github.sebastiantoepfer.jsonschema.keyword.KeywordType; +import jakarta.json.JsonObject; +import java.util.Objects; +import java.util.Optional; + +final class KeywordSearch { + + private final KeywordType keywordType; + + public KeywordSearch(final KeywordType keywordType) { + this.keywordType = Objects.requireNonNull(keywordType); + } + + public Optional searchForKeywordIn(final JsonObject schema) { + return Optional.ofNullable(schema.get(keywordType.name())).map(keywordType::createKeyword); + } +} 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 new file mode 100644 index 00000000..eb8a6d2d --- /dev/null +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/Keywords.java @@ -0,0 +1,92 @@ +/* + * 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; + +import static java.util.function.Predicate.not; +import static java.util.stream.Collectors.toMap; + +import io.github.sebastiantoepfer.jsonschema.Vocabulary; +import io.github.sebastiantoepfer.jsonschema.core.vocab.basic.BasicVocabulary; +import io.github.sebastiantoepfer.jsonschema.core.vocab.core.CoreVocabulary; +import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; +import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.VocabularyDefinition; +import jakarta.json.JsonValue; +import java.net.URI; +import java.util.ArrayDeque; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.Function; +import java.util.stream.Collector; +import java.util.stream.Stream; + +final class Keywords { + + private static final Map MANDANTORY_VOCABS; + + static { + MANDANTORY_VOCABS = + List + .of(new BasicVocabulary(), new CoreVocabulary()) + .stream() + .collect(toMap(Vocabulary::id, Function.identity())); + } + + private final Collection vocabularies; + + public Keywords(final Collection vocabDefs) { + if ( + vocabDefs + .stream() + .filter(vocabDef -> MANDANTORY_VOCABS.containsKey(vocabDef.id())) + .anyMatch(not(VocabularyDefinition::required)) + ) { + throw new IllegalArgumentException("can not be created without core vocabulary is requiered!"); + } + vocabularies = + Stream + .concat( + MANDANTORY_VOCABS.values().stream(), + vocabDefs.stream().map(VocabularyDefinition::findVocabulary).flatMap(Optional::stream) + ) + .collect( + Collector.of( + ArrayDeque::new, + ArrayDeque::addFirst, + (first, last) -> null //pitest otherwise see mutants here :( + ) + ); + } + + public Keyword createKeywordFor(final Map.Entry property) { + return vocabularies + .stream() + .map(vocab -> vocab.findKeywordTypeByName(property.getKey())) + .flatMap(Optional::stream) + .findFirst() + .map(keywordType -> keywordType.createKeyword(property.getValue())) + .orElseThrow(); + } +} diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/spi/TrueJsonSchema.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/TrueJsonSchema.java similarity index 87% rename from core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/spi/TrueJsonSchema.java rename to core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/TrueJsonSchema.java index aae77a7e..8cc4b777 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/spi/TrueJsonSchema.java +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/TrueJsonSchema.java @@ -21,10 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.github.sebastiantoepfer.jsonschema.core.impl.spi; +package io.github.sebastiantoepfer.jsonschema.core; -import io.github.sebastiantoepfer.jsonschema.core.Validator; -import io.github.sebastiantoepfer.jsonschema.core.impl.constraint.NoConstraint; +import io.github.sebastiantoepfer.jsonschema.Validator; +import io.github.sebastiantoepfer.jsonschema.core.constraint.NoConstraint; import jakarta.json.JsonValue; final class TrueJsonSchema extends AbstractJsonValueSchema { diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/constraint/AllOfConstraint.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/constraint/AllOfConstraint.java similarity index 93% rename from core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/constraint/AllOfConstraint.java rename to core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/constraint/AllOfConstraint.java index 9f661b0c..657b557a 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/constraint/AllOfConstraint.java +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/constraint/AllOfConstraint.java @@ -21,12 +21,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.github.sebastiantoepfer.jsonschema.core.impl.constraint; +package io.github.sebastiantoepfer.jsonschema.core.constraint; import static java.util.Arrays.asList; import static java.util.function.Predicate.not; -import io.github.sebastiantoepfer.jsonschema.core.ConstraintViolation; +import io.github.sebastiantoepfer.jsonschema.ConstraintViolation; import java.util.Collection; import java.util.List; import java.util.Set; diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/constraint/AnyConstraint.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/constraint/AnyConstraint.java similarity index 94% rename from core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/constraint/AnyConstraint.java rename to core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/constraint/AnyConstraint.java index cdf54e83..e4454126 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/constraint/AnyConstraint.java +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/constraint/AnyConstraint.java @@ -21,12 +21,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.github.sebastiantoepfer.jsonschema.core.impl.constraint; +package io.github.sebastiantoepfer.jsonschema.core.constraint; import static java.util.Arrays.asList; import static java.util.stream.Collectors.toSet; -import io.github.sebastiantoepfer.jsonschema.core.ConstraintViolation; +import io.github.sebastiantoepfer.jsonschema.ConstraintViolation; import java.util.Collection; import java.util.List; import java.util.Set; diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/constraint/Constraint.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/constraint/Constraint.java similarity index 90% rename from core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/constraint/Constraint.java rename to core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/constraint/Constraint.java index 291d6b25..18bc877f 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/constraint/Constraint.java +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/constraint/Constraint.java @@ -21,9 +21,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.github.sebastiantoepfer.jsonschema.core.impl.constraint; +package io.github.sebastiantoepfer.jsonschema.core.constraint; -import io.github.sebastiantoepfer.jsonschema.core.ConstraintViolation; +import io.github.sebastiantoepfer.jsonschema.ConstraintViolation; import java.util.Collection; public interface Constraint { diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/constraint/NoConstraint.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/constraint/NoConstraint.java similarity index 90% rename from core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/constraint/NoConstraint.java rename to core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/constraint/NoConstraint.java index f3aebcf1..1c0ffc7d 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/constraint/NoConstraint.java +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/constraint/NoConstraint.java @@ -21,9 +21,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.github.sebastiantoepfer.jsonschema.core.impl.constraint; +package io.github.sebastiantoepfer.jsonschema.core.constraint; -import io.github.sebastiantoepfer.jsonschema.core.ConstraintViolation; +import io.github.sebastiantoepfer.jsonschema.ConstraintViolation; import java.util.Collection; import java.util.Set; diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/constraint/UnfulfillableConstraint.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/constraint/UnfulfillableConstraint.java similarity index 90% rename from core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/constraint/UnfulfillableConstraint.java rename to core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/constraint/UnfulfillableConstraint.java index f351d498..78f27e04 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/constraint/UnfulfillableConstraint.java +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/constraint/UnfulfillableConstraint.java @@ -21,9 +21,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.github.sebastiantoepfer.jsonschema.core.impl.constraint; +package io.github.sebastiantoepfer.jsonschema.core.constraint; -import io.github.sebastiantoepfer.jsonschema.core.ConstraintViolation; +import io.github.sebastiantoepfer.jsonschema.ConstraintViolation; import java.util.Collection; import java.util.Set; diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/keyword/Type.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/keyword/Type.java deleted file mode 100644 index 2fa13a7d..00000000 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/keyword/Type.java +++ /dev/null @@ -1,119 +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.impl.keyword; - -import static java.util.stream.Collectors.collectingAndThen; -import static java.util.stream.Collectors.toList; - -import io.github.sebastiantoepfer.jsonschema.core.ConstraintViolation; -import io.github.sebastiantoepfer.jsonschema.core.InstanceType; -import io.github.sebastiantoepfer.jsonschema.core.impl.constraint.AnyConstraint; -import io.github.sebastiantoepfer.jsonschema.core.impl.constraint.Constraint; -import jakarta.json.JsonArray; -import jakarta.json.JsonString; -import jakarta.json.JsonValue; -import java.util.Collection; -import java.util.Locale; -import java.util.Objects; -import java.util.Set; - -/** - * see: https://json-schema.org/understanding-json-schema/reference/type.html - */ -final class Type implements ConstraintAssertion, Constraint { - - private final JsonValue definition; - - public Type(final JsonValue definition) { - this.definition = Objects.requireNonNull(definition); - } - - @Override - public boolean hasName(final String name) { - return Objects.equals("type", name); - } - - @Override - public Collection violationsBy(final JsonValue value) { - return new JsonMappedTypeConstaint(definition).violationsBy(value); - } - - private static final class JsonMappedTypeConstaint implements Constraint { - - private final JsonValue definition; - - public JsonMappedTypeConstaint(final JsonValue definition) { - this.definition = Objects.requireNonNull(definition); - } - - @Override - public Collection violationsBy(final JsonValue value) { - final Constraint typeContraint = - switch (definition.getValueType()) { - case STRING -> new JsonStringTypeConstraint((JsonString) definition); - default -> new JsonArrayTypeConstraint(definition.asJsonArray()); - }; - return typeContraint.violationsBy(value); - } - } - - private static final class JsonArrayTypeConstraint implements Constraint { - - private final JsonArray types; - - public JsonArrayTypeConstraint(final JsonArray types) { - this.types = Objects.requireNonNull(types); - } - - @Override - public Collection violationsBy(final JsonValue value) { - return types - .stream() - .map(JsonMappedTypeConstaint::new) - .collect(collectingAndThen(toList(), AnyConstraint::new)) - .violationsBy(value); - } - } - - private static final class JsonStringTypeConstraint implements Constraint { - - private final String type; - - public JsonStringTypeConstraint(final JsonString type) { - this.type = Objects.requireNonNull(type).getString().toUpperCase(Locale.US); - } - - @Override - public Collection violationsBy(final JsonValue value) { - final InstanceType instanceType = InstanceType.valueOf(type); - final Collection result; - if (instanceType.isInstance(value)) { - result = Set.of(); - } else { - result = Set.of(new ConstraintViolation()); - } - return result; - } - } -} diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/keyword/ConstraintAssertion.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/ConstraintAssertion.java similarity index 82% rename from core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/keyword/ConstraintAssertion.java rename to core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/ConstraintAssertion.java index 14e75640..8c01a472 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/keyword/ConstraintAssertion.java +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/ConstraintAssertion.java @@ -21,16 +21,16 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.github.sebastiantoepfer.jsonschema.core.impl.keyword; +package io.github.sebastiantoepfer.jsonschema.core.vocab; -import io.github.sebastiantoepfer.jsonschema.core.impl.constraint.Constraint; -import io.github.sebastiantoepfer.jsonschema.core.keyword.Assertion; +import io.github.sebastiantoepfer.jsonschema.core.constraint.Constraint; +import io.github.sebastiantoepfer.jsonschema.keyword.Assertion; import jakarta.json.JsonValue; /** * only simplify pitest :) */ -interface ConstraintAssertion extends Assertion, Constraint { +public interface ConstraintAssertion extends Assertion, Constraint { @Override default boolean isValidFor(JsonValue instance) { return violationsBy(instance).isEmpty(); diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/keyword/BasicVocabulary.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/basic/BasicVocabulary.java similarity index 52% rename from core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/keyword/BasicVocabulary.java rename to core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/basic/BasicVocabulary.java index d5fd1c35..decce0b8 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/keyword/BasicVocabulary.java +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/basic/BasicVocabulary.java @@ -21,17 +21,14 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.github.sebastiantoepfer.jsonschema.core.impl.keyword; +package io.github.sebastiantoepfer.jsonschema.core.vocab.basic; -import io.github.sebastiantoepfer.jsonschema.core.Vocabulary; -import io.github.sebastiantoepfer.jsonschema.core.keyword.DefaultAnnotation; -import io.github.sebastiantoepfer.jsonschema.core.keyword.Keyword; -import io.github.sebastiantoepfer.jsonschema.core.keyword.KeywordType; -import jakarta.json.JsonValue; +import io.github.sebastiantoepfer.jsonschema.Vocabulary; +import io.github.sebastiantoepfer.jsonschema.keyword.KeywordType; import java.net.URI; import java.util.Optional; -final class BasicVocabulary implements Vocabulary { +public final class BasicVocabulary implements Vocabulary { @Override public URI id() { @@ -40,31 +37,11 @@ public URI id() { @Override public Optional findKeywordTypeByName(final String name) { - KeywordType keywordType = + return Optional.of( switch (name) { - case "type" -> new KeywordType() { - @Override - public String name() { - return "type"; - } - - @Override - public Keyword createKeyword(final JsonValue value) { - return new Type(value); - } - }; - default -> new KeywordType() { - @Override - public String name() { - return name; - } - - @Override - public Keyword createKeyword(final JsonValue value) { - return new DefaultAnnotation(name(), value); - } - }; - }; - return Optional.of(keywordType); + case "type" -> new TypeKeywordType(); + default -> new UnknowKeywordType(name); + } + ); } } diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/basic/TypeKeywordType.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/basic/TypeKeywordType.java new file mode 100644 index 00000000..c3ef73f4 --- /dev/null +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/basic/TypeKeywordType.java @@ -0,0 +1,135 @@ +/* + * 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 java.util.stream.Collectors.collectingAndThen; +import static java.util.stream.Collectors.toList; + +import io.github.sebastiantoepfer.jsonschema.ConstraintViolation; +import io.github.sebastiantoepfer.jsonschema.InstanceType; +import io.github.sebastiantoepfer.jsonschema.core.constraint.AnyConstraint; +import io.github.sebastiantoepfer.jsonschema.core.constraint.Constraint; +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.JsonString; +import jakarta.json.JsonValue; +import java.util.Collection; +import java.util.Locale; +import java.util.Objects; +import java.util.Set; + +/** + * see: https://json-schema.org/understanding-json-schema/reference/type.html + */ +final class TypeKeywordType implements KeywordType { + + @Override + public String name() { + return "type"; + } + + @Override + public Keyword createKeyword(final JsonValue value) { + return new TypeKeyword(value); + } + + private final class TypeKeyword implements ConstraintAssertion, Constraint { + + private final JsonValue definition; + + public TypeKeyword(final JsonValue definition) { + this.definition = Objects.requireNonNull(definition); + } + + @Override + public boolean hasName(final String name) { + return Objects.equals(name(), name); + } + + @Override + public Collection violationsBy(final JsonValue value) { + return new JsonMappedTypeConstaint(definition).violationsBy(value); + } + + private static final class JsonMappedTypeConstaint implements Constraint { + + private final JsonValue definition; + + public JsonMappedTypeConstaint(final JsonValue definition) { + this.definition = Objects.requireNonNull(definition); + } + + @Override + public Collection violationsBy(final JsonValue value) { + final Constraint typeContraint = + switch (definition.getValueType()) { + case STRING -> new JsonStringTypeConstraint((JsonString) definition); + default -> new JsonArrayTypeConstraint(definition.asJsonArray()); + }; + return typeContraint.violationsBy(value); + } + } + + private static final class JsonArrayTypeConstraint implements Constraint { + + private final JsonArray types; + + public JsonArrayTypeConstraint(final JsonArray types) { + this.types = Objects.requireNonNull(types); + } + + @Override + public Collection violationsBy(final JsonValue value) { + return types + .stream() + .map(JsonMappedTypeConstaint::new) + .collect(collectingAndThen(toList(), AnyConstraint::new)) + .violationsBy(value); + } + } + + private static final class JsonStringTypeConstraint implements Constraint { + + private final String type; + + public JsonStringTypeConstraint(final JsonString type) { + this.type = Objects.requireNonNull(type).getString().toUpperCase(Locale.US); + } + + @Override + public Collection violationsBy(final JsonValue value) { + final InstanceType instanceType = InstanceType.valueOf(type); + final Collection result; + if (instanceType.isInstance(value)) { + result = Set.of(); + } else { + result = Set.of(new ConstraintViolation()); + } + return result; + } + } + } +} diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/basic/UnknowKeywordType.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/basic/UnknowKeywordType.java new file mode 100644 index 00000000..d3d86476 --- /dev/null +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/basic/UnknowKeywordType.java @@ -0,0 +1,49 @@ +/* + * 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.keyword.DefaultAnnotation; +import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; +import io.github.sebastiantoepfer.jsonschema.keyword.KeywordType; +import jakarta.json.JsonValue; +import java.util.Objects; + +final class UnknowKeywordType implements KeywordType { + + private final String name; + + public UnknowKeywordType(final String name) { + this.name = Objects.requireNonNull(name); + } + + @Override + public String name() { + return name; + } + + @Override + public Keyword createKeyword(final JsonValue value) { + return new DefaultAnnotation(name(), value); + } +} diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/CommentKeywordType.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/CommentKeywordType.java new file mode 100644 index 00000000..985f2922 --- /dev/null +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/CommentKeywordType.java @@ -0,0 +1,46 @@ +/* + * 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 io.github.sebastiantoepfer.jsonschema.keyword.DefaultAnnotation; +import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; +import io.github.sebastiantoepfer.jsonschema.keyword.KeywordType; +import jakarta.json.JsonValue; + +/** + * + * see: https://json-schema.org/draft/2020-12/json-schema-core.html#name-comments-with-comment + */ +final class CommentKeywordType implements KeywordType { + + @Override + public String name() { + return "$comment"; + } + + @Override + public Keyword createKeyword(final JsonValue value) { + return new DefaultAnnotation(name(), value); + } +} 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 new file mode 100644 index 00000000..33b7477e --- /dev/null +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/CoreVocabulary.java @@ -0,0 +1,58 @@ +/* + * 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 io.github.sebastiantoepfer.jsonschema.Vocabulary; +import io.github.sebastiantoepfer.jsonschema.keyword.KeywordType; +import java.net.URI; +import java.util.Collection; +import java.util.List; +import java.util.Optional; + +/** + * see: https://json-schema.org/draft/2020-12/json-schema-core.html#name-the-json-schema-core-vocabu + */ +public final class CoreVocabulary implements Vocabulary { + + private Collection supportedKeywords = List.of( + new SchemaKeywordType(), + new VocabularyKeywordType(), + new IdKeywordType(), + new RefKeywordType(), + new DynamicRefKeywordType(), + new DefsKeywordType(), + new CommentKeywordType() + ); + + @Override + public URI id() { + //we need a way to find out which draft we are using! + return URI.create("https://json-schema.org/draft/2020-12/vocab/core"); + } + + @Override + public Optional findKeywordTypeByName(final String name) { + return supportedKeywords.stream().filter(keywordType -> keywordType.hasName(name)).findFirst(); + } +} diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/DefsKeywordType.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/DefsKeywordType.java new file mode 100644 index 00000000..ed4e0d33 --- /dev/null +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/DefsKeywordType.java @@ -0,0 +1,46 @@ +/* + * 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 io.github.sebastiantoepfer.jsonschema.keyword.DefaultAnnotation; +import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; +import io.github.sebastiantoepfer.jsonschema.keyword.KeywordType; +import jakarta.json.JsonValue; + +/** + * + * see: https://json-schema.org/draft/2020-12/json-schema-core.html#name-schema-re-use-with-defs + */ +final class DefsKeywordType implements KeywordType { + + @Override + public String name() { + return "$defs"; + } + + @Override + public Keyword createKeyword(final JsonValue value) { + return new DefaultAnnotation(name(), value); + } +} diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/DynamicRefKeywordType.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/DynamicRefKeywordType.java new file mode 100644 index 00000000..390c58b4 --- /dev/null +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/DynamicRefKeywordType.java @@ -0,0 +1,58 @@ +/* + * 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 io.github.sebastiantoepfer.jsonschema.keyword.Applicator; +import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; +import io.github.sebastiantoepfer.jsonschema.keyword.KeywordType; +import jakarta.json.JsonValue; +import java.util.Objects; + +/** + * + * see: https://json-schema.org/draft/2020-12/json-schema-core.html#name-dynamic-references-with-dyn + */ +final class DynamicRefKeywordType implements KeywordType { + + @Override + public String name() { + return "$dynamicRef"; + } + + @Override + public Keyword createKeyword(final JsonValue value) { + return new Applicator() { + @Override + public boolean applyTo(final JsonValue instance) { + //something is wrong here + return true; + } + + @Override + public boolean hasName(final String name) { + return Objects.equals(name(), name); + } + }; + } +} diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/IdKeywordType.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/IdKeywordType.java new file mode 100644 index 00000000..6bf3fa21 --- /dev/null +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/IdKeywordType.java @@ -0,0 +1,46 @@ +/* + * 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 io.github.sebastiantoepfer.jsonschema.keyword.DefaultAnnotation; +import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; +import io.github.sebastiantoepfer.jsonschema.keyword.KeywordType; +import jakarta.json.JsonValue; + +/** + * + * see: https://json-schema.org/draft/2020-12/json-schema-core.html#name-the-id-keyword + */ +final class IdKeywordType implements KeywordType { + + @Override + public String name() { + return "$id"; + } + + @Override + public Keyword createKeyword(final JsonValue value) { + return new DefaultAnnotation(name(), value); + } +} diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/LazyCoreVocabulary.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/LazyCoreVocabulary.java new file mode 100644 index 00000000..82edca2e --- /dev/null +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/LazyCoreVocabulary.java @@ -0,0 +1,50 @@ +/* + * 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 io.github.sebastiantoepfer.jsonschema.Vocabulary; +import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.LazyVocabularies; +import java.net.URI; +import java.util.Objects; +import java.util.Optional; + +public final class LazyCoreVocabulary implements LazyVocabularies { + + private final Vocabulary vocab; + + public LazyCoreVocabulary() { + this.vocab = new CoreVocabulary(); + } + + @Override + public Optional loadVocabularyWithId(final URI id) { + final Optional result; + if (Objects.equals(id, vocab.id())) { + result = Optional.of(vocab); + } else { + result = Optional.empty(); + } + return result; + } +} 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 new file mode 100644 index 00000000..b59ba3a6 --- /dev/null +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/RefKeywordType.java @@ -0,0 +1,57 @@ +/* + * 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 io.github.sebastiantoepfer.jsonschema.keyword.Applicator; +import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; +import io.github.sebastiantoepfer.jsonschema.keyword.KeywordType; +import jakarta.json.JsonValue; +import java.util.Objects; + +/** + * + * see: https://json-schema.org/draft/2020-12/json-schema-core.html#name-direct-references-with-ref + */ +final class RefKeywordType implements KeywordType { + + @Override + public String name() { + return "$ref"; + } + + @Override + public Keyword createKeyword(final JsonValue value) { + return new Applicator() { + @Override + public boolean applyTo(final JsonValue instance) { + return true; //something is wrong here + } + + @Override + public boolean hasName(final String name) { + return Objects.equals(name(), name); + } + }; + } +} diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/SchemaKeywordType.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/SchemaKeywordType.java new file mode 100644 index 00000000..926ec37c --- /dev/null +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/SchemaKeywordType.java @@ -0,0 +1,46 @@ +/* + * 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 io.github.sebastiantoepfer.jsonschema.keyword.DefaultAnnotation; +import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; +import io.github.sebastiantoepfer.jsonschema.keyword.KeywordType; +import jakarta.json.JsonValue; + +/** + * + * see: https://json-schema.org/draft/2020-12/json-schema-core.html#name-the-schema-keyword + */ +final class SchemaKeywordType implements KeywordType { + + @Override + public String name() { + return "$schema"; + } + + @Override + public Keyword createKeyword(final JsonValue value) { + return new DefaultAnnotation(name(), value); + } +} 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 new file mode 100644 index 00000000..2ff582e8 --- /dev/null +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/VocabularyKeywordType.java @@ -0,0 +1,94 @@ +/* + * 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 io.github.sebastiantoepfer.jsonschema.InstanceType; +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.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 { + + @Override + public String name() { + return "$vocabulary"; + } + + @Override + public Keyword createKeyword(final JsonValue value) { + final Keyword result; + if (InstanceType.OBJECT.isInstance(value)) { + result = new VocabularyKeyword(value); + } else { + throw new IllegalArgumentException( + "must be an object! " + + "read https://json-schema.org/draft/2020-12/json-schema-core.html#name-the-vocabulary-keyword" + + "for more infromations" + ); + } + return result; + } + + 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 Collection categories() { + return List.of(); + } + + @Override + public boolean hasName(final String name) { + return Objects.equals(name(), name); + } + + @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/module-info.java b/core/src/main/java/module-info.java index 99eafb82..1bcda2e5 100644 --- a/core/src/main/java/module-info.java +++ b/core/src/main/java/module-info.java @@ -22,8 +22,13 @@ * THE SOFTWARE. */ module io.github.sebastiantoepfer.jsonschema.core { - exports io.github.sebastiantoepfer.jsonschema.core; - exports io.github.sebastiantoepfer.jsonschema.core.keyword; - + requires io.github.sebastiantoepfer.jsonschema; + requires io.github.sebastiantoepfer.jsonschema.vocabulary.spi; requires jakarta.json; + + provides io.github.sebastiantoepfer.jsonschema.spi.JsonSchemaFactory + with io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory; + + provides io.github.sebastiantoepfer.jsonschema.vocabulary.spi.LazyVocabularies + with io.github.sebastiantoepfer.jsonschema.core.vocab.core.LazyCoreVocabulary; } diff --git a/core/src/main/resources/META-INF/services/io.github.sebastiantoepfer.jsonschema.core.spi.JsonSchemaFactory b/core/src/main/resources/META-INF/services/io.github.sebastiantoepfer.jsonschema.core.spi.JsonSchemaFactory deleted file mode 100644 index b2dd1495..00000000 --- a/core/src/main/resources/META-INF/services/io.github.sebastiantoepfer.jsonschema.core.spi.JsonSchemaFactory +++ /dev/null @@ -1 +0,0 @@ -io.github.sebastiantoepfer.jsonschema.core.impl.spi.DefaultJsonSchemaFactory diff --git a/core/src/main/resources/META-INF/services/io.github.sebastiantoepfer.jsonschema.spi.JsonSchemaFactory b/core/src/main/resources/META-INF/services/io.github.sebastiantoepfer.jsonschema.spi.JsonSchemaFactory new file mode 100644 index 00000000..f38f8f8b --- /dev/null +++ b/core/src/main/resources/META-INF/services/io.github.sebastiantoepfer.jsonschema.spi.JsonSchemaFactory @@ -0,0 +1 @@ +io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory diff --git a/core/src/main/resources/META-INF/services/io.github.sebastiantoepfer.jsonschema.vocabulary.spi.LazyVocabularies b/core/src/main/resources/META-INF/services/io.github.sebastiantoepfer.jsonschema.vocabulary.spi.LazyVocabularies new file mode 100644 index 00000000..68cddf8a --- /dev/null +++ b/core/src/main/resources/META-INF/services/io.github.sebastiantoepfer.jsonschema.vocabulary.spi.LazyVocabularies @@ -0,0 +1 @@ +io.github.sebastiantoepfer.jsonschema.core.vocab.core.LazyCoreVocabulary diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/impl/spi/AbstractJsonValueSchemaTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/AbstractJsonValueSchemaTest.java similarity index 88% rename from core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/impl/spi/AbstractJsonValueSchemaTest.java rename to core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/AbstractJsonValueSchemaTest.java index 7b31aff2..b660641b 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/impl/spi/AbstractJsonValueSchemaTest.java +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/AbstractJsonValueSchemaTest.java @@ -21,14 +21,13 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.github.sebastiantoepfer.jsonschema.core.impl.spi; +package io.github.sebastiantoepfer.jsonschema.core; -import static org.hamcrest.CoreMatchers.instanceOf; -import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.is; -import io.github.sebastiantoepfer.jsonschema.core.Validator; -import io.github.sebastiantoepfer.jsonschema.core.impl.spi.AbstractJsonValueSchema; +import io.github.sebastiantoepfer.jsonschema.Validator; import jakarta.json.JsonArray; import jakarta.json.JsonObject; import jakarta.json.JsonValue; diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/DefaultJsonSchemaFactoryTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/DefaultJsonSchemaFactoryTest.java new file mode 100644 index 00000000..bab69f66 --- /dev/null +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/DefaultJsonSchemaFactoryTest.java @@ -0,0 +1,61 @@ +/* + * 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; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.is; + +import jakarta.json.Json; +import jakarta.json.JsonValue; +import org.junit.jupiter.api.Test; + +class DefaultJsonSchemaFactoryTest { + + @Test + void should_return_truejsonschema_for_true() { + assertThat(new DefaultJsonSchemaFactory().create(JsonValue.TRUE), is(instanceOf(TrueJsonSchema.class))); + } + + @Test + void should_return_truejsonschema_for_false() { + assertThat(new DefaultJsonSchemaFactory().create(JsonValue.FALSE), is(instanceOf(FalseJsonSchema.class))); + } + + @Test + void should_return_emptyjsonschema_for_emptyobject() { + assertThat( + new DefaultJsonSchemaFactory().create(JsonValue.EMPTY_JSON_OBJECT), + is(instanceOf(EmptyJsonSchema.class)) + ); + } + + @Test + void should_return_defaultjsonschema_for_everything_else() { + assertThat( + new DefaultJsonSchemaFactory().create(Json.createObjectBuilder().add("type", "string").build()), + is(instanceOf(DefaultJsonSchema.class)) + ); + } +} diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/DefaultJsonSchemaTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/DefaultJsonSchemaTest.java new file mode 100644 index 00000000..e0e3ac5b --- /dev/null +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/DefaultJsonSchemaTest.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; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.empty; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; + +import jakarta.json.Json; +import jakarta.json.JsonObject; +import jakarta.json.JsonValue; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +class DefaultJsonSchemaTest { + + private final DefaultJsonSchema schema = new DefaultJsonSchema( + Json.createObjectBuilder().add("type", "string").build() + ); + + @Test + void should_be_valid_for_string() { + assertThat(schema.validator().validate(Json.createValue("test")), is(empty())); + } + + @Test + void should_be_invalid_for_object() { + assertThat(schema.validator().validate(JsonValue.EMPTY_JSON_OBJECT), is(not(empty()))); + } + + @Test + void should_not_be_loadable_without_mandantory_core_vocabulary() { + final JsonObject invalidSchema = Json + .createObjectBuilder() + .add( + "$vocabulary", + Json.createObjectBuilder().add("https://json-schema.org/draft/2020-12/vocab/core", false) + ) + .build(); + + Assertions.assertThrows(Exception.class, () -> new DefaultJsonSchema(invalidSchema)); + } +} 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 new file mode 100644 index 00000000..657e981b --- /dev/null +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/EmptyJsonSchemaTest.java @@ -0,0 +1,41 @@ +/* + * 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; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.empty; +import static org.hamcrest.Matchers.is; + +import jakarta.json.JsonValue; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ArgumentsSource; + +class EmptyJsonSchemaTest { + + @ParameterizedTest + @ArgumentsSource(JsonValuesArguments.class) + void should_be_valid_for_everything(final JsonValue value) { + assertThat(new EmptyJsonSchema().validator().validate(value), is(empty())); + } +} 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 new file mode 100644 index 00000000..9819fcf6 --- /dev/null +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/FalseJsonSchemaTest.java @@ -0,0 +1,42 @@ +/* + * 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; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.empty; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; + +import jakarta.json.JsonValue; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ArgumentsSource; + +class FalseJsonSchemaTest { + + @ParameterizedTest + @ArgumentsSource(JsonValuesArguments.class) + void should_be_invalid_for_everything(final JsonValue value) { + assertThat(new FalseJsonSchema().validator().validate(value), is(not(empty()))); + } +} diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/keyword/Keywords.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/JsonValuesArguments.java similarity index 64% rename from core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/keyword/Keywords.java rename to core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/JsonValuesArguments.java index 2a81121e..13c5a4a2 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/keyword/Keywords.java +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/JsonValuesArguments.java @@ -21,25 +21,24 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.github.sebastiantoepfer.jsonschema.core.impl.keyword; +package io.github.sebastiantoepfer.jsonschema.core; -import io.github.sebastiantoepfer.jsonschema.core.keyword.Keyword; import jakarta.json.JsonValue; -import java.util.Map; -import java.util.Optional; import java.util.stream.Stream; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.ArgumentsProvider; -public final class Keywords { +public class JsonValuesArguments implements ArgumentsProvider { - public static Keyword createKeywordFor(final Map.Entry property) { - return Stream - .of(new BasicVocabulary()) - .map(vocab -> vocab.findKeywordTypeByName(property.getKey())) - .flatMap(Optional::stream) - .findFirst() - .map(keywordType -> keywordType.createKeyword(property.getValue())) - .orElseThrow(); + @Override + public Stream provideArguments(final ExtensionContext context) throws Exception { + return Stream.of( + Arguments.of(JsonValue.EMPTY_JSON_ARRAY), + Arguments.of(JsonValue.EMPTY_JSON_OBJECT), + Arguments.of(JsonValue.FALSE), + Arguments.of(JsonValue.TRUE), + Arguments.of(JsonValue.NULL) + ); } - - private Keywords() {} } 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 new file mode 100644 index 00000000..1945fda6 --- /dev/null +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/KeywordsTest.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; + +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.core.vocab.basic.BasicVocabulary; +import io.github.sebastiantoepfer.jsonschema.core.vocab.core.CoreVocabulary; +import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.VocabularyDefinition; +import java.net.URI; +import java.util.Collection; +import java.util.List; +import org.junit.jupiter.api.Test; + +class KeywordsTest { + + @Test + void should_not_be_createbale_without_mandantory_core_vocabulary() { + final Collection vocabDefs = List.of( + new VocabularyDefinition(new CoreVocabulary().id(), false) + ); + assertThrows(IllegalArgumentException.class, () -> new Keywords(vocabDefs)); + } + + @Test + void should_not_be_createbale_without_mandantory_base_vocabulary() { + final Collection vocabDefs = List.of( + new VocabularyDefinition(new BasicVocabulary().id(), false) + ); + assertThrows(IllegalArgumentException.class, () -> new Keywords(vocabDefs)); + } + + @Test + void should_be_createbale_with_optional_vocabularies() { + assertThat( + new Keywords(List.of(new VocabularyDefinition(URI.create("http://optinal"), false))), + is(not(nullValue())) + ); + } +} diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/TrueJsonSchemaTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/TrueJsonSchemaTest.java new file mode 100644 index 00000000..36f5ff5b --- /dev/null +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/TrueJsonSchemaTest.java @@ -0,0 +1,41 @@ +/* + * 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; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.empty; +import static org.hamcrest.Matchers.is; + +import jakarta.json.JsonValue; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ArgumentsSource; + +class TrueJsonSchemaTest { + + @ParameterizedTest + @ArgumentsSource(JsonValuesArguments.class) + void should_be_valid_for_everything(final JsonValue value) { + assertThat(new TrueJsonSchema().validator().validate(value), is(empty())); + } +} diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/testsuite/JsonSchemaSchemaTestValidatorAdapterLoader.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/testsuite/JsonTestSuiteIT.java similarity index 56% rename from core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/testsuite/JsonSchemaSchemaTestValidatorAdapterLoader.java rename to core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/testsuite/JsonTestSuiteIT.java index 866ec232..a7f77238 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/testsuite/JsonSchemaSchemaTestValidatorAdapterLoader.java +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/testsuite/JsonTestSuiteIT.java @@ -23,29 +23,16 @@ */ package io.github.sebastiantoepfer.jsonschema.core.testsuite; -import io.github.sebastiantoepfer.jsonschema.core.JsonSchemas; -import io.github.sebastiantoepfer.jsonschema.core.Validator; -import io.github.sebastiantoepfer.jsonschema.testsuite.junit.SchemaTestValidatorLoader; -import java.util.Objects; +import static org.junit.jupiter.api.Assertions.assertTrue; -public final class JsonSchemaSchemaTestValidatorAdapterLoader implements SchemaTestValidatorLoader { +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ArgumentsSource; - @Override - public SchemaTestValidator loadSchemaTestValidator(final String schema) { - return new SchemaTestValidatorAdapter(JsonSchemas.load(schema).validator()); - } - - private static class SchemaTestValidatorAdapter implements SchemaTestValidator { - - private final Validator validator; - - public SchemaTestValidatorAdapter(final Validator validator) { - this.validator = Objects.requireNonNull(validator); - } +class JsonTestSuiteIT { - @Override - public boolean validate(final String data) { - return validator.validate(data).isEmpty(); - } + @ParameterizedTest(name = "{0}") + @ArgumentsSource(JsonTestSuiteTestCaseProvider.class) + void runJsonTestSuite(final JsonTestSuiteTestCase testcase) { + assertTrue(testcase.isValid()); } } diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/testsuite/JsonTestSuiteTestCase.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/testsuite/JsonTestSuiteTestCase.java new file mode 100644 index 00000000..42358e35 --- /dev/null +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/testsuite/JsonTestSuiteTestCase.java @@ -0,0 +1,28 @@ +/* + * 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.testsuite; + +interface JsonTestSuiteTestCase { + boolean isValid(); +} diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/testsuite/JsonTestSuiteTestCaseProvider.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/testsuite/JsonTestSuiteTestCaseProvider.java new file mode 100644 index 00000000..0656f74c --- /dev/null +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/testsuite/JsonTestSuiteTestCaseProvider.java @@ -0,0 +1,124 @@ +/* + * 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.testsuite; + +import io.github.sebastiantoepfer.jsonschema.JsonSchemas; +import jakarta.json.Json; +import jakarta.json.JsonObject; +import jakarta.json.JsonValue; +import jakarta.json.stream.JsonParser; +import java.util.Objects; +import java.util.stream.Stream; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.ArgumentsProvider; + +class JsonTestSuiteTestCaseProvider implements ArgumentsProvider { + + @Override + public Stream provideArguments(final ExtensionContext context) throws Exception { + return new Resources() + .all() + .filter(resource -> resource.hasExtension("json")) + .map(JsonSchemaTestSuites::new) + .flatMap(JsonSchemaTestSuites::allTestCases) + .map(Arguments::of); + } + + private static class JsonSchemaTestSuites { + + private final Resource jsonResource; + + public JsonSchemaTestSuites(final Resource jsonResource) { + this.jsonResource = Objects.requireNonNull(jsonResource); + } + + Stream allTestCases() { + final Stream result; + final JsonParser parser = Json.createParser(jsonResource.content()); + if (parser.next() == JsonParser.Event.START_ARRAY) { + result = + parser + .getArrayStream() + .onClose(() -> parser.close()) + .map(JsonValue::asJsonObject) + .map(JsonSchemaTestSuite::new) + .flatMap(JsonSchemaTestSuite::allTestCases); + } else { + parser.close(); + result = Stream.empty(); + } + return result; + } + + private class JsonSchemaTestSuite { + + private final JsonObject testsuite; + + public JsonSchemaTestSuite(final JsonObject testsuite) { + this.testsuite = Objects.requireNonNull(testsuite); + } + + Stream allTestCases() { + return testsuite + .getJsonArray("tests") + .stream() + .map(test -> new JsonSchemaTest(testsuite.get("schema"), test.asJsonObject())); + } + + private class JsonSchemaTest implements JsonTestSuiteTestCase { + + private final JsonValue schema; + private final JsonObject test; + + public JsonSchemaTest(final JsonValue schema, final JsonObject test) { + this.schema = schema; + this.test = test; + } + + @Override + public boolean isValid() { + return ( + JsonSchemas.load(schema).validator().validate(test.get("data")).isEmpty() == + test.getBoolean("valid") + ); + } + + @Override + public String toString() { + return ( + "JsonSchemaTest{" + + "schema=" + + schema + + ", test=" + + test + + " in " + + JsonSchemaTestSuites.this.jsonResource.name() + + '}' + ); + } + } + } + } +} diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/testsuite/Resource.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/testsuite/Resource.java new file mode 100644 index 00000000..cfa43487 --- /dev/null +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/testsuite/Resource.java @@ -0,0 +1,68 @@ +/* + * 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.testsuite; + +import java.io.InputStream; +import java.util.Objects; + +final record Resource(String name) { + boolean hasName(final String name) { + return Objects.equals(this.name, name); + } + + boolean hasExtension(final String extension) { + return name.endsWith(".".concat(extension)); + } + + InputStream content() { + return Resource.class.getClassLoader().getResourceAsStream(name); + } + + @Override + public String toString() { + return "Resource{" + "name=" + name + '}'; + } + + @Override + public int hashCode() { + int hash = 7; + hash = 83 * hash + (this.name != null ? this.name.hashCode() : 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 Resource other = (Resource) obj; + return (this.name == null) ? (other.name == null) : this.name.equals(other.name); + } +} diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/testsuite/Resources.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/testsuite/Resources.java new file mode 100644 index 00000000..26f785d8 --- /dev/null +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/testsuite/Resources.java @@ -0,0 +1,119 @@ +/* + * 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.testsuite; + +import java.io.File; +import java.io.IOException; +import java.net.URISyntaxException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Objects; +import java.util.Spliterator; +import java.util.Spliterators; +import java.util.regex.Pattern; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +final class Resources { + + private final String baseDir; + + public Resources() { + this("."); + } + + public Resources(final String baseDir) { + this.baseDir = baseDir; + } + + Stream all() { + try { + return StreamSupport + .stream( + Spliterators.spliteratorUnknownSize( + Resource.class.getClassLoader().getResources(baseDir).asIterator(), + Spliterator.ORDERED + ), + false + ) + .map(url -> { + try { + return url.toURI(); + } catch (URISyntaxException e) { + throw new IllegalStateException(e); + } + }) + .filter(uri -> "file".equals(uri.getScheme())) + .map(Paths::get) + .map(PathResources::new) + .flatMap(PathResources::toResources); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + private static class PathResources { + + private static final Pattern PATH_SEPARATOR = Pattern.compile(File.pathSeparator); + private final Path path; + + public PathResources(final Path path) { + this.path = Objects.requireNonNull(path); + } + + Stream toResources() { + final Stream result; + try { + if (path.toFile().isFile()) { + result = + Stream.of( + new Resource( + path + .toFile() + .getAbsolutePath() + .substring( + PATH_SEPARATOR + .splitAsStream(System.getProperty("java.class.path")) + .map(Path::of) + .filter(path::startsWith) + .map(Path::toFile) + .map(File::getAbsolutePath) + .map(String::length) + .map(i -> i + 1) + .findAny() + .orElse(0) + ) + ) + ); + } else { + result = Files.list(path).map(PathResources::new).flatMap(PathResources::toResources); + } + } catch (IOException e) { + throw new IllegalStateException(e); + } + return result; + } + } +} diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/impl/keyword/ConstraintAssertionTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/ConstraintAssertionTest.java similarity index 89% rename from core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/impl/keyword/ConstraintAssertionTest.java rename to core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/ConstraintAssertionTest.java index 15abc7af..6561f6cd 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/impl/keyword/ConstraintAssertionTest.java +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/ConstraintAssertionTest.java @@ -21,13 +21,14 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.github.sebastiantoepfer.jsonschema.core.impl.keyword; +package io.github.sebastiantoepfer.jsonschema.core.vocab; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; -import io.github.sebastiantoepfer.jsonschema.core.ConstraintViolation; -import io.github.sebastiantoepfer.jsonschema.core.impl.constraint.Constraint; +import io.github.sebastiantoepfer.jsonschema.ConstraintViolation; +import io.github.sebastiantoepfer.jsonschema.core.constraint.Constraint; +import io.github.sebastiantoepfer.jsonschema.core.vocab.ConstraintAssertion; import jakarta.json.JsonValue; import java.util.Collection; import java.util.Objects; diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/impl/keyword/BasicVocabularyTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/basic/BasicVocabularyTest.java similarity index 79% rename from core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/impl/keyword/BasicVocabularyTest.java rename to core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/basic/BasicVocabularyTest.java index 63eb5e96..75962d00 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/impl/keyword/BasicVocabularyTest.java +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/basic/BasicVocabularyTest.java @@ -21,13 +21,15 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.github.sebastiantoepfer.jsonschema.core.impl.keyword; +package io.github.sebastiantoepfer.jsonschema.core.vocab.basic; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; import com.github.npathai.hamcrestopt.OptionalMatchers; -import io.github.sebastiantoepfer.jsonschema.core.keyword.KeywordType; +import io.github.sebastiantoepfer.jsonschema.core.vocab.basic.BasicVocabulary; +import io.github.sebastiantoepfer.jsonschema.keyword.KeywordType; +import jakarta.json.JsonValue; import java.net.URI; import org.junit.jupiter.api.Test; @@ -52,8 +54,11 @@ void should_return_the_type_keywordtype() { @Test void should_return_the_custom_annotation_for_unknow_keyword() { assertThat( - new BasicVocabulary().findKeywordTypeByName("unknow").map(KeywordType::name), - OptionalMatchers.isPresentAndIs("unknow") + new BasicVocabulary() + .findKeywordTypeByName("unknow") + .map(keywordType -> keywordType.createKeyword(JsonValue.FALSE)) + .map(keyword -> keyword.hasName("unknow")), + OptionalMatchers.isPresentAndIs(true) ); } } diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/basic/TypeTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/basic/TypeTest.java new file mode 100644 index 00000000..88fcd282 --- /dev/null +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/basic/TypeTest.java @@ -0,0 +1,70 @@ +/* + * 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.core.vocab.basic.TypeKeywordType; +import io.github.sebastiantoepfer.jsonschema.keyword.Assertion; +import jakarta.json.Json; +import jakarta.json.JsonValue; +import org.junit.jupiter.api.Test; + +class TypeTest { + + @Test + void should_know_his_name() { + assertThat(new TypeKeywordType().createKeyword(Json.createValue("string")).hasName("type"), is(true)); + } + + @Test + void should_know_other_names() { + assertThat(new TypeKeywordType().createKeyword(Json.createValue("string")).hasName("id"), is(false)); + } + + @Test + void should_use_stringvalue_to_validate_type() { + final Assertion typeAssertion = new TypeKeywordType().createKeyword(Json.createValue("string")).asAssertion(); + + assertThat(typeAssertion.isValidFor(Json.createValue("value")), is(true)); + assertThat(typeAssertion.isValidFor(JsonValue.EMPTY_JSON_OBJECT), is(false)); + assertThat(typeAssertion.isValidFor(Json.createValue(1L)), is(false)); + assertThat(typeAssertion.isValidFor(JsonValue.EMPTY_JSON_ARRAY), is(false)); + } + + @Test + void should_use_arrayvalue_to_validate_type() { + final Assertion typeAssertion = new TypeKeywordType() + .createKeyword( + Json.createArrayBuilder().add(Json.createValue("string")).add(Json.createValue("object")).build() + ) + .asAssertion(); + + assertThat(typeAssertion.isValidFor(Json.createValue("value")), is(true)); + assertThat(typeAssertion.isValidFor(JsonValue.EMPTY_JSON_OBJECT), is(true)); + assertThat(typeAssertion.isValidFor(Json.createValue(1L)), is(false)); + assertThat(typeAssertion.isValidFor(JsonValue.EMPTY_JSON_ARRAY), is(false)); + } +} diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/CoreVocabularyTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/CoreVocabularyTest.java new file mode 100644 index 00000000..392e842e --- /dev/null +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/CoreVocabularyTest.java @@ -0,0 +1,54 @@ +/* + * 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.is; + +import com.github.npathai.hamcrestopt.OptionalMatchers; +import io.github.sebastiantoepfer.jsonschema.core.vocab.core.CoreVocabulary; +import jakarta.json.JsonValue; +import java.net.URI; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class CoreVocabularyTest { + + void should_return_the_uri_of_the_current_core_vocabulary() { + assertThat(new CoreVocabulary().id(), is(URI.create("https://json-schema.org/draft/2020-12/vocab/core"))); + } + + @ParameterizedTest(name = "should know keyword {0}") + @ValueSource(strings = { "$schema", "$vocabulary", "$id", "$ref", "$dynamicRef", "$defs", "$comment" }) + void should_return_keywords_for_name(final String name) { + //keyword creation for easier pitesting :) -> i know it is bad + assertThat( + new CoreVocabulary() + .findKeywordTypeByName(name) + .map(keywordType -> keywordType.createKeyword(JsonValue.EMPTY_JSON_OBJECT)) + .map(keyword -> keyword.hasName(name)), + OptionalMatchers.isPresentAndIs(true) + ); + } +} diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/DynamicRefKeywordTypeTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/DynamicRefKeywordTypeTest.java new file mode 100644 index 00000000..4a6dfb94 --- /dev/null +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/DynamicRefKeywordTypeTest.java @@ -0,0 +1,45 @@ +/* + * 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.is; + +import io.github.sebastiantoepfer.jsonschema.core.vocab.core.DynamicRefKeywordType; +import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; +import jakarta.json.JsonValue; +import org.junit.jupiter.api.Test; + +class DynamicRefKeywordTypeTest { + + @Test + void notFinischedYet() { + final Keyword keyword = new DynamicRefKeywordType().createKeyword(JsonValue.FALSE); + + 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/LazyCoreVocabularyTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/LazyCoreVocabularyTest.java new file mode 100644 index 00000000..5f1aed0e --- /dev/null +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/LazyCoreVocabularyTest.java @@ -0,0 +1,50 @@ +/* + * 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 com.github.npathai.hamcrestopt.OptionalMatchers.isEmpty; +import static com.github.npathai.hamcrestopt.OptionalMatchers.isPresentAndIs; +import static org.hamcrest.MatcherAssert.assertThat; + +import io.github.sebastiantoepfer.jsonschema.Vocabulary; +import java.net.URI; +import org.junit.jupiter.api.Test; + +class LazyCoreVocabularyTest { + + @Test + void should_return_empty_for_non_core_id() { + assertThat(new LazyCoreVocabulary().loadVocabularyWithId(URI.create("")), isEmpty()); + } + + @Test + void should_return_core_vocabulary_for_core_id() { + assertThat( + new LazyCoreVocabulary() + .loadVocabularyWithId(URI.create("https://json-schema.org/draft/2020-12/vocab/core")) + .map(Vocabulary::id), + isPresentAndIs(URI.create("https://json-schema.org/draft/2020-12/vocab/core")) + ); + } +} 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 new file mode 100644 index 00000000..345da416 --- /dev/null +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/RefKeywordTypeTest.java @@ -0,0 +1,45 @@ +/* + * 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.is; + +import io.github.sebastiantoepfer.jsonschema.core.vocab.core.RefKeywordType; +import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; +import jakarta.json.JsonValue; +import org.junit.jupiter.api.Test; + +class RefKeywordTypeTest { + + @Test + void notFinischedYet() { + final Keyword keyword = new RefKeywordType().createKeyword(JsonValue.FALSE); + + assertThat(keyword.hasName("$ref"), 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/VocabularyKeywordTypeTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/VocabularyKeywordTypeTest.java new file mode 100644 index 00000000..45923f04 --- /dev/null +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/core/VocabularyKeywordTypeTest.java @@ -0,0 +1,74 @@ +/* + * 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.containsInAnyOrder; +import static org.hamcrest.Matchers.is; + +import io.github.sebastiantoepfer.jsonschema.core.vocab.core.VocabularyKeywordType; +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.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +class VocabularyKeywordTypeTest { + + @Test + void should_not_create_keyword_for_non_jsonobject() { + final VocabularyKeywordType keywordType = new VocabularyKeywordType(); + Assertions.assertThrows(IllegalArgumentException.class, () -> keywordType.createKeyword(JsonValue.FALSE)); + } + + @Test + void should_created_keyword_should_know_his_name() { + final Keyword vocabulary = new VocabularyKeywordType().createKeyword(JsonValue.EMPTY_JSON_OBJECT); + + assertThat(vocabulary.hasName("$vocabulary"), is(true)); + assertThat(vocabulary.hasName("$id"), is(false)); + } + + @Test + void should_create_definitions() { + assertThat( + ((VocabularyDefinitions) new VocabularyKeywordType() + .createKeyword( + Json + .createObjectBuilder() + .add("http://json-schema.org/test", true) + .add("http://openapi.org/test", false) + .build() + )).definitions() + .toList(), + containsInAnyOrder( + new VocabularyDefinition(URI.create("http://json-schema.org/test"), true), + new VocabularyDefinition(URI.create("http://openapi.org/test"), false) + ) + ); + } +} diff --git a/core/src/test/java/module-info.java b/core/src/test/java/module-info.java index 1d06fa1a..b7ce75fd 100644 --- a/core/src/test/java/module-info.java +++ b/core/src/test/java/module-info.java @@ -22,10 +22,12 @@ * THE SOFTWARE. */ open module io.github.sebastiantoepfer.jsonschema.core { + requires io.github.sebastiantoepfer.jsonschema; + requires io.github.sebastiantoepfer.jsonschema.vocabulary.spi; requires jakarta.json; - requires io.github.sebastiantoepfer.jsonschema.testsuite.junit; requires org.junit.jupiter.api; + requires org.junit.jupiter.params; requires org.junit.jupiter.engine; requires org.hamcrest; } diff --git a/core/src/test/resources/META-INF/services/io.github.sebastiantoepfer.jsonschema.testsuite.junit.SchemaTestValidatorLoader b/core/src/test/resources/META-INF/services/io.github.sebastiantoepfer.jsonschema.testsuite.junit.SchemaTestValidatorLoader deleted file mode 100644 index eb2d5163..00000000 --- a/core/src/test/resources/META-INF/services/io.github.sebastiantoepfer.jsonschema.testsuite.junit.SchemaTestValidatorLoader +++ /dev/null @@ -1 +0,0 @@ -io.github.sebastiantoepfer.jsonschema.core.testsuite.JsonSchemaSchemaTestValidatorAdapterLoader diff --git a/pom.xml b/pom.xml index a73a1e9c..d16ec52d 100644 --- a/pom.xml +++ b/pom.xml @@ -52,7 +52,9 @@ testsuite-junit-platform-engine - core + api + vocabulary-spi + core @@ -244,6 +246,9 @@ toString hashCode + + **IT + diff --git a/vocabulary-spi/pom.xml b/vocabulary-spi/pom.xml new file mode 100644 index 00000000..e3227436 --- /dev/null +++ b/vocabulary-spi/pom.xml @@ -0,0 +1,46 @@ + + + + 4.0.0 + + + io.github.sebastian-toepfer.json-schema + json-schema + 0.1.0-SNAPSHOT + + + json-schema-vocabulary-spi + Json Schema :: vocabulary :: spi + + + + ${project.groupId} + json-schema-api + ${project.version} + + + + org.junit.jupiter + junit-jupiter-api + test + + + org.junit.jupiter + junit-jupiter-engine + test + + + + org.hamcrest + hamcrest + test + + + com.github.npathai + hamcrest-optional + test + + + diff --git a/vocabulary-spi/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/LazyVocabularies.java b/vocabulary-spi/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/LazyVocabularies.java new file mode 100644 index 00000000..05d7fd67 --- /dev/null +++ b/vocabulary-spi/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/LazyVocabularies.java @@ -0,0 +1,36 @@ +/* + * 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.vocabulary.spi; + +import io.github.sebastiantoepfer.jsonschema.Vocabulary; +import java.net.URI; +import java.util.Optional; + +public interface LazyVocabularies { + default boolean knowsId(URI id) { + return loadVocabularyWithId(id).isPresent(); + } + + Optional loadVocabularyWithId(URI id); +} 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 new file mode 100644 index 00000000..0d4ab838 --- /dev/null +++ b/vocabulary-spi/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/VocabularyDefinition.java @@ -0,0 +1,45 @@ +/* + * 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.vocabulary.spi; + +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; + } +} 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 new file mode 100644 index 00000000..fe9dd85f --- /dev/null +++ b/vocabulary-spi/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/VocabularyDefinitions.java @@ -0,0 +1,30 @@ +/* + * 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.vocabulary.spi; + +import java.util.stream.Stream; + +public interface VocabularyDefinitions { + Stream definitions(); +} diff --git a/vocabulary-spi/src/main/java/module-info.java b/vocabulary-spi/src/main/java/module-info.java new file mode 100644 index 00000000..68e99b3f --- /dev/null +++ b/vocabulary-spi/src/main/java/module-info.java @@ -0,0 +1,29 @@ +/* + * 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. + */ + +module io.github.sebastiantoepfer.jsonschema.vocabulary.spi { + exports io.github.sebastiantoepfer.jsonschema.vocabulary.spi; + + requires io.github.sebastiantoepfer.jsonschema; +} diff --git a/vocabulary-spi/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/LazyVocabulariesTest.java b/vocabulary-spi/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/LazyVocabulariesTest.java new file mode 100644 index 00000000..fb7f777b --- /dev/null +++ b/vocabulary-spi/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/LazyVocabulariesTest.java @@ -0,0 +1,67 @@ +/* + * 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.vocabulary.spi; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +import io.github.sebastiantoepfer.jsonschema.Vocabulary; +import io.github.sebastiantoepfer.jsonschema.keyword.KeywordType; +import java.net.URI; +import java.util.Objects; +import java.util.Optional; +import org.junit.jupiter.api.Test; + +class LazyVocabulariesTest implements LazyVocabularies { + + @Test + void should_know_which_vocabularies_are_supported() { + assertThat(knowsId(URI.create("http://github.com/sebastian-toepfer/json-schema/basic")), is(true)); + assertThat(knowsId(URI.create("http://invalid")), is(false)); + } + + @Override + public Optional loadVocabularyWithId(final URI id) { + final Optional result; + if (Objects.equals(URI.create("http://github.com/sebastian-toepfer/json-schema/basic"), id)) { + result = + Optional.of( + new Vocabulary() { + @Override + public URI id() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Optional findKeywordTypeByName(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + } + ); + } else { + result = Optional.empty(); + } + return result; + } +} diff --git a/vocabulary-spi/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/TestLazyVocabularies.java b/vocabulary-spi/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/TestLazyVocabularies.java new file mode 100644 index 00000000..e9efbd88 --- /dev/null +++ b/vocabulary-spi/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/TestLazyVocabularies.java @@ -0,0 +1,53 @@ +/* + * 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.vocabulary.spi; + +import io.github.sebastiantoepfer.jsonschema.Vocabulary; +import io.github.sebastiantoepfer.jsonschema.keyword.KeywordType; +import java.net.URI; +import java.util.Optional; + +public final class TestLazyVocabularies implements LazyVocabularies { + + @Override + public Optional loadVocabularyWithId(final URI id) { + if (id.equals(URI.create("https://json-schema.org/draft/2020-12/vocab/core"))) { + return Optional.of( + new Vocabulary() { + @Override + public URI id() { + return id; + } + + @Override + public Optional findKeywordTypeByName(String name) { + return Optional.empty(); + } + } + ); + } else { + return Optional.empty(); + } + } +} 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/VocabularyDefinitionTest.java new file mode 100644 index 00000000..dd582c88 --- /dev/null +++ b/vocabulary-spi/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/spi/VocabularyDefinitionTest.java @@ -0,0 +1,60 @@ +/* + * 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.vocabulary.spi; + +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.junit.jupiter.api.Assertions.assertThrows; + +import io.github.sebastiantoepfer.jsonschema.Vocabulary; +import java.net.URI; +import org.junit.jupiter.api.Test; + +class VocabularyDefinitionTest { + + @Test + void should_throw_illegal_state_if_a_required_vocabulary_can_not_be_loaded() { + final VocabularyDefinition vocabDef = new VocabularyDefinition(URI.create("https://invalid"), true); + 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) + .findVocabulary() + .map(Vocabulary::id), + isPresentAndIs(URI.create("https://json-schema.org/draft/2020-12/vocab/core")) + ); + } + + @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), + isEmpty() + ); + } +} diff --git a/vocabulary-spi/src/test/resources/META-INF/services/io.github.sebastiantoepfer.jsonschema.vocabulary.spi.LazyVocabularies b/vocabulary-spi/src/test/resources/META-INF/services/io.github.sebastiantoepfer.jsonschema.vocabulary.spi.LazyVocabularies new file mode 100644 index 00000000..7f7bf604 --- /dev/null +++ b/vocabulary-spi/src/test/resources/META-INF/services/io.github.sebastiantoepfer.jsonschema.vocabulary.spi.LazyVocabularies @@ -0,0 +1 @@ +io.github.sebastiantoepfer.jsonschema.vocabulary.spi.TestLazyVocabularies