From a1a2dd858be869b20fd495e978bb66fc9c41f678 Mon Sep 17 00:00:00 2001 From: Sebastian Toepfer <61313468+sebastian-toepfer@users.noreply.github.com> Date: Sun, 3 Dec 2023 20:16:24 +0100 Subject: [PATCH] improve creation of properties keyword --- .../applicator/PropertiesKeywordType.java | 35 ++++++------ .../applicator/PropertiesKeywordTypeTest.java | 54 +++++++++++++++++++ 2 files changed, 74 insertions(+), 15 deletions(-) diff --git a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/PropertiesKeywordType.java b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/PropertiesKeywordType.java index 0715ccb1..9799450b 100644 --- a/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/PropertiesKeywordType.java +++ b/core/src/main/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/PropertiesKeywordType.java @@ -24,10 +24,11 @@ package io.github.sebastiantoepfer.jsonschema.core.vocab.applicator; import static jakarta.json.stream.JsonCollectors.toJsonArray; +import static java.util.stream.Collectors.collectingAndThen; +import static java.util.stream.Collectors.toMap; import io.github.sebastiantoepfer.jsonschema.InstanceType; import io.github.sebastiantoepfer.jsonschema.JsonSchema; -import io.github.sebastiantoepfer.jsonschema.JsonSubSchema; import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory; import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSubSchema; import io.github.sebastiantoepfer.jsonschema.keyword.Annotation; @@ -52,17 +53,28 @@ public String name() { @Override public Keyword createKeyword(final JsonSchema schema) { - return new PropertiesKeyword(schema, schema.asJsonObject().getJsonObject(name())); + final DefaultJsonSchemaFactory factory = new DefaultJsonSchemaFactory(); + return schema + .asJsonObject() + .getJsonObject(name()) + .entrySet() + .stream() + .map(entry -> + Map.entry( + entry.getKey(), + factory.tryToCreateSchemaFrom(entry.getValue()).orElseThrow(IllegalArgumentException::new) + ) + ) + .map(entry -> Map.entry(entry.getKey(), new DefaultJsonSubSchema(schema, entry.getValue()))) + .collect(collectingAndThen(toMap(Map.Entry::getKey, Map.Entry::getValue), PropertiesKeyword::new)); } private class PropertiesKeyword implements Applicator, Annotation { - private final JsonSchema schema; - private final JsonObject schemas; + private final Map schemas; - public PropertiesKeyword(final JsonSchema schema, final JsonObject schemas) { - this.schema = schema; - this.schemas = schemas; + public PropertiesKeyword(final Map schemas) { + this.schemas = Map.copyOf(schemas); } @Override @@ -87,25 +99,18 @@ private boolean propertiesMatches(final JsonObject instance) { private boolean propertyMatches(final Map.Entry property) { return Optional .ofNullable(schemas.get(property.getKey())) - .flatMap(this::toSubSchema) .map(JsonSchema::validator) .map(validator -> validator.isValid(property.getValue())) .orElse(true); } - private Optional toSubSchema(final JsonValue value) { - return new DefaultJsonSchemaFactory() - .tryToCreateSchemaFrom(value) - .map(subSchema -> new DefaultJsonSubSchema(schema, subSchema)); - } - @Override public JsonValue valueFor(final JsonValue instance) { return instance .asJsonObject() .keySet() .stream() - .filter(schemas.asJsonObject()::containsKey) + .filter(schemas::containsKey) .map(Json::createValue) .collect(toJsonArray()); } diff --git a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/PropertiesKeywordTypeTest.java b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/PropertiesKeywordTypeTest.java index efa34fb4..aca5917c 100644 --- a/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/PropertiesKeywordTypeTest.java +++ b/core/src/test/java/io/github/sebastiantoepfer/jsonschema/core/vocab/applicator/PropertiesKeywordTypeTest.java @@ -26,9 +26,12 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.is; +import static org.junit.jupiter.api.Assertions.assertThrows; +import io.github.sebastiantoepfer.jsonschema.JsonSchema; import io.github.sebastiantoepfer.jsonschema.core.DefaultJsonSchemaFactory; import io.github.sebastiantoepfer.jsonschema.keyword.Keyword; +import io.github.sebastiantoepfer.jsonschema.keyword.KeywordType; import jakarta.json.Json; import jakarta.json.JsonValue; import org.hamcrest.Matchers; @@ -36,6 +39,57 @@ class PropertiesKeywordTypeTest { + @Test + void should_not_be_createable_with_array_in_schemas() { + final JsonSchema schema = new DefaultJsonSchemaFactory() + .create( + Json + .createObjectBuilder() + .add( + "properties", + Json + .createObjectBuilder() + .add("test", JsonValue.TRUE) + .add("invalid", JsonValue.EMPTY_JSON_ARRAY) + ) + .build() + ); + final KeywordType keywordType = new PropertiesKeywordType(); + assertThrows(IllegalArgumentException.class, () -> keywordType.createKeyword(schema)); + } + + @Test + void should_not_be_createable_with_string_in_schemas() { + final JsonSchema schema = new DefaultJsonSchemaFactory() + .create( + Json + .createObjectBuilder() + .add( + "properties", + Json.createObjectBuilder().add("test", JsonValue.TRUE).add("invalid", Json.createValue("value")) + ) + .build() + ); + final KeywordType keywordType = new PropertiesKeywordType(); + assertThrows(IllegalArgumentException.class, () -> keywordType.createKeyword(schema)); + } + + @Test + void should_not_be_createable_with_number_in_schemas() { + final JsonSchema schema = new DefaultJsonSchemaFactory() + .create( + Json + .createObjectBuilder() + .add( + "properties", + Json.createObjectBuilder().add("test", JsonValue.TRUE).add("invalid", Json.createValue(3.14)) + ) + .build() + ); + final KeywordType keywordType = new PropertiesKeywordType(); + assertThrows(IllegalArgumentException.class, () -> keywordType.createKeyword(schema)); + } + @Test void should_be_know_his_name() { final Keyword keyword = new PropertiesKeywordType()