Skip to content

Commit

Permalink
Feature/dev harrel impl (#50)
Browse files Browse the repository at this point in the history
add dev.harrel:json-schema implementation
  • Loading branch information
harrel56 authored Nov 14, 2023
1 parent 38a0429 commit 1612852
Show file tree
Hide file tree
Showing 8 changed files with 218 additions and 3 deletions.
2 changes: 2 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ dependencies {

implementation("org.leadpony.justify:justify:3.1.0")

implementation("dev.harrel:json-schema:1.4.1")

implementation("org.apache.logging.log4j:log4j-core:$log4jVersion")
runtimeOnly("org.apache.logging.log4j:log4j-slf4j2-impl:$log4jVersion")

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
/*
* Copyright 2023 Creek Contributors (https://github.com/creek-service)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.creekservice.kafka.test.perf.implementations;

import static org.creekservice.kafka.test.perf.testsuite.SchemaSpec.DRAFT_2019_09;
import static org.creekservice.kafka.test.perf.testsuite.SchemaSpec.DRAFT_2020_12;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.json.JsonMapper;
import dev.harrel.jsonschema.Dialects;
import dev.harrel.jsonschema.JsonNode;
import dev.harrel.jsonschema.SchemaResolver;
import dev.harrel.jsonschema.SpecificationVersion;
import dev.harrel.jsonschema.Validator;
import dev.harrel.jsonschema.providers.JacksonNode;
import java.awt.Color;
import java.io.IOException;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import org.creekservice.kafka.test.perf.model.TestModel;
import org.creekservice.kafka.test.perf.testsuite.AdditionalSchemas;
import org.creekservice.kafka.test.perf.testsuite.SchemaSpec;

@SuppressWarnings("FieldMayBeFinal") // not final to avoid folding.
public class DevHarrelImplementation implements Implementation {

private static final MetaData METADATA =
new MetaData(
"json-schema (dev.harrel)",
"dev.harrel",
Language.Java,
Licence.MIT,
Set.of(DRAFT_2020_12, DRAFT_2019_09),
"https://github.com/harrel56/json-schema",
new Color(22, 99, 0));

private ObjectMapper mapper = JsonMapper.builder().build();

@Override
public MetaData metadata() {
return METADATA;
}

@Override
public JsonValidator prepare(
final String schema, final SchemaSpec spec, final AdditionalSchemas additionalSchemas) {

final Validator validator = validator(spec, additionalSchemas);
final URI schemaUri = validator.registerSchema(schema);

return new JsonValidator() {

@Override
public void validate(final String json) {
final Validator.Result result = validator.validate(schemaUri, json);
if (!result.isValid()) {
throw new RuntimeException(result.getErrors().get(0).getError());
}
}

@Override
public byte[] serialize(final TestModel model, final boolean validate) {
try {
final String asString = mapper.writeValueAsString(model);
final Validator.Result result = validator.validate(schemaUri, asString);
if (validate && !result.isValid()) {
throw new RuntimeException(result.getErrors().get(0).getError());
}
return asString.getBytes(StandardCharsets.UTF_8);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}

@Override
public TestModel deserialize(final byte[] data) {
try {
final String json = new String(data, StandardCharsets.UTF_8);
final Validator.Result result = validator.validate(schemaUri, json);
if (!result.isValid()) {
throw new RuntimeException(result.getErrors().get(0).getError());
}
return mapper.readValue(data, TestModel.class);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
};
}

private Validator validator(final SchemaSpec spec, final AdditionalSchemas additionalSchemas) {
final JacksonNode.Factory nodeFactory = new JacksonNode.Factory();
final Map<String, JsonNode> remotes =
additionalSchemas.remotes().entrySet().stream()
.collect(
Collectors.toMap(
e -> e.getKey().toString(),
e -> nodeFactory.create(e.getValue())));
final SchemaResolver resolver =
uri -> {
final JsonNode schema = remotes.get(uri);
if (schema != null) {
return SchemaResolver.Result.fromJsonNode(schema);
}
return SchemaResolver.Result.empty();
};
switch (spec) {
case DRAFT_2020_12:
final Validator validator2020 =
new dev.harrel.jsonschema.ValidatorFactory()
.withDialect(new Dialects.Draft2020Dialect())
.withJsonNodeFactory(nodeFactory)
.withSchemaResolver(resolver)
.createValidator();
/* Validate against meta-schema in order to parse it eagerly */
validator2020.validate(URI.create(SpecificationVersion.DRAFT2020_12.getId()), "{}");
return validator2020;
case DRAFT_2019_09:
final Validator validator2019 =
new dev.harrel.jsonschema.ValidatorFactory()
.withDialect(new Dialects.Draft2019Dialect())
.withJsonNodeFactory(nodeFactory)
.withSchemaResolver(resolver)
.createValidator();
/* Validate against meta-schema in order to parse it eagerly */
validator2019.validate(URI.create(SpecificationVersion.DRAFT2019_09.getId()), "{}");
return validator2019;
default:
throw new RuntimeException("Unsupported Spec:" + spec);
}
}

