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

com.github.fge.jsonschema.tree.InlineSchemaTree Maven / Gradle / Ivy

There is a newer version: 1.2.5
Show newest version
/*
 * Copyright (c) 2013, 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.tree;

import com.fasterxml.jackson.databind.JsonNode;
import com.github.fge.jsonschema.jsonpointer.JsonPointer;
import com.github.fge.jsonschema.ref.JsonRef;
import com.github.fge.jsonschema.util.JacksonUtils;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;

import java.util.Map;

/**
 * A {@link SchemaTree} using inline dereferencing
 *
 * 

In inline dereferencing, implementations are expected to trust that the * schema is the referrent document for all contexts declared by {@code id}. * For instance, with this schema:

* *
 *     {
 *         "id": "x;//y/z",
 *         "sub": {
 *             "id": "t"
 *         }
 *     }
 * 
* *

JSON Reference {@code x://y/t#} is this JSON document at JSON Pointer * {@code /sub}.

*/ public final class InlineSchemaTree extends BaseSchemaTree { /** * The list of contexts whose URIs are absolute JSON References */ private final Map absRefs; /** * The list of contexts whose URIs are not absolute JSON References, or * outright illegal JSON References */ private final Map otherRefs; public InlineSchemaTree(final JsonNode baseNode) { this(JsonRef.emptyRef(), baseNode); } public InlineSchemaTree(final JsonRef loadingRef, final JsonNode baseNode) { super(loadingRef, baseNode, JsonPointer.empty()); final Map abs = Maps.newHashMap(); final Map other = Maps.newHashMap(); walk(loadingRef, baseNode, JsonPointer.empty(), abs, other); absRefs = ImmutableMap.copyOf(abs); otherRefs = ImmutableMap.copyOf(other); } private InlineSchemaTree(final InlineSchemaTree other, final JsonPointer newPointer) { super(other, newPointer); absRefs = other.absRefs; otherRefs = other.otherRefs; } @Override public SchemaTree append(final JsonPointer pointer) { final JsonPointer newPointer = this.pointer.append(pointer); return new InlineSchemaTree(this, newPointer); } @Override public SchemaTree setPointer(final JsonPointer pointer) { return new InlineSchemaTree(this, pointer); } @Override public boolean containsRef(final JsonRef ref) { return getMatchingPointer(ref) != null; } @Override public JsonPointer matchingPointer(final JsonRef ref) { final JsonPointer ret = getMatchingPointer(ref); if (ret == null) return null; return ret.path(baseNode).isMissingNode() ? null : ret; } private JsonPointer getMatchingPointer(final JsonRef ref) { if (otherRefs.containsKey(ref)) return otherRefs.get(ref); if (!ref.isLegal()) return null; return refMatchingPointer(ref); } /** * Return a matching pointer for a JSON Pointer terminated fully resolved * reference * *

This includes the loading URI. Note, however, that due to "id" * intricacies, the test against the loading reference is done only as a * last resort.

* * @param ref the target reference * @return the matching pointer, or {@code null} if not found */ private JsonPointer refMatchingPointer(final JsonRef ref) { final JsonPointer refPtr = ref.getPointer(); /* * When using inline addressing, we must favor whatever "id" has defined * as a URI scope over what the loading URI is... */ for (final Map.Entry entry: absRefs.entrySet()) if (entry.getKey().contains(ref)) return entry.getValue().append(refPtr); /* * ... Which means this test must be done last... (since refPtr is * declared final, this is safe) */ return loadingRef.contains(ref) ? refPtr : null; } /** * Walk a JSON document to collect URI contexts * *

Unlike what happens with a canonical schema tree, we must walk * the whole tree in advance here. This is necessary for {@link * #containsRef(JsonRef)} and {@link #matchingPointer(JsonRef)} to work.

* *

This method is called recursively. Its furst invocation is from the * constructor, with {@link #loadingRef} as a reference, {@link #baseNode} * as a JSON document and an empty pointer as the document pointer.

* * @param baseRef the current context * @param node the current document * @param ptr the current pointer into the base document * @param absMap map for absolute JSON References * @param otherMap map for non absolute and/or illegal JSON References * * @see #idFromNode(JsonNode) */ private static void walk(final JsonRef baseRef, final JsonNode node, final JsonPointer ptr, final Map absMap, final Map otherMap) { /* * FIXME: this means we won't go through schemas in keywords such as * "anyOf" and friends. No idea whether this is a concern. It may be. */ if (!node.isObject()) return; final JsonRef ref = idFromNode(node); final Map targetMap; JsonRef nextRef = baseRef; if (ref != null) { nextRef = baseRef.resolve(ref); targetMap = nextRef.isAbsolute() ? absMap : otherMap; targetMap.put(nextRef, ptr); } final Map tmp = JacksonUtils.asMap(node); for (final Map.Entry entry: tmp.entrySet()) walk(nextRef, entry.getValue(), ptr.append(entry.getKey()), absMap, otherMap); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy