com.github.fge.jsonschema.validator.JsonResolver Maven / Gradle / Ivy
/*
* Copyright (c) 2012, Francis Galiegue
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the Lesser GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Lesser GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
package com.github.fge.jsonschema.validator;
import com.fasterxml.jackson.databind.JsonNode;
import com.github.fge.jsonschema.main.JsonSchemaException;
import com.github.fge.jsonschema.ref.JsonRef;
import com.github.fge.jsonschema.report.Domain;
import com.github.fge.jsonschema.report.Message;
import com.github.fge.jsonschema.schema.SchemaContext;
import com.github.fge.jsonschema.schema.SchemaNode;
import com.github.fge.jsonschema.schema.SchemaRegistry;
import java.net.URI;
import java.util.LinkedHashSet;
import java.util.Set;
/**
* Class responsible for JSON Reference resolution
*
* One instance of such class is created for each instance of {@link
* JsonValidatorCache}.
*/
final class JsonResolver
{
private final SchemaRegistry registry;
JsonResolver(final SchemaRegistry registry)
{
this.registry = registry;
}
/**
* Resolve a schema node to the target schema node
*
* @see SchemaRegistry#get(URI)
*
* @param schemaNode the original schema node
* @return the computed schema node
* @throws JsonSchemaException ref resolution failure (dangling ref, ref
* loop, etc)
*/
SchemaNode resolve(final SchemaNode schemaNode)
throws JsonSchemaException
{
/*
* All failures at this level are fatal
*/
final Message.Builder msg = Domain.REF_RESOLVING.newMessage()
.setKeyword("$ref").setFatal(true);
/*
* These two elements might change during ref resolving. Set them to
* their initial values.
*/
SchemaContext schemaContext = schemaNode.getSchemaContext();
JsonNode node = schemaNode.getNode();
/*
* This set will store all ABSOLUTE JSON references we encounter
* during ref resolution. If there is an attempt to store an already
* existing reference, this means a ref loop.
*
* We want to preserve insertion order, therefore we have to use a
* LinkedHashSet.
*/
final Set refs = new LinkedHashSet();
/*
* All elements below are set during the ref resolution process.
*/
JsonRef source, ref, target;
JsonNode refNode;
while (true) {
/*
* We break out immediately if either there is no $ref node,
* or there exists one but it is not a text node (syntax validation
* will catch that).
*/
refNode = node.path("$ref");
if (!refNode.isTextual())
break;
/*
* Similarly, the constructor will fail at this point iif the text
* value of the node is not an URI: break, we want this caught by
* syntax validation.
*/
try {
ref = JsonRef.fromString(refNode.textValue());
} catch (JsonSchemaException ignored) {
break;
}
/*
* Compute the target ref. Try and insert it into the set of refs
* already seen: if it has been already seen, there is a ref loop.
*/
source = schemaContext.getLocator();
target = source.resolve(ref);
if (!refs.add(target)) {
msg.setMessage("ref loop detected").addInfo("path", refs);
throw new JsonSchemaException(msg.build());
}
/*
* Should we change schema context? We should if the source ref (the
* one in the current context) does not contain the target ref. In
* this case, get the new context from our schema registry. If we
* cannot do that, this is an error condition, bail out.
*/
if (!schemaContext.contains(target))
schemaContext = registry.get(target.getLocator());
/*
* Finally, compute the next node in the process. If it is missing,
* we have a dangling JSON Pointer: this is an error condition.
*/
node = schemaContext.resolve(target);
if (node.isMissingNode()) {
msg.setMessage("dangling JSON Reference")
.addInfo("ref", target);
throw new JsonSchemaException(msg.build());
}
}
return new SchemaNode(schemaContext, node);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy