Skip to content

Commit

Permalink
improve keyword
Browse files Browse the repository at this point in the history
  • Loading branch information
sebastian-toepfer committed Oct 3, 2023
1 parent 2a45e7d commit ed86b9d
Show file tree
Hide file tree
Showing 2 changed files with 130 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,19 @@
*/
package io.github.sebastiantoepfer.jsonschema.core.vocab.core;

import io.github.sebastiantoepfer.jsonschema.InstanceType;
import io.github.sebastiantoepfer.jsonschema.JsonSchema;
import io.github.sebastiantoepfer.jsonschema.JsonSchemas;
import io.github.sebastiantoepfer.jsonschema.keyword.Applicator;
import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
import io.github.sebastiantoepfer.jsonschema.keyword.KeywordType;
import jakarta.json.Json;
import jakarta.json.JsonPointer;
import jakarta.json.JsonReader;
import jakarta.json.JsonString;
import jakarta.json.JsonValue;
import java.io.IOException;
import java.net.URI;
import java.util.Objects;

/**
Expand All @@ -43,16 +51,75 @@ public String name() {

@Override
public Keyword createKeyword(final JsonSchema schema, final JsonValue value) {
return new Applicator() {
@Override
public boolean applyTo(final JsonValue instance) {
return true; //something is wrong here
if (InstanceType.STRING.isInstance(value)) {
return new RefKeyword(schema, (JsonString) value);
} else {
throw new IllegalArgumentException("must be a string");
}
}

private class RefKeyword implements Applicator {

private final JsonSchema schema;
private final URI uri;

private RefKeyword(final JsonSchema schema, final JsonString uri) {
this.schema = schema;
this.uri = URI.create(uri.getString());
}

@Override
public boolean applyTo(final JsonValue instance) {
return retrieveJsonSchema().validator().validate(instance).isEmpty();
}

@Override
public boolean hasName(final String name) {
return Objects.equals(name(), name);
}

private JsonSchema retrieveJsonSchema() {
final JsonValue json;
try {
if (isRemote()) {
json = retrieveValueFromRemoteLocation();
} else {
json = retrievValueFromLocalSchema();
}
return JsonSchemas.load(json);
} catch (IOException ex) {
throw new IllegalStateException("can not load schema!", ex);
}
}

private JsonValue retrievValueFromLocalSchema() throws IOException {
final JsonPointer pointer = createPointer();
if (schema.getValueType() == JsonValue.ValueType.OBJECT && pointer.containsValue(schema.asJsonObject())) {
return pointer.getValue(schema.asJsonObject());
} else {
throw new IOException("can not find referenced value.");
}
}

@Override
public boolean hasName(final String name) {
return Objects.equals(name(), name);
private JsonPointer createPointer() {
final String fragment = uri.getFragment();
final JsonPointer pointer;
if (fragment.startsWith("/")) {
pointer = Json.createPointer(fragment);
} else {
pointer = Json.createPointer("/".concat(fragment));
}
};
return pointer;
}

private JsonValue retrieveValueFromRemoteLocation() throws IOException {
try (final JsonReader reader = Json.createReader(uri.toURL().openStream())) {
return reader.readValue();
}
}

private boolean isRemote() {
return uri.getScheme() != null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,32 +25,75 @@

import static org.hamcrest.MatcherAssert.assertThat;
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 jakarta.json.Json;
import jakarta.json.JsonValue;
import org.junit.jupiter.api.Test;

class RefKeywordTypeTest {

@Test
void should_create_keyword_with_name() {
assertThat(
new RefKeywordType()
.createKeyword(new DefaultJsonSchemaFactory().create(JsonValue.TRUE), JsonValue.EMPTY_JSON_OBJECT)
.hasName("$ref"),
is(true)
);
void should_be_not_createbale_from_non_string() {
final RefKeywordType keywordType = new RefKeywordType();
final JsonSchema schema = new DefaultJsonSchemaFactory().create(JsonValue.TRUE);
assertThrows(IllegalArgumentException.class, () -> keywordType.createKeyword(schema, JsonValue.TRUE));
}

@Test
void notFinischedYet() {
void should_know_his_name() {
final Keyword ref = new RefKeywordType()
.createKeyword(new DefaultJsonSchemaFactory().create(JsonValue.TRUE), Json.createValue("#"));

assertThat(ref.hasName("$ref"), is(true));
assertThat(ref.hasName("test"), is(false));
}

@Test
void should_use_local_referenced_schema_for_validation() {
final Keyword keyword = new RefKeywordType()
.createKeyword(new DefaultJsonSchemaFactory().create(JsonValue.TRUE), JsonValue.FALSE);
.createKeyword(
new DefaultJsonSchemaFactory()
.create(
Json
.createObjectBuilder()
.add(
"$defs",
Json
.createObjectBuilder()
.add("positiveInteger", Json.createObjectBuilder().add("type", "integer"))
)
.build()
),
Json.createValue("#/$defs/positiveInteger")
);

assertThat(keyword.hasName("$ref"), is(true));
assertThat(keyword.hasName("$id"), is(false));
assertThat(keyword.asApplicator().applyTo(Json.createValue(1L)), is(true));
assertThat(keyword.asApplicator().applyTo(Json.createValue("invalid")), is(false));
}

@Test
void should_use_remote_referenced_schema_for_validation() {
final Keyword keyword = new RefKeywordType()
.createKeyword(
new DefaultJsonSchemaFactory()
.create(
Json
.createObjectBuilder()
.add(
"$defs",
Json
.createObjectBuilder()
.add("positiveInteger", Json.createObjectBuilder().add("type", "integer"))
)
.build()
),
Json.createValue("#/$defs/positiveInteger")
);

assertThat(keyword.asApplicator().applyTo(JsonValue.TRUE), is(true));
assertThat(keyword.asApplicator().applyTo(Json.createValue(1L)), is(true));
}
}

0 comments on commit ed86b9d

Please sign in to comment.