// Final, empty finalize method stops spotbugs CT_CONSTRUCTOR_THROW
// Can be moved to base type after https://github.com/spotbugs/spotbugs/issues/2665
@Override
@SuppressWarnings({"deprecation", "Finalize"})
protected final void finalize() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ public final class Implementations {
new SchemaFriendImplementation(),
new SkemaImplementation(),
new SnowImplementation(),
new VertxImplementation());
new VertxImplementation(),
new DevHarrelImplementation());

public static List<Implementation> all() {
return IMPLS;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import java.nio.file.Path;
import java.util.Map;
import org.creekservice.kafka.test.perf.implementations.ConfluentImplementation;
import org.creekservice.kafka.test.perf.implementations.DevHarrelImplementation;
import org.creekservice.kafka.test.perf.implementations.EveritImplementation;
import org.creekservice.kafka.test.perf.implementations.Implementation;
import org.creekservice.kafka.test.perf.implementations.JacksonImplementation;
Expand Down Expand Up @@ -198,6 +199,17 @@ public TestModel measureJustifyRoundTrip(final JustifyState impl, final ModelSta
return impl.roundTrip(model);
}

public static class DevHarrelState extends ImplementationState {
public DevHarrelState() {
super(new DevHarrelImplementation());
}
}

@Benchmark
public TestModel measureDevHarrelRoundTrip(final DevHarrelState impl, final ModelState model) {
return impl.roundTrip(model);
}

@State(Scope.Thread)
private static class ImplementationState {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import static java.util.concurrent.TimeUnit.MILLISECONDS;

import org.creekservice.api.test.util.TestPaths;
import org.creekservice.kafka.test.perf.implementations.DevHarrelImplementation;
import org.creekservice.kafka.test.perf.implementations.EveritImplementation;
import org.creekservice.kafka.test.perf.implementations.Implementation;
import org.creekservice.kafka.test.perf.implementations.JustifyImplementation;
Expand Down Expand Up @@ -301,6 +302,23 @@ public Result measureDraft_7_Justify(final JustifyValidator validator) {
return validator.validate(SchemaSpec.DRAFT_07);
}

public static class DevHarrelValidator extends ValidatorState {

public DevHarrelValidator() {
super(new DevHarrelImplementation());
}
}

@Benchmark
public Result measureDraft_2019_09_DevHarrel(final DevHarrelValidator validator) {
return validator.validate(SchemaSpec.DRAFT_2019_09);
}

@Benchmark
public Result measureDraft_2020_12_DevHarrel(final DevHarrelValidator validator) {
return validator.validate(SchemaSpec.DRAFT_2020_12);
}

@State(Scope.Benchmark)
@SuppressWarnings("FieldMayBeFinal") // not final to avoid folding.
abstract static class ValidatorState {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.JsonNode;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.List;
Expand Down Expand Up @@ -53,7 +54,10 @@ public TestSuite(
this.suiteFilePath = requireNonNull(suiteFilePath, "suiteFilePath");
this.optional =
suiteFilePath.getParent() != null
&& suiteFilePath.getParent().toString().contains("/optional");
&& suiteFilePath
.getParent()
.toString()
.contains(File.separator + "optional");
} catch (final IOException e) {
throw new RuntimeException(e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,10 @@ public JsonSchemaTestSuite load(final Path rootDir) {
private static Map<URI, String> loadRemotes(final Path remotes) {

final Function<Path, URI> createKey =
path -> URI.create("http://localhost:1234/" + remotes.relativize(path));
path ->
URI.create(
"http://localhost:1234/"
+ remotes.relativize(path).toString().replace("\\", "/"));

final Function<Path, String> readContent =
path -> {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* Copyright 2023 Creek Contributors (https://github.com/creek-service)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.creekservice.kafka.test.perf.implementations;

class DevHarrelImplementationTest extends ImplementationTest {}

0 comments on commit 1612852

Please sign in to comment.