From e3418e2dfa77c19393970750fb692016692bad82 Mon Sep 17 00:00:00 2001 From: Sebastian Toepfer <61313468+sebastian-toepfer@users.noreply.github.com> Date: Sun, 3 Dec 2023 20:49:52 +0100 Subject: [PATCH] refactor TypeKeywordType --- .../core/codition/AnyOfCondition.java | 42 ++++++++++ .../core/codition/OfTypeCondition.java | 41 ++++++++++ .../vocab/validation/TypeKeywordType.java | 80 +++++++------------ 3 files changed, 111 insertions(+), 52 deletions(-) create mode 100644 core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/codition/AnyOfCondition.java create mode 100644 core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/codition/OfTypeCondition.java diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/codition/AnyOfCondition.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/codition/AnyOfCondition.java new file mode 100644 index 00000000..194167f6 --- /dev/null +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/codition/AnyOfCondition.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.codition; + +import jakarta.json.JsonValue; +import java.util.Collection; +import java.util.List; + +public class AnyOfCondition implements Condition { + + private final Collection> conditions; + + public AnyOfCondition(final Collection> conditions) { + this.conditions = List.copyOf(conditions); + } + + @Override + public boolean isFulfilledBy(final JsonValue value) { + return conditions.stream().anyMatch(c -> c.isFulfilledBy(value)); + } +} diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/codition/OfTypeCondition.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/codition/OfTypeCondition.java new file mode 100644 index 00000000..9c9573b7 --- /dev/null +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/codition/OfTypeCondition.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.codition; + +import io.github.sebastiantoepfer.jsonschema.InstanceType; +import jakarta.json.JsonValue; + +public final class OfTypeCondition implements Condition { + + private final InstanceType type; + + public OfTypeCondition(final InstanceType type) { + this.type = type; + } + + @Override + public boolean isFulfilledBy(final JsonValue value) { + return type.isInstance(value); + } +} diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/TypeKeywordType.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/TypeKeywordType.java index 9daae6b0..c074c362 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/TypeKeywordType.java +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/validation/TypeKeywordType.java @@ -23,13 +23,18 @@ */ package io.github.sebastiantoepfer.jsonschema.core.vocab.validation; +import static jakarta.json.JsonValue.ValueType.STRING; +import static java.util.stream.Collectors.collectingAndThen; +import static java.util.stream.Collectors.toList; + import io.github.sebastiantoepfer.jsonschema.InstanceType; import io.github.sebastiantoepfer.jsonschema.JsonSchema; +import io.github.sebastiantoepfer.jsonschema.core.codition.AnyOfCondition; import io.github.sebastiantoepfer.jsonschema.core.codition.Condition; +import io.github.sebastiantoepfer.jsonschema.core.codition.OfTypeCondition; import io.github.sebastiantoepfer.jsonschema.keyword.Assertion; 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.Locale; @@ -47,14 +52,32 @@ public String name() { @Override public Keyword createKeyword(final JsonSchema schema) { - return new TypeKeyword(schema.asJsonObject().get(name())); + final JsonValue typeDefinition = schema.asJsonObject().get(name()); + final Condition typeContraint = + switch (typeDefinition.getValueType()) { + case STRING -> new OfTypeCondition( + InstanceType.valueOf(((JsonString) typeDefinition).getString().toUpperCase(Locale.US)) + ); + case ARRAY -> typeDefinition + .asJsonArray() + .stream() + .map(JsonString.class::cast) + .map(JsonString::getString) + .map(String::toUpperCase) + .map(InstanceType::valueOf) + .map(OfTypeCondition::new) + .collect(collectingAndThen(toList(), AnyOfCondition::new)); + default -> throw new IllegalArgumentException(); + }; + + return new TypeKeyword(typeContraint); } private final class TypeKeyword implements Assertion { - private final JsonValue definition; + private final Condition definition; - public TypeKeyword(final JsonValue definition) { + public TypeKeyword(final Condition definition) { this.definition = Objects.requireNonNull(definition); } @@ -65,54 +88,7 @@ public boolean hasName(final String name) { @Override public boolean isValidFor(final JsonValue instance) { - return new JsonMappedTypeConstaint(definition).isFulfilledBy(instance); - } - - private static final class JsonMappedTypeConstaint implements Condition { - - private final JsonValue definition; - - public JsonMappedTypeConstaint(final JsonValue definition) { - this.definition = Objects.requireNonNull(definition); - } - - @Override - public boolean isFulfilledBy(final JsonValue value) { - final Condition typeContraint = - switch (definition.getValueType()) { - case STRING -> new JsonStringTypeConstraint((JsonString) definition); - default -> new JsonArrayTypeConstraint(definition.asJsonArray()); - }; - return typeContraint.isFulfilledBy(value); - } - } - - private static final class JsonArrayTypeConstraint implements Condition { - - private final JsonArray types; - - public JsonArrayTypeConstraint(final JsonArray types) { - this.types = Objects.requireNonNull(types); - } - - @Override - public boolean isFulfilledBy(final JsonValue value) { - return types.stream().map(JsonMappedTypeConstaint::new).anyMatch(c -> c.isFulfilledBy(value)); - } - } - - private static final class JsonStringTypeConstraint implements Condition { - - private final String type; - - public JsonStringTypeConstraint(final JsonString type) { - this.type = Objects.requireNonNull(type).getString().toUpperCase(Locale.US); - } - - @Override - public boolean isFulfilledBy(final JsonValue value) { - return InstanceType.valueOf(type).isInstance(value); - } + return definition.isFulfilledBy(instance); } } }