All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.everit.json.schema.loader.ReferenceLookup Maven / Gradle / Ivy

Go to download

This is a fork of the implementation of the JSON Schema Core Draft v4 specification built with the org.json API which also supports internationalization

The newest version!
package org.everit.json.schema.loader;

import static java.util.Objects.requireNonNull;
import static org.everit.json.schema.loader.OrgJsonUtil.toMap;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;

import org.everit.json.schema.ReferenceSchema;
import org.everit.json.schema.Schema;
import org.everit.json.schema.SchemaLocation;
import org.everit.json.schema.loader.internal.ReferenceResolver;
import org.json.JSONObject;

/**
 * @author erosb
 */
class ReferenceLookup {

    /**
     * Underscore-like extend function. Merges the properties of {@code additional} and
     * {@code original}. Neither {@code additional} nor {@code original} will be modified, but the
     * returned object may be referentially the same as one of the parameters (in case the other
     * parameter is an empty object).
     */
    @Deprecated
    static JSONObject extend(JSONObject additional, JSONObject original) {
        return new JSONObject(extend(toMap(additional), toMap(original)));
    }

    static Map extend(Map additional, Map original) {
        if (additional.keySet().isEmpty()) {
            return original;
        }
        if (original.keySet().isEmpty()) {
            return additional;
        }
        Map rawObj = new HashMap<>();
        original.forEach(rawObj::put);
        additional.forEach(rawObj::put);
        return rawObj;
    }

    private LoadingState ls;

    private SchemaClient schemaClient;

    public ReferenceLookup(LoadingState ls) {
        this.ls = requireNonNull(ls, "ls cannot be null");
        this.schemaClient = ls.config.schemaClient;
    }

    private Map doExtend(Map additional, Map original) {
        if (ls.specVersion() == SpecificationVersion.DRAFT_4) {
            return extend(additional, original);
        } else {
            return original;
        }
    }

    /**
     * Returns the absolute URI without its fragment part.
     *
     * @param fullUri
     *         the abslute URI
     * @return the URI without the fragment part
     */
    static URI withoutFragment(final String fullUri) {
        int hashmarkIdx = fullUri.indexOf('#');
        String rval;
        if (hashmarkIdx == -1) {
            rval = fullUri;
        } else {
            rval = fullUri.substring(0, hashmarkIdx);
        }
        try {
            return new URI(rval);
        } catch (URISyntaxException e) {
            throw new RuntimeException(e);
        }
    }

    Map withoutRef(JsonObject original) {
        Map rawObj = new HashMap<>();
        original.keySet().stream()
                .filter(name -> !"$ref".equals(name))
                .forEach(name -> rawObj.put(name, original.get(name)));
        return rawObj;
    }

    private JsonObject lookupObjById(JsonValue val, String idAttrVal) {
        if (val instanceof JsonObject) {
            JsonObject obj = (JsonObject) val;
            if (obj.containsKey("$id") && obj.require("$id").requireString()
                    .equals(idAttrVal)) {
                return obj;
            }
            for (String key : obj.keySet()) {
                JsonObject maybeFound = lookupObjById(obj.require(key), idAttrVal);
                if (maybeFound != null) {
                    return maybeFound;
                }
            }
        } else if (val instanceof JsonArray) {
            JsonArray arr = (JsonArray) val;
            for (int i = 0; i < arr.length(); ++i) {
                JsonObject maybeFound = lookupObjById(arr.at(i), idAttrVal);
                if (maybeFound != null) {
                    return maybeFound;
                }
            }
        }

        return null;
    }

