Skip to content

Commit

Permalink
feat: allow to preload json meta schemas into the repository
Browse files Browse the repository at this point in the history
Signed-off-by: Pascal Krause <[email protected]>
  • Loading branch information
pk-work committed Nov 25, 2022
1 parent bcc2474 commit 1f16fa1
Show file tree
Hide file tree
Showing 9 changed files with 4,748 additions and 19 deletions.
50 changes: 31 additions & 19 deletions src/main/java/io/vertx/json/schema/Draft.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,30 +25,43 @@ public enum Draft {
/**
* Draft 4 - <a href="http://json-schema.org/draft-04/schema#">http://json-schema.org/draft-04/schema#</a>
*
* Usually used by Swagger 2.0
* Usually used by OpenAPI 3.0
*/
DRAFT4,
DRAFT4("http://json-schema.org/draft-04/schema#"),

/**
* Draft 7 - <a href="http://json-schema.org/draft-07/schema#">http://json-schema.org/draft-07/schema#</a>
*
* Usually used by OpenAPI 3.0
* Commonly used by many projects
*/
DRAFT7,
DRAFT7("http://json-schema.org/draft-07/schema#"),

/**
* Draft 2019-09 - <a href="https://json-schema.org/draft/2019-09/schema">https://json-schema.org/draft/2019-09/schema</a>
*
* Commonly used by many projects
*/
DRAFT201909,
DRAFT201909("https://json-schema.org/draft/2019-09/schema"),

/**
* Draft 2019-09 - <a href="https://json-schema.org/draft/2020-12/schema">https://json-schema.org/draft/2020-12/schema</a>
* Draft 2020-12 - <a href="https://json-schema.org/draft/2020-12/schema">https://json-schema.org/draft/2020-12/schema</a>
*
* Usually used by OpenAPI 3.1
*/
DRAFT202012;
DRAFT202012("https://json-schema.org/draft/2020-12/schema");

private final String identifier;

Draft(String identifier) {
this.identifier = identifier;
}

/**
* @return the identifier of the draft version.
*/
public String getIdentifier() {
return identifier;
}

/**
* Converts a draft number to a {@link Draft} enum value.
Expand All @@ -75,25 +88,24 @@ public static Draft from(String string) {
}

/**
* Converts a draft idenfifier to a {@link Draft} enum value.
* Converts a draft identifier to a {@link Draft} enum value.
* @param string The identifier (in URL format)
* @return a Draft enum value
*/
public static Draft fromIdentifier(String string) {
if (string == null) {
throw new IllegalArgumentException("Invalid draft identifier: null");
}
switch (string) {
case "http://json-schema.org/draft-04/schema#":
return DRAFT4;
case "http://json-schema.org/draft-07/schema#":
return DRAFT7;
case "https://json-schema.org/draft/2019-09/schema":
return DRAFT201909;
case "https://json-schema.org/draft/2020-12/schema":
return DRAFT202012;
default:
throw new IllegalArgumentException("Unsupported draft identifier: " + string);
if(DRAFT4.identifier.equals(string)) {
return DRAFT4;
} else if(DRAFT7.identifier.equals(string)) {
return DRAFT7;
} else if(DRAFT201909.identifier.equals(string)) {
return DRAFT201909;
} else if(DRAFT202012.identifier.equals(string)) {
return DRAFT202012;
} else {
throw new IllegalArgumentException("Unsupported draft identifier: " + string);
}
}
}
10 changes: 10 additions & 0 deletions src/main/java/io/vertx/json/schema/SchemaRepository.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

import io.vertx.codegen.annotations.Fluent;
import io.vertx.codegen.annotations.VertxGen;
import io.vertx.core.file.FileSystem;
import io.vertx.core.json.JsonObject;
import io.vertx.json.schema.impl.SchemaRepositoryImpl;

Expand Down Expand Up @@ -56,6 +57,15 @@ static SchemaRepository create(JsonSchemaOptions options) {
@Fluent
SchemaRepository dereference(String uri, JsonSchema schema) throws SchemaException;

/**
* Preloads the repository with the meta schemas for the related draft version.
* @param fs The Vert.x file system to load the related schema meta files from classpath
* @param draft The draft version of the meta files to load
* @return a repository
*/
@Fluent
SchemaRepository preloadMetaSchema(FileSystem fs, Draft draft);

/**
* A new validator instance using this repository options.
*
Expand Down
57 changes: 57 additions & 0 deletions src/main/java/io/vertx/json/schema/impl/SchemaRepositoryImpl.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.vertx.json.schema.impl;

import io.vertx.core.file.FileSystem;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.json.schema.*;
Expand Down Expand Up @@ -64,6 +65,35 @@ public class SchemaRepositoryImpl implements SchemaRepository {
"else"
);

static final List<String> DRAFT_4_META_FILES = Arrays.asList(
"http://json-schema.org/draft-04/schema"
);

static final List<String> DRAFT_7_META_FILES = Arrays.asList(
"http://json-schema.org/draft-07/schema"
);

static final List<String> DRAFT_201909_META_FILES = Arrays.asList(
"https://json-schema.org/draft/2019-09/schema",
"https://json-schema.org/draft/2019-09/meta/core",
"https://json-schema.org/draft/2019-09/meta/applicator",
"https://json-schema.org/draft/2019-09/meta/validation",
"https://json-schema.org/draft/2019-09/meta/meta-data",
"https://json-schema.org/draft/2019-09/meta/format",
"https://json-schema.org/draft/2019-09/meta/content"
);

static final List<String> DRAFT_202012_META_FILES = Arrays.asList(
"https://json-schema.org/draft/2020-12/schema",
"https://json-schema.org/draft/2020-12/meta/core",
"https://json-schema.org/draft/2020-12/meta/applicator",
"https://json-schema.org/draft/2020-12/meta/validation",
"https://json-schema.org/draft/2020-12/meta/meta-data",
"https://json-schema.org/draft/2020-12/meta/format-annotation",
"https://json-schema.org/draft/2020-12/meta/content",
"https://json-schema.org/draft/2020-12/meta/unevaluated"
);

private final Map<String, JsonSchema> lookup = new HashMap<>();

private final JsonSchemaOptions options;
Expand All @@ -88,6 +118,33 @@ public SchemaRepository dereference(String uri, JsonSchema schema) throws Schema
return this;
}

@Override public SchemaRepository preloadMetaSchema(FileSystem fs, Draft draft) {
List<String> metaSchemaIds;
switch (draft) {
case DRAFT4:
metaSchemaIds = DRAFT_4_META_FILES;
break;
case DRAFT7:
metaSchemaIds = DRAFT_7_META_FILES;
break;
case DRAFT201909:
metaSchemaIds = DRAFT_201909_META_FILES;
break;
case DRAFT202012:
metaSchemaIds = DRAFT_202012_META_FILES;
break;
default:
throw new IllegalStateException();
}

for (String id : metaSchemaIds) {
// read files from classpath
JsonSchema schema = JsonSchema.of(fs.readFileBlocking(id.substring(id.indexOf("://") + 3)).toJsonObject());
dereference(id, schema);
}
return this;
}

@Override
public Validator validator(JsonSchema schema) {
return new SchemaValidatorImpl(schema, options, Collections.unmodifiableMap(lookup));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package io.vertx.json.schema;

import io.vertx.core.Vertx;
import io.vertx.core.buffer.Buffer;
import io.vertx.junit5.VertxExtension;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Stream;

import static io.vertx.json.schema.Draft.DRAFT201909;
import static io.vertx.json.schema.Draft.DRAFT202012;
import static io.vertx.json.schema.Draft.DRAFT4;
import static io.vertx.json.schema.Draft.DRAFT7;

@ExtendWith(VertxExtension.class)
class SchemaDefinitionValidationTest {

private static final Path RESOURCE_PATH = Paths.get("src", "test", "resources", "schema_definition_validation");

private static Stream<Arguments> testSchemaDefinitionValidation() {
return Stream.of(
Arguments.of(DRAFT4, RESOURCE_PATH.resolve("OpenAPI3_0.json")),
Arguments.of(DRAFT7, RESOURCE_PATH.resolve("angular_cli_workspace_schema.json")),
Arguments.of(DRAFT201909, RESOURCE_PATH.resolve("compose_spec.json")),
Arguments.of(DRAFT202012, RESOURCE_PATH.resolve("OpenAPI3_1.json"))
);
}

@ParameterizedTest(name = "{index} test preloadMetaSchema with draft {0}")
@MethodSource
void testSchemaDefinitionValidation(Draft draft, Path schemaPath, Vertx vertx) throws IOException {
JsonSchemaOptions opts = new JsonSchemaOptions().setBaseUri("https://example.org");
SchemaRepository repo = SchemaRepository.create(opts);
repo.preloadMetaSchema(vertx.fileSystem(), draft);

Buffer schemaBuffer = Buffer.buffer(Files.readAllBytes(schemaPath));
JsonSchema schemaToValidate = JsonSchema.of(schemaBuffer.toJsonObject());

OutputUnit res = repo.validator(draft.getIdentifier()).validate(schemaToValidate);
Assertions.assertTrue(res.getValid());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package io.vertx.json.schema.impl;

import io.vertx.core.Vertx;
import io.vertx.core.file.FileSystem;
import io.vertx.json.schema.Draft;
import io.vertx.json.schema.JsonSchemaOptions;
import io.vertx.json.schema.SchemaRepository;
import io.vertx.junit5.VertxExtension;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

import java.util.List;
import java.util.stream.Stream;

import static io.vertx.json.schema.Draft.DRAFT201909;
import static io.vertx.json.schema.Draft.DRAFT202012;
import static io.vertx.json.schema.Draft.DRAFT4;
import static io.vertx.json.schema.Draft.DRAFT7;
import static io.vertx.json.schema.impl.SchemaRepositoryImpl.DRAFT_201909_META_FILES;
import static io.vertx.json.schema.impl.SchemaRepositoryImpl.DRAFT_202012_META_FILES;
import static io.vertx.json.schema.impl.SchemaRepositoryImpl.DRAFT_4_META_FILES;
import static io.vertx.json.schema.impl.SchemaRepositoryImpl.DRAFT_7_META_FILES;
import static org.mockito.ArgumentMatchers.endsWith;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;

@ExtendWith(VertxExtension.class)
class SchemaRepositoryImplTest {

private static Stream<Arguments> testPreloadMetaSchema() {
return Stream.of(
Arguments.of(DRAFT4, DRAFT_4_META_FILES),
Arguments.of(DRAFT7, DRAFT_7_META_FILES),
Arguments.of(DRAFT201909, DRAFT_201909_META_FILES),
Arguments.of(DRAFT202012, DRAFT_202012_META_FILES)
);
}

@ParameterizedTest(name = "{index} test preloadMetaSchema with draft {0}")
@MethodSource
void testPreloadMetaSchema(Draft draft, List<String> ids, Vertx vertx) {
JsonSchemaOptions opts = new JsonSchemaOptions().setBaseUri("https://example.org");
SchemaRepository repo = SchemaRepository.create(opts);
FileSystem fileSystemSpy = spy(vertx.fileSystem());
repo.preloadMetaSchema(fileSystemSpy, draft);

for(String id : ids) {
String classpath = id.replace("http://", "").replace("https://", "");
verify(fileSystemSpy).readFileBlocking(endsWith(classpath));
}
}
}
Loading

0 comments on commit 1f16fa1

Please sign in to comment.