Skip to content

Commit 1612852

Browse files
authored
Feature/dev harrel impl (#50)
add dev.harrel:json-schema implementation
1 parent 38a0429 commit 1612852

File tree

8 files changed

+218
-3
lines changed

8 files changed

+218
-3
lines changed

build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ dependencies {
7171

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

74+
implementation("dev.harrel:json-schema:1.4.1")
75+
7476
implementation("org.apache.logging.log4j:log4j-core:$log4jVersion")
7577
runtimeOnly("org.apache.logging.log4j:log4j-slf4j2-impl:$log4jVersion")
7678

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
/*
2+
* Copyright 2023 Creek Contributors (https://github.com/creek-service)
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.creekservice.kafka.test.perf.implementations;
18+
19+
import static org.creekservice.kafka.test.perf.testsuite.SchemaSpec.DRAFT_2019_09;
20+
import static org.creekservice.kafka.test.perf.testsuite.SchemaSpec.DRAFT_2020_12;
21+
22+
import com.fasterxml.jackson.core.JsonProcessingException;
23+
import com.fasterxml.jackson.databind.ObjectMapper;
24+
import com.fasterxml.jackson.databind.json.JsonMapper;
25+
import dev.harrel.jsonschema.Dialects;
26+
import dev.harrel.jsonschema.JsonNode;
27+
import dev.harrel.jsonschema.SchemaResolver;
28+
import dev.harrel.jsonschema.SpecificationVersion;
29+
import dev.harrel.jsonschema.Validator;
30+
import dev.harrel.jsonschema.providers.JacksonNode;
31+
import java.awt.Color;
32+
import java.io.IOException;
33+
import java.net.URI;
34+
import java.nio.charset.StandardCharsets;
35+
import java.util.Map;
36+
import java.util.Set;
37+
import java.util.stream.Collectors;
38+
import org.creekservice.kafka.test.perf.model.TestModel;
39+
import org.creekservice.kafka.test.perf.testsuite.AdditionalSchemas;
40+
import org.creekservice.kafka.test.perf.testsuite.SchemaSpec;
41+
42+
@SuppressWarnings("FieldMayBeFinal") // not final to avoid folding.
43+
public class DevHarrelImplementation implements Implementation {
44+
45+
private static final MetaData METADATA =
46+
new MetaData(
47+
"json-schema (dev.harrel)",
48+
"dev.harrel",
49+
Language.Java,
50+
Licence.MIT,
51+
Set.of(DRAFT_2020_12, DRAFT_2019_09),
52+
"https://github.com/harrel56/json-schema",
53+
new Color(22, 99, 0));
54+
55+
private ObjectMapper mapper = JsonMapper.builder().build();
56+
57+
@Override
58+
public MetaData metadata() {
59+
return METADATA;
60+
}
61+
62+
@Override
63+
public JsonValidator prepare(
64+
final String schema, final SchemaSpec spec, final AdditionalSchemas additionalSchemas) {
65+
66+
final Validator validator = validator(spec, additionalSchemas);
67+
final URI schemaUri = validator.registerSchema(schema);
68+
69+
return new JsonValidator() {
70+
71+
@Override
72+
public void validate(final String json) {
73+
final Validator.Result result = validator.validate(schemaUri, json);
74+
if (!result.isValid()) {
75+
throw new RuntimeException(result.getErrors().get(0).getError());
76+
}
77+
}
78+
79+
@Override
80+
public byte[] serialize(final TestModel model, final boolean validate) {
81+
try {
82+
final String asString = mapper.writeValueAsString(model);
83+
final Validator.Result result = validator.validate(schemaUri, asString);
84+
if (validate && !result.isValid()) {
85+
throw new RuntimeException(result.getErrors().get(0).getError());
86+
}
87+
return asString.getBytes(StandardCharsets.UTF_8);
88+
} catch (JsonProcessingException e) {
89+
throw new RuntimeException(e);
90+
}
91+
}
92+
93+
@Override
94+
public TestModel deserialize(final byte[] data) {
95+
try {
96+
final String json = new String(data, StandardCharsets.UTF_8);
97+
final Validator.Result result = validator.validate(schemaUri, json);
98+
if (!result.isValid()) {
99+
throw new RuntimeException(result.getErrors().get(0).getError());
100+
}
101+
return mapper.readValue(data, TestModel.class);
102+
} catch (IOException e) {
103+
throw new RuntimeException(e);
104+
}
105+
}
106+
};
107+
}
108+
109+
private Validator validator(final SchemaSpec spec, final AdditionalSchemas additionalSchemas) {
110+
final JacksonNode.Factory nodeFactory = new JacksonNode.Factory();
111+
final Map<String, JsonNode> remotes =
112+
additionalSchemas.remotes().entrySet().stream()
113+
.collect(
114+
Collectors.toMap(
115+
e -> e.getKey().toString(),
116+
e -> nodeFactory.create(e.getValue())));
117+
final SchemaResolver resolver =
118+
uri -> {
119+
final JsonNode schema = remotes.get(uri);
120+
if (schema != null) {
121+
return SchemaResolver.Result.fromJsonNode(schema);
122+
}
123+
return SchemaResolver.Result.empty();
124+
};
125+
switch (spec) {
126+
case DRAFT_2020_12:
127+
final Validator validator2020 =
128+
new dev.harrel.jsonschema.ValidatorFactory()
129+
.withDialect(new Dialects.Draft2020Dialect())
130+
.withJsonNodeFactory(nodeFactory)
131+
.withSchemaResolver(resolver)
132+
.createValidator();
133+
/* Validate against meta-schema in order to parse it eagerly */
134+
validator2020.validate(URI.create(SpecificationVersion.DRAFT2020_12.getId()), "{}");
135+
return validator2020;
136+
case DRAFT_2019_09:
137+
final Validator validator2019 =
138+
new dev.harrel.jsonschema.ValidatorFactory()
139+
.withDialect(new Dialects.Draft2019Dialect())
140+
.withJsonNodeFactory(nodeFactory)
141+
.withSchemaResolver(resolver)
142+
.createValidator();
143+
/* Validate against meta-schema in order to parse it eagerly */
144+
validator2019.validate(URI.create(SpecificationVersion.DRAFT2019_09.getId()), "{}");
145+
return validator2019;
146+
default:
147+
throw new RuntimeException("Unsupported Spec:" + spec);
148+
}
149+
}
150+
151+
// Final, empty finalize method stops spotbugs CT_CONSTRUCTOR_THROW
152+
// Can be moved to base type after https://github.com/spotbugs/spotbugs/issues/2665
153+
@Override
154+
@SuppressWarnings({"deprecation", "Finalize"})
155+
protected final void finalize() {}
156+
}

src/main/java/org/creekservice/kafka/test/perf/implementations/Implementations.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ public final class Implementations {
3434
new SchemaFriendImplementation(),
3535
new SkemaImplementation(),
3636
new SnowImplementation(),
37-
new VertxImplementation());
37+
new VertxImplementation(),
38+
new DevHarrelImplementation());
3839

3940
public static List<Implementation> all() {
4041
return IMPLS;

src/main/java/org/creekservice/kafka/test/perf/performance/JsonSerdeBenchmark.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.nio.file.Path;
2222
import java.util.Map;
2323
import org.creekservice.kafka.test.perf.implementations.ConfluentImplementation;
24+
import org.creekservice.kafka.test.perf.implementations.DevHarrelImplementation;
2425
import org.creekservice.kafka.test.perf.implementations.EveritImplementation;
2526
import org.creekservice.kafka.test.perf.implementations.Implementation;
2627
import org.creekservice.kafka.test.perf.implementations.JacksonImplementation;
@@ -198,6 +199,17 @@ public TestModel measureJustifyRoundTrip(final JustifyState impl, final ModelSta
198199
return impl.roundTrip(model);
199200
}
200201

202+
public static class DevHarrelState extends ImplementationState {
203+
public DevHarrelState() {
204+
super(new DevHarrelImplementation());
205+
}
206+
}
207+
208+
@Benchmark
209+
public TestModel measureDevHarrelRoundTrip(final DevHarrelState impl, final ModelState model) {
210+
return impl.roundTrip(model);
211+
}
212+
201213
@State(Scope.Thread)
202214
private static class ImplementationState {
203215

src/main/java/org/creekservice/kafka/test/perf/performance/JsonValidateBenchmark.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import static java.util.concurrent.TimeUnit.MILLISECONDS;
2020

2121
import org.creekservice.api.test.util.TestPaths;
22+
import org.creekservice.kafka.test.perf.implementations.DevHarrelImplementation;
2223
import org.creekservice.kafka.test.perf.implementations.EveritImplementation;
2324
import org.creekservice.kafka.test.perf.implementations.Implementation;
2425
import org.creekservice.kafka.test.perf.implementations.JustifyImplementation;
@@ -301,6 +302,23 @@ public Result measureDraft_7_Justify(final JustifyValidator validator) {
301302
return validator.validate(SchemaSpec.DRAFT_07);
302303
}
303304

305+
public static class DevHarrelValidator extends ValidatorState {
306+
307+
public DevHarrelValidator() {
308+
super(new DevHarrelImplementation());
309+
}
310+
}
311+
312+
@Benchmark
313+
public Result measureDraft_2019_09_DevHarrel(final DevHarrelValidator validator) {
314+
return validator.validate(SchemaSpec.DRAFT_2019_09);
315+
}
316+
317+
@Benchmark
318+
public Result measureDraft_2020_12_DevHarrel(final DevHarrelValidator validator) {
319+
return validator.validate(SchemaSpec.DRAFT_2020_12);
320+
}
321+
304322
@State(Scope.Benchmark)
305323
@SuppressWarnings("FieldMayBeFinal") // not final to avoid folding.
306324
abstract static class ValidatorState {

src/main/java/org/creekservice/kafka/test/perf/testsuite/TestSuite.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import com.fasterxml.jackson.annotation.JsonProperty;
2323
import com.fasterxml.jackson.databind.JsonNode;
2424
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
25+
import java.io.File;
2526
import java.io.IOException;
2627
import java.nio.file.Path;
2728
import java.util.List;
@@ -53,7 +54,10 @@ public TestSuite(
5354
this.suiteFilePath = requireNonNull(suiteFilePath, "suiteFilePath");
5455
this.optional =
5556
suiteFilePath.getParent() != null
56-
&& suiteFilePath.getParent().toString().contains("/optional");
57+
&& suiteFilePath
58+
.getParent()
59+
.toString()
60+
.contains(File.separator + "optional");
5761
} catch (final IOException e) {
5862
throw new RuntimeException(e);
5963
}

src/main/java/org/creekservice/kafka/test/perf/testsuite/TestSuiteLoader.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,10 @@ public JsonSchemaTestSuite load(final Path rootDir) {
9494
private static Map<URI, String> loadRemotes(final Path remotes) {
9595

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

99102
final Function<Path, String> readContent =
100103
path -> {
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
* Copyright 2023 Creek Contributors (https://github.com/creek-service)
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.creekservice.kafka.test.perf.implementations;
18+
19+
class DevHarrelImplementationTest extends ImplementationTest {}

0 commit comments

Comments
 (0)