diff --git a/core/pom.xml b/core/pom.xml index c3efb7ea..86e23439 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -35,6 +35,11 @@ hamcrest test + + com.github.npathai + hamcrest-optional + test + jakarta.json diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/Vocabulary.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/Vocabulary.java new file mode 100644 index 00000000..abe04c48 --- /dev/null +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/Vocabulary.java @@ -0,0 +1,37 @@ +/* + * 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.core.keyword.KeywordType; +import java.net.URI; +import java.util.Optional; + +/** + * see: https://json-schema.org/draft/2020-12/json-schema-core.html#name-schema-vocabularies + */ +public interface Vocabulary { + URI id(); + + Optional findKeywordTypeByName(String name); +} 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/impl/keyword/BasicVocabulary.java new file mode 100644 index 00000000..d5fd1c35 --- /dev/null +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/keyword/BasicVocabulary.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.impl.keyword; + +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 java.net.URI; +import java.util.Optional; + +final class BasicVocabulary implements Vocabulary { + + @Override + public URI id() { + return URI.create("http://https://github.com/sebastian-toepfer/json-schema/basic"); + } + + @Override + public Optional findKeywordTypeByName(final String name) { + KeywordType keywordType = + 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); + } +} diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/keyword/Keywords.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/keyword/Keywords.java index 33901132..2a81121e 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/keyword/Keywords.java +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/impl/keyword/Keywords.java @@ -23,18 +23,22 @@ */ package io.github.sebastiantoepfer.jsonschema.core.impl.keyword; -import io.github.sebastiantoepfer.jsonschema.core.keyword.DefaultAnnotation; 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; public final class Keywords { public static Keyword createKeywordFor(final Map.Entry property) { - return switch (property.getKey()) { - case "type" -> new Type(property.getValue()); - default -> new DefaultAnnotation(property.getKey(), property.getValue()); - }; + return Stream + .of(new BasicVocabulary()) + .map(vocab -> vocab.findKeywordTypeByName(property.getKey())) + .flatMap(Optional::stream) + .findFirst() + .map(keywordType -> keywordType.createKeyword(property.getValue())) + .orElseThrow(); } private Keywords() {} diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/KeywordType.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/KeywordType.java new file mode 100644 index 00000000..85f08a56 --- /dev/null +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/keyword/KeywordType.java @@ -0,0 +1,37 @@ +/* + * 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.keyword; + +import jakarta.json.JsonValue; +import java.util.Objects; + +public interface KeywordType { + default boolean hasName(String name) { + return Objects.equals(name(), name); + } + + String name(); + + Keyword createKeyword(JsonValue value); +} 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/impl/keyword/BasicVocabularyTest.java new file mode 100644 index 00000000..63eb5e96 --- /dev/null +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/impl/keyword/BasicVocabularyTest.java @@ -0,0 +1,59 @@ +/* + * 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 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 java.net.URI; +import org.junit.jupiter.api.Test; + +class BasicVocabularyTest { + + @Test + void should_return_a_fake_id() { + assertThat( + new BasicVocabulary().id(), + is(URI.create("http://https://github.com/sebastian-toepfer/json-schema/basic")) + ); + } + + @Test + void should_return_the_type_keywordtype() { + assertThat( + new BasicVocabulary().findKeywordTypeByName("type").map(KeywordType::name), + OptionalMatchers.isPresentAndIs("type") + ); + } + + @Test + void should_return_the_custom_annotation_for_unknow_keyword() { + assertThat( + new BasicVocabulary().findKeywordTypeByName("unknow").map(KeywordType::name), + OptionalMatchers.isPresentAndIs("unknow") + ); + } +} diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/keyword/KeywordTypeTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/keyword/KeywordTypeTest.java new file mode 100644 index 00000000..6a3d95df --- /dev/null +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/keyword/KeywordTypeTest.java @@ -0,0 +1,52 @@ +/* + * 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.keyword; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +import jakarta.json.JsonValue; +import org.junit.jupiter.api.Test; + +class KeywordTypeTest { + + @Test + void should_know_his_name() { + assertThat(new TestKeywordType().hasName("test"), is(true)); + assertThat(new TestKeywordType().hasName("unknown"), is(false)); + } + + private static class TestKeywordType implements KeywordType { + + @Override + public String name() { + return "test"; + } + + @Override + public Keyword createKeyword(JsonValue value) { + throw new UnsupportedOperationException("Not supported yet."); + } + } +}