    private Schema.Builder performQueryEvaluation(String mapKey, JsonPointerEvaluator pointerEvaluator) {
        String absolutePointer = ReferenceResolver.resolve(ls.id, mapKey).toString();
        if (ls.pointerSchemas.containsKey(absolutePointer)) {
            return ls.pointerSchemas.get(absolutePointer);
        }
        JsonValue rawInternalReferenced = pointerEvaluator.query().getQueryResult();
        ReferenceSchema.Builder refBuilder = ReferenceSchema.builder()
                .refValue(mapKey);
        ls.pointerSchemas.put(absolutePointer, refBuilder);
        Schema referredSchema = new SchemaLoader(rawInternalReferenced.ls).load().build();
        refBuilder.build().setReferredSchema(referredSchema);
        return refBuilder;
    }

    /**
     * Returns a schema builder instance after looking up the JSON pointer.
     */
    Schema.Builder lookup(String relPointerString, JsonObject ctx) {
        if (isSameDocumentRef(relPointerString)) {
            return performQueryEvaluation(relPointerString, JsonPointerEvaluator.forDocument(ls.rootSchemaJson(), relPointerString));
        }
        String absPointerString = ReferenceResolver.resolve(ls.id, relPointerString).toString();
        if (ls.pointerSchemas.containsKey(absPointerString)) {
            return ls.pointerSchemas.get(absPointerString);
        }
        JsonValue rawInternalReferenced = lookupObjById(ls.rootSchemaJson, absPointerString);
        if (rawInternalReferenced != null) {
            ReferenceSchema.Builder refBuilder = ReferenceSchema.builder()
                    .refValue(relPointerString);
            ls.pointerSchemas.put(absPointerString, refBuilder);
            Schema referredSchema = new SchemaLoader(rawInternalReferenced.ls).load().build();
            refBuilder.build().setReferredSchema(referredSchema);
            return refBuilder;
        }

        JsonPointerEvaluator pointer = createPointerEvaluator(absPointerString);
        ReferenceSchema.Builder refBuilder = ReferenceSchema.builder()
                .refValue(relPointerString);
        ls.pointerSchemas.put(absPointerString, refBuilder);
        JsonPointerEvaluator.QueryResult result = pointer.query();

        URI resolutionScope = !isSameDocumentRef(absPointerString) ? withoutFragment(absPointerString) : ls.id;
        JsonObject containingDocument = result.getContainingDocument();
        SchemaLoader childLoader = ls.initNewDocumentLoader()
                .pointerToCurrentObj(SchemaLocation.parseURI(absPointerString))
                .resolutionScope(resolutionScope)
                .schemaJson(result.getQueryResult())
                .rootSchemaJson(containingDocument).build();
        Schema referredSchema = childLoader.load().build();
        refBuilder.schemaLocation(SchemaLocation.parseURI(absPointerString));
        refBuilder.build().setReferredSchema(referredSchema);
        return refBuilder;
    }

    private JsonObject initJsonObjectById(URI id) {
        JsonObject o = JsonValue.of(ls.config.schemasByURI.get(id)).requireObject();
        new LoadingState(ls.config, ls.pointerSchemas, o, o, id, SchemaLocation.parseURI(id.toString()));
        return o;
    }

    private JsonPointerEvaluator createPointerEvaluator(String absPointerString) {
        if (isSameDocumentRef(absPointerString)) {
            return JsonPointerEvaluator.forDocument(ls.rootSchemaJson(), absPointerString);
        }
        try {
            Uri uri = Uri.parse(absPointerString);
            if (ls.config.schemasByURI.containsKey(uri.asJavaURI())) {
                JsonObject o = initJsonObjectById(uri.asJavaURI());
                return JsonPointerEvaluator.forDocument(o, "#");
            } else if (ls.config.schemasByURI.containsKey(uri.toBeQueried)) {
                JsonObject o = initJsonObjectById(uri.toBeQueried);
                return JsonPointerEvaluator.forDocument(o, uri.fragment);
            }
        } catch (URISyntaxException e) {
            throw ls.createSchemaException(e);
        }
        return JsonPointerEvaluator.forURL(schemaClient, absPointerString, ls);
    }

    private boolean isSameDocumentRef(String ref) {
        return ref.startsWith("#");
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy