|
|
@@ -4,6 +4,7 @@ import java.util.HashMap;
|
|
|
import java.util.List;
|
|
|
import java.util.Map;
|
|
|
import java.util.function.Predicate;
|
|
|
+import java.util.function.Supplier;
|
|
|
import java.util.regex.Matcher;
|
|
|
import java.util.regex.Pattern;
|
|
|
|
|
|
@@ -17,11 +18,13 @@ import com.fasterxml.jackson.databind.node.JsonNodeType;
|
|
|
|
|
|
import lombok.AccessLevel;
|
|
|
import lombok.AllArgsConstructor;
|
|
|
+import lombok.Getter;
|
|
|
import lombok.NoArgsConstructor;
|
|
|
import lombok.RequiredArgsConstructor;
|
|
|
import lombok.experimental.FieldDefaults;
|
|
|
|
|
|
@NoArgsConstructor
|
|
|
+@FieldDefaults(level=AccessLevel.PROTECTED)
|
|
|
public class SchemaFactory {
|
|
|
@AllArgsConstructor
|
|
|
static final class SimpleTester implements Tester {
|
|
|
@@ -39,6 +42,29 @@ public class SchemaFactory {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ @AllArgsConstructor
|
|
|
+ static final class DeferredTester implements Tester {
|
|
|
+ Supplier<Tester> actual;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public JsonNodeType[] acceptedTypes() {
|
|
|
+ return ANY;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public boolean accepts(JsonNode node) {
|
|
|
+ return actual.get().accepts(node);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ @FieldDefaults(level=AccessLevel.PRIVATE)
|
|
|
+ static final class SharedData {
|
|
|
+ @Getter(AccessLevel.PRIVATE) Tester schema = null;
|
|
|
+ @Getter(AccessLevel.PROTECTED) Definitions definitions = null;
|
|
|
+ JsonNode root = null;
|
|
|
+ }
|
|
|
+
|
|
|
@RequiredArgsConstructor
|
|
|
@FieldDefaults(level=AccessLevel.PRIVATE, makeFinal=true)
|
|
|
protected class Definitions {
|
|
|
@@ -51,7 +77,9 @@ public class SchemaFactory {
|
|
|
}
|
|
|
|
|
|
private Tester createTester(final String path) {
|
|
|
- if (path.startsWith("#")) {
|
|
|
+ if (path.equals("#")) {
|
|
|
+ return new DeferredTester(SchemaFactory.this.shared::getSchema);
|
|
|
+ } else if (path.startsWith("#")) {
|
|
|
JsonNode current = localJson;
|
|
|
final String[] tokens = path.substring(2).split("/");
|
|
|
for (final String tok : tokens) {
|
|
|
@@ -68,20 +96,19 @@ public class SchemaFactory {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- protected Definitions defs = null;
|
|
|
+ SharedData shared = new SharedData();
|
|
|
|
|
|
- protected SchemaFactory(Definitions defs) {
|
|
|
- this.defs = defs;
|
|
|
+ protected SchemaFactory(SharedData shared) {
|
|
|
+ this.shared = shared;
|
|
|
}
|
|
|
|
|
|
public final Tester create(final JsonNode object) {
|
|
|
- if (defs == null) { defs = this.new Definitions(object); }
|
|
|
switch (object.getNodeType()) {
|
|
|
case BOOLEAN:
|
|
|
return new Schema(object.asBoolean() ? FixedTester.ACCEPT : FixedTester.REJECT);
|
|
|
case OBJECT:
|
|
|
- final SchemaFactory versioned = getVersionFactory(object.path("$schema").asText());
|
|
|
- return new Schema(JsonHelper.fields(object, versioned::createMapping));
|
|
|
+ final SchemaFactory versioned = factory(object);
|
|
|
+ return shared.schema = new Schema(JsonHelper.fields(object, versioned::createMapping));
|
|
|
default:
|
|
|
throw new IllegalStateException("Expected OBJECT or BOOLEAN, got " + object.getNodeType());
|
|
|
}
|
|
|
@@ -90,18 +117,30 @@ public class SchemaFactory {
|
|
|
protected String getVersion() {
|
|
|
return "";
|
|
|
}
|
|
|
+
|
|
|
+ private final SchemaFactory factory(final JsonNode object) {
|
|
|
+ return getVersionFactory(object.path("$schema").asText()).postInit(object);
|
|
|
+ }
|
|
|
|
|
|
private final SchemaFactory getVersionFactory(final String version) {
|
|
|
if (version.isEmpty() || version.equals(getVersion())) {
|
|
|
return this;
|
|
|
} else {
|
|
|
switch (getVersionInt(version)) {
|
|
|
- case 6: return new SchemaV6Factory(defs);
|
|
|
+ case 6: return new SchemaV6Factory(shared);
|
|
|
default:
|
|
|
throw new IllegalArgumentException("Unsupported schema version: " + version);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ private final SchemaFactory postInit(final JsonNode root) {
|
|
|
+ if (shared.root == null) {
|
|
|
+ shared.root = root;
|
|
|
+ shared.definitions = this.new Definitions(root);
|
|
|
+ }
|
|
|
+ return this;
|
|
|
+ }
|
|
|
|
|
|
private static int getVersionInt(final String version) {
|
|
|
final Pattern pat = Pattern.compile("http://json-schema.org/draft-(\\d+)/schema#");
|