io.openapiprocessor.jsonschema.schema.ResolverRef Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of json-schema-validator Show documentation
Show all versions of json-schema-validator Show documentation
OpenAPI Parser JSON-Schema Validator
/*
* Copyright 2023 https://github.com/openapi-processor/openapi-parser
* PDX-License-Identifier: Apache-2.0
*/
package io.openapiprocessor.jsonschema.schema;
import io.openapiprocessor.jsonschema.support.Types;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.net.URI;
import java.util.Collection;
public class ResolverRef {
private final ResolverContext context;
public ResolverRef (ResolverContext context) {
this.context = context;
}
public void resolve (Bucket bucket) {
context.addDocument(bucket.getScope(), bucket.getRawValues());
walkBucket (bucket);
resolve ();
}
@SuppressWarnings({"dereference.of.nullable"})
private void walkBucket (Bucket bucket) {
Scope scope = bucket.getScope ();
JsonPointer location = bucket.getLocation ();
SchemaVersion version = scope.getVersion ();
bucket.forEach ((name, value) -> {
JsonPointer propLocation = location.append (name);
Keyword keyword = version.getKeyword (name);
boolean navigable = isNavigable(keyword);
if (isMetaSchema(name, value)) {
Ref ref = createRef (scope, name, value);
walkRef (ref, propLocation);
} else if (isRef(name, value)) {
Ref ref = createRef (scope, name, value);
walkRef (ref, propLocation);
} else if (isDynamicRef(name, value)) {
Ref ref = createRef (scope, name, value);
walkRef (ref, propLocation);
} else if (isRecursiveRef(name, value)) {
Ref ref = createRef (scope, name, value);
walkRef (ref, propLocation);
} else if (isNavigableObject(keyword, value)) {
walkSchema (scope, value, propLocation);
} else if (isNavigableSchemaArray(keyword, value)) {
walkSchemaArray (scope, value, propLocation);
} else if (isNavigableSchemaMap(keyword, value)) {
walkSchemaMap (scope, value, propLocation);
} else if (isDefaultObject(name, value)) {
walkSchema (scope, value, propLocation);
} else if (keyword == null && Types.isObject (value)) {
walkSchema (scope, value, propLocation);
} else if (keyword == null && Types.isArray (value)) {
walkSchemaArray (scope, value, propLocation);
}
});
}
private static boolean isDefaultObject(String name, Object value) {
return name.equals(Keywords.DEFAULT) && Types.isObject(value);
}
private static boolean isNavigableSchemaMap(Keyword keyword, Object value) {
if (keyword == null)
return false;
return keyword.isNavigable() && keyword.isSchemaMap() && Types.isObject(value);
}
private static boolean isNavigableSchemaArray(@Nullable Keyword keyword, Object value) {
if (keyword == null)
return false;
return keyword.isNavigable() && keyword.isSchemaArray() && Types.isArray(value);
}
private static boolean isNavigableObject(@Nullable Keyword keyword, Object value) {
if (keyword == null)
return false;
return keyword.isNavigable() && keyword.isSchema() && Types.isObject(value);
}
private static boolean isRecursiveRef(String name, Object value) {
return name.equals(Keywords.RECURSIVE_REF) && Types.isString(value);
}
private static boolean isDynamicRef(String name, Object value) {
return name.equals(Keywords.DYNAMIC_REF) && Types.isString(value);
}
private static boolean isRef(String name, Object value) {
return name.equals(Keywords.REF) && Types.isString(value);
}
private static boolean isMetaSchema(String name, Object value) {
return name.equals(Keywords.SCHEMA) && Types.isString(value);
}
private static boolean isNavigable(Keyword keyword) {
return keyword != null && keyword.isNavigable();
}
private Ref createRef (Scope scope, String name, Object value) {
String ref = Types.convertOrNull (name, value, String.class);
if (ref == null) {
throw new ResolverException (String.format ("failed to resolve empty $ref in '%s'.", scope));
}
return new Ref (scope, ref);
}
private void walkRef (Ref ref, JsonPointer location) {
Scope scope = ref.getScope ();
URI uri = ref.getDocumentUri ();
Object document = context.getDocument (uri);
if (document == null) {
// todo no auto load -> throw
document = addDocument (scope, uri, ref);
}
if (!context.isProcessedDocument (uri)) {
context.setProcessedDocument (uri);
Scope docScope = scope.move (uri, document); // todo document != null
Bucket bucket = Bucket.createBucket(docScope, document, JsonPointer.empty());
if (bucket == null) {
return; // todo error
}
walkIds (bucket);
walkBucket (bucket);
}
addReference (ref);
}
private void addReference (Ref ref) {
context.addRef (ref);
}
private void walkIds (Bucket bucket) {
ResolverId resolverId = new ResolverId (context);
resolverId.resolve(bucket);
}
private void walkSchema (Scope currentScope, Object value, JsonPointer location) {
Scope scope = currentScope.move (value);
Bucket bucket = Bucket.createBucket(scope, value, location);
if (bucket == null) {
return; // todo error
}
walkBucket (bucket);
}
private void walkSchemaArray (Scope currentScope, Object value, JsonPointer location) {
Collection