From f7d767a909ff17cddbea4d172c5ef116c7ecbb90 Mon Sep 17 00:00:00 2001 From: Jake Waffle Date: Fri, 3 May 2019 13:25:59 -0700 Subject: [PATCH 1/9] Updated the RefValidator so that it is more robust and supports relative references. --- .../schema/AdditionalPropertiesValidator.java | 2 +- .../com/networknt/schema/AllOfValidator.java | 2 +- .../com/networknt/schema/AnyOfValidator.java | 2 +- .../schema/DependenciesValidator.java | 2 +- .../com/networknt/schema/ItemsValidator.java | 6 +- .../java/com/networknt/schema/JsonSchema.java | 63 +++++++++-- .../networknt/schema/JsonSchemaFactory.java | 27 ++++- .../com/networknt/schema/NotValidator.java | 2 +- .../com/networknt/schema/OneOfValidator.java | 2 +- .../schema/PatternPropertiesValidator.java | 2 +- .../networknt/schema/PropertiesValidator.java | 2 +- .../com/networknt/schema/RefValidator.java | 78 ++++++------- .../schema/SchemaValidatorsConfig.java | 4 +- .../networknt/schema/UnionTypeValidator.java | 2 +- .../com/networknt/schema/url/URLFactory.java | 17 ++- .../com/networknt/schema/JsonSchemaTest.java | 5 + .../com/networknt/schema/SelfRefTest.java | 48 +++++++- src/test/resources/selfref.json | 31 ------ src/test/resources/tests/refRemoteSchema.json | 3 + .../resources/tests/relativeRefRemote.json | 105 ++++++++++++++++++ 20 files changed, 292 insertions(+), 113 deletions(-) delete mode 100644 src/test/resources/selfref.json create mode 100644 src/test/resources/tests/refRemoteSchema.json create mode 100644 src/test/resources/tests/relativeRefRemote.json diff --git a/src/main/java/com/networknt/schema/AdditionalPropertiesValidator.java b/src/main/java/com/networknt/schema/AdditionalPropertiesValidator.java index 67fb6cc31..2384f0ad6 100644 --- a/src/main/java/com/networknt/schema/AdditionalPropertiesValidator.java +++ b/src/main/java/com/networknt/schema/AdditionalPropertiesValidator.java @@ -47,7 +47,7 @@ public AdditionalPropertiesValidator(String schemaPath, JsonNode schemaNode, Jso additionalPropertiesSchema = null; } else if (schemaNode.isObject()) { allowAdditionalProperties = true; - additionalPropertiesSchema = new JsonSchema(validationContext, getValidatorType().getValue(), schemaNode, parentSchema); + additionalPropertiesSchema = new JsonSchema(validationContext, getValidatorType().getValue(), parentSchema.getCurrentUrl(), schemaNode, parentSchema); } else { allowAdditionalProperties = false; additionalPropertiesSchema = null; diff --git a/src/main/java/com/networknt/schema/AllOfValidator.java b/src/main/java/com/networknt/schema/AllOfValidator.java index b95d3120d..52c23824c 100644 --- a/src/main/java/com/networknt/schema/AllOfValidator.java +++ b/src/main/java/com/networknt/schema/AllOfValidator.java @@ -35,7 +35,7 @@ public AllOfValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentS super(schemaPath, schemaNode, parentSchema, ValidatorTypeCode.ALL_OF, validationContext); int size = schemaNode.size(); for (int i = 0; i < size; i++) { - schemas.add(new JsonSchema(validationContext, getValidatorType().getValue(), schemaNode.get(i), parentSchema)); + schemas.add(new JsonSchema(validationContext, getValidatorType().getValue(), parentSchema.getCurrentUrl(), schemaNode.get(i), parentSchema)); } } diff --git a/src/main/java/com/networknt/schema/AnyOfValidator.java b/src/main/java/com/networknt/schema/AnyOfValidator.java index 7cda0345f..1d1a95464 100644 --- a/src/main/java/com/networknt/schema/AnyOfValidator.java +++ b/src/main/java/com/networknt/schema/AnyOfValidator.java @@ -36,7 +36,7 @@ public AnyOfValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentS super(schemaPath, schemaNode, parentSchema, ValidatorTypeCode.ANY_OF, validationContext); int size = schemaNode.size(); for (int i = 0; i < size; i++) { - schemas.add(new JsonSchema(validationContext, getValidatorType().getValue(), schemaNode.get(i), parentSchema)); + schemas.add(new JsonSchema(validationContext, getValidatorType().getValue(), parentSchema.getCurrentUrl(), schemaNode.get(i), parentSchema)); } } diff --git a/src/main/java/com/networknt/schema/DependenciesValidator.java b/src/main/java/com/networknt/schema/DependenciesValidator.java index ccb85d56c..1eb016810 100644 --- a/src/main/java/com/networknt/schema/DependenciesValidator.java +++ b/src/main/java/com/networknt/schema/DependenciesValidator.java @@ -44,7 +44,7 @@ public DependenciesValidator(String schemaPath, JsonNode schemaNode, JsonSchema depsProps.add(pvalue.get(i).asText()); } } else if (pvalue.isObject()) { - schemaDeps.put(pname, new JsonSchema(validationContext, pname, pvalue, parentSchema)); + schemaDeps.put(pname, new JsonSchema(validationContext, pname, parentSchema.getCurrentUrl(), pvalue, parentSchema)); } } diff --git a/src/main/java/com/networknt/schema/ItemsValidator.java b/src/main/java/com/networknt/schema/ItemsValidator.java index a851ff92a..1638f23cd 100644 --- a/src/main/java/com/networknt/schema/ItemsValidator.java +++ b/src/main/java/com/networknt/schema/ItemsValidator.java @@ -38,11 +38,11 @@ public class ItemsValidator extends BaseJsonValidator implements JsonValidator { public ItemsValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { super(schemaPath, schemaNode, parentSchema, ValidatorTypeCode.ITEMS, validationContext); if (schemaNode.isObject()) { - schema = new JsonSchema(validationContext, getValidatorType().getValue(), schemaNode, parentSchema); + schema = new JsonSchema(validationContext, getValidatorType().getValue(), parentSchema.getCurrentUrl(), schemaNode, parentSchema); } else { tupleSchema = new ArrayList(); for (JsonNode s : schemaNode) { - tupleSchema.add(new JsonSchema(validationContext, getValidatorType().getValue(), s, parentSchema)); + tupleSchema.add(new JsonSchema(validationContext, getValidatorType().getValue(), parentSchema.getCurrentUrl(), s, parentSchema)); } JsonNode addItemNode = getParentSchema().getSchemaNode().get(PROPERTY_ADDITIONAL_ITEMS); @@ -50,7 +50,7 @@ public ItemsValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentS if (addItemNode.isBoolean()) { additionalItems = addItemNode.asBoolean(); } else if (addItemNode.isObject()) { - additionalSchema = new JsonSchema(validationContext, addItemNode); + additionalSchema = new JsonSchema(validationContext, parentSchema.getCurrentUrl(), addItemNode); } } } diff --git a/src/main/java/com/networknt/schema/JsonSchema.java b/src/main/java/com/networknt/schema/JsonSchema.java index 63c409aaf..bc9e6a23a 100644 --- a/src/main/java/com/networknt/schema/JsonSchema.java +++ b/src/main/java/com/networknt/schema/JsonSchema.java @@ -16,14 +16,22 @@ package com.networknt.schema; -import com.fasterxml.jackson.databind.JsonNode; - import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URL; import java.net.URLDecoder; -import java.util.*; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; +import com.fasterxml.jackson.databind.JsonNode; +import com.networknt.schema.url.URLFactory; + /** * This is the core of json constraint implementation. It parses json constraint * file and generates JsonValidators. The class is thread safe, once it is @@ -34,27 +42,60 @@ public class JsonSchema extends BaseJsonValidator { protected final Map validators; private final ValidationContext validationContext; + /** + * This is the current url of this schema. This url could refer to the url of this schema's file + * or it could potentially be a url that has been altered by an id. An 'id' is able to completely overwrite + * the current url or add onto it. This is necessary so that '$ref's are able to be relative to a + * combination of the current schema file's url and 'id' urls visible to this schema. + * + * This can be null. If it is null, then the creation of relative urls will fail. However, an absolute + * 'id' would still be able to specify an absolute url. + */ + private final URL currentUrl; + private JsonValidator requiredValidator = null; - public JsonSchema(ValidationContext validationContext, JsonNode schemaNode) { - this(validationContext, "#", schemaNode, null); + public JsonSchema(ValidationContext validationContext, URL baseUrl, JsonNode schemaNode) { + this(validationContext, "#", baseUrl, schemaNode, null); } - public JsonSchema(ValidationContext validationContext, String schemaPath, JsonNode schemaNode, + public JsonSchema(ValidationContext validationContext, String schemaPath, URL currentUrl, JsonNode schemaNode, JsonSchema parent) { - this(validationContext, schemaPath, schemaNode, parent, false); + this(validationContext, schemaPath, currentUrl, schemaNode, parent, false); } - public JsonSchema(ValidationContext validationContext, String schemaPath, JsonNode schemaNode, + public JsonSchema(ValidationContext validationContext, URL baseUrl, JsonNode schemaNode, boolean suppressSubSchemaRetrieval) { + this(validationContext, "#", baseUrl, schemaNode, null, suppressSubSchemaRetrieval); + } + + private JsonSchema(ValidationContext validationContext, String schemaPath, URL currentUrl, JsonNode schemaNode, JsonSchema parent, boolean suppressSubSchemaRetrieval) { super(schemaPath, schemaNode, parent, null, suppressSubSchemaRetrieval); this.validationContext = validationContext; this.config = validationContext.getConfig(); this.validators = Collections.unmodifiableMap(this.read(schemaNode)); + this.currentUrl = this.combineCurrentUrlWithIds(currentUrl, schemaNode); } - - public JsonSchema(ValidationContext validationContext, JsonNode schemaNode, boolean suppressSubSchemaRetrieval) { - this(validationContext, "#", schemaNode, null, suppressSubSchemaRetrieval); + + private URL combineCurrentUrlWithIds(URL currentUrl, JsonNode schemaNode) { + final JsonNode idNode = schemaNode.get("id"); + if (idNode == null) { + return currentUrl; + } else { + try + { + return URLFactory.toURL(currentUrl, idNode.asText()); + } + catch (MalformedURLException e) + { + throw new IllegalArgumentException(String.format("Invalid 'id' in schema: %s", schemaNode), e); + } + } + } + + public URL getCurrentUrl() + { + return this.currentUrl; } /** diff --git a/src/main/java/com/networknt/schema/JsonSchemaFactory.java b/src/main/java/com/networknt/schema/JsonSchemaFactory.java index 01dadf33d..763b7e5fe 100644 --- a/src/main/java/com/networknt/schema/JsonSchemaFactory.java +++ b/src/main/java/com/networknt/schema/JsonSchemaFactory.java @@ -42,6 +42,7 @@ public static class Builder { private String defaultMetaSchemaURI; private Map jsonMetaSchemas = new HashMap(); private Map urlMap = new HashMap(); + private URL rootSchemaUrl = null; public Builder objectMapper(ObjectMapper objectMapper) { this.objectMapper = objectMapper; @@ -75,6 +76,12 @@ public Builder addUrlMappings(Map map) { return this; } + public Builder setRootSchemaUrl(URL rootSchemaUrl) + { + this.rootSchemaUrl = rootSchemaUrl; + return this; + } + public JsonSchemaFactory build() { // create builtin keywords with (custom) formats. return new JsonSchemaFactory( @@ -82,7 +89,8 @@ public JsonSchemaFactory build() { urlFetcher == null ? new StandardURLFetcher(): urlFetcher, defaultMetaSchemaURI, jsonMetaSchemas, - urlMap + urlMap, + rootSchemaUrl ); } } @@ -92,8 +100,14 @@ public JsonSchemaFactory build() { private final String defaultMetaSchemaURI; private final Map jsonMetaSchemas; private final Map urlMap; + private final URL rootSchemaUrl; - private JsonSchemaFactory(ObjectMapper mapper, URLFetcher urlFetcher, String defaultMetaSchemaURI, Map jsonMetaSchemas, Map urlMap) { + private JsonSchemaFactory( + ObjectMapper mapper, + URLFetcher urlFetcher, + String defaultMetaSchemaURI, + Map jsonMetaSchemas, Map urlMap, + URL rootSchemaUrl) { if (mapper == null) { throw new IllegalArgumentException("ObjectMapper must not be null"); } @@ -117,6 +131,7 @@ private JsonSchemaFactory(ObjectMapper mapper, URLFetcher urlFetcher, String def this.urlFetcher = urlFetcher; this.jsonMetaSchemas = jsonMetaSchemas; this.urlMap = urlMap; + this.rootSchemaUrl = rootSchemaUrl; } /** @@ -148,13 +163,14 @@ public static Builder builder(JsonSchemaFactory blueprint) { .urlFetcher(blueprint.urlFetcher) .defaultMetaSchemaURI(blueprint.defaultMetaSchemaURI) .objectMapper(blueprint.mapper) - .addUrlMappings(blueprint.urlMap); + .addUrlMappings(blueprint.urlMap) + .setRootSchemaUrl(blueprint.rootSchemaUrl); } private JsonSchema newJsonSchema(JsonNode schemaNode, SchemaValidatorsConfig config) { final ValidationContext validationContext = createValidationContext(schemaNode); validationContext.setConfig(config); - JsonSchema jsonSchema = new JsonSchema(validationContext, schemaNode); + JsonSchema jsonSchema = new JsonSchema(validationContext, this.rootSchemaUrl, schemaNode); return jsonSchema; } @@ -213,8 +229,7 @@ public JsonSchema getSchema(URL schemaURL, SchemaValidatorsConfig config) { final JsonMetaSchema jsonMetaSchema = findMetaSchemaForSchema(schemaNode); if (idMatchesSourceUrl(jsonMetaSchema, schemaNode, schemaURL)) { - - return new JsonSchema(new ValidationContext(jsonMetaSchema, this), schemaNode, true /*retrieved via id, resolving will not change anything*/); + return new JsonSchema(new ValidationContext(jsonMetaSchema, this), mappedURL, schemaNode, true /*retrieved via id, resolving will not change anything*/); } return newJsonSchema(schemaNode, config); diff --git a/src/main/java/com/networknt/schema/NotValidator.java b/src/main/java/com/networknt/schema/NotValidator.java index 7917f368f..564d83301 100644 --- a/src/main/java/com/networknt/schema/NotValidator.java +++ b/src/main/java/com/networknt/schema/NotValidator.java @@ -30,7 +30,7 @@ public class NotValidator extends BaseJsonValidator implements JsonValidator { public NotValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { super(schemaPath, schemaNode, parentSchema, ValidatorTypeCode.NOT, validationContext); - schema = new JsonSchema(validationContext, getValidatorType().getValue(), schemaNode, parentSchema); + schema = new JsonSchema(validationContext, getValidatorType().getValue(), parentSchema.getCurrentUrl(), schemaNode, parentSchema); parseErrorCode(getValidatorType().getErrorCodeKey()); } diff --git a/src/main/java/com/networknt/schema/OneOfValidator.java b/src/main/java/com/networknt/schema/OneOfValidator.java index 777cef4dd..e1905e15c 100644 --- a/src/main/java/com/networknt/schema/OneOfValidator.java +++ b/src/main/java/com/networknt/schema/OneOfValidator.java @@ -121,7 +121,7 @@ public OneOfValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentS int size = schemaNode.size(); for (int i = 0; i < size; i++) { JsonNode childNode = schemaNode.get(i); - JsonSchema childSchema = new JsonSchema(validationContext, getValidatorType().getValue(), childNode, parentSchema); + JsonSchema childSchema = new JsonSchema(validationContext, getValidatorType().getValue(), parentSchema.getCurrentUrl(), childNode, parentSchema); schemas.add(new ShortcutValidator(childNode, parentSchema, validationContext, childSchema)); } diff --git a/src/main/java/com/networknt/schema/PatternPropertiesValidator.java b/src/main/java/com/networknt/schema/PatternPropertiesValidator.java index 2efe4dc22..9feb4aa73 100644 --- a/src/main/java/com/networknt/schema/PatternPropertiesValidator.java +++ b/src/main/java/com/networknt/schema/PatternPropertiesValidator.java @@ -38,7 +38,7 @@ public PatternPropertiesValidator(String schemaPath, JsonNode schemaNode, JsonSc Iterator names = schemaNode.fieldNames(); while (names.hasNext()) { String name = names.next(); - schemas.put(Pattern.compile(name), new JsonSchema(validationContext, name, schemaNode.get(name), parentSchema)); + schemas.put(Pattern.compile(name), new JsonSchema(validationContext, name, parentSchema.getCurrentUrl(), schemaNode.get(name), parentSchema)); } } diff --git a/src/main/java/com/networknt/schema/PropertiesValidator.java b/src/main/java/com/networknt/schema/PropertiesValidator.java index 4a4f9e766..3daee20c0 100644 --- a/src/main/java/com/networknt/schema/PropertiesValidator.java +++ b/src/main/java/com/networknt/schema/PropertiesValidator.java @@ -32,7 +32,7 @@ public PropertiesValidator(String schemaPath, JsonNode schemaNode, JsonSchema pa schemas = new HashMap(); for (Iterator it = schemaNode.fieldNames(); it.hasNext(); ) { String pname = it.next(); - schemas.put(pname, new JsonSchema(validationContext, schemaPath + "/" + pname, schemaNode.get(pname), parentSchema)); + schemas.put(pname, new JsonSchema(validationContext, schemaPath + "/" + pname, parentSchema.getCurrentUrl(), schemaNode.get(pname), parentSchema)); } } diff --git a/src/main/java/com/networknt/schema/RefValidator.java b/src/main/java/com/networknt/schema/RefValidator.java index 8374fb27b..f3e61c260 100644 --- a/src/main/java/com/networknt/schema/RefValidator.java +++ b/src/main/java/com/networknt/schema/RefValidator.java @@ -18,6 +18,7 @@ import java.io.InputStream; import java.net.MalformedURLException; +import java.net.URI; import java.net.URL; import java.text.MessageFormat; import java.util.Collections; @@ -50,23 +51,25 @@ public RefValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentSch static JsonSchema getRefSchema(JsonSchema parentSchema, ValidationContext validationContext, String refValue) { if (!refValue.startsWith(REF_CURRENT)) { - // handle remote ref - String schemaUrl = refValue; - int index = refValue.indexOf(REF_CURRENT); + // This will be the url extracted from the refValue (this may be a relative or absolute Url). + final String refUrl; + final int index = refValue.indexOf(REF_CURRENT); if (index > 0) { - schemaUrl = schemaUrl.substring(0, index); - } - if(isRelativePath(schemaUrl)){ - schemaUrl = obtainAbsolutePath(parentSchema, schemaUrl); + refUrl = refValue.substring(0, index); + } else { + refUrl = refValue; } - try { - URL url = URLFactory.toURL(schemaUrl); - parentSchema = validationContext.getJsonSchemaFactory().getSchema(url); - } catch (MalformedURLException e) { - InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(schemaUrl); - parentSchema = validationContext.getJsonSchemaFactory().getSchema(is); + // This will determine the correct absolute url for the refUrl. This decision will take into + // account the current url of the parent schema. + URL schemaUrl = determineSchemaUrl(parentSchema, refUrl); + if (schemaUrl == null) { + return null; } + + // This should retrieve schemas regardless of the protocol that is in the url. + parentSchema = validationContext.getJsonSchemaFactory().getSchema(schemaUrl); + if (index < 0) { return parentSchema.findAncestor(); } else { @@ -78,41 +81,28 @@ static JsonSchema getRefSchema(JsonSchema parentSchema, ValidationContext valida } else { JsonNode node = parentSchema.getRefSchemaNode(refValue); if (node != null) { - return new JsonSchema(validationContext, refValue, node, parentSchema); + return new JsonSchema(validationContext, refValue, parentSchema.getCurrentUrl(), node, parentSchema); } } return null; } - - private static boolean isRelativePath(String schemaUrl) { - return !schemaUrl.startsWith("http"); - } - - private static String obtainAbsolutePath(JsonSchema parentSchema, String schemaUrl) { - String baseSchemaUrl = parentSchema.findAncestor().getSchemaNode().get("id").textValue(); - int index = baseSchemaUrl.lastIndexOf("/"); - baseSchemaUrl = baseSchemaUrl.substring(0, index); - - String schemaRef = schemaUrl; - - if(schemaRef.startsWith(REF_DOMAIN)){ - // from domain add ref - try { - URL url = URLFactory.toURL(baseSchemaUrl); - baseSchemaUrl = url.getProtocol()+"//"+url.getHost(); - } catch (MalformedURLException e) { - e.printStackTrace(); - } - }else if(schemaRef.startsWith(REF_RELATIVE)){ - // relative from schema - while(schemaRef.startsWith(REF_RELATIVE)){ - index = baseSchemaUrl.lastIndexOf("/"); - baseSchemaUrl = baseSchemaUrl.substring(0, index); - schemaRef = schemaRef.replaceFirst(REF_RELATIVE, ""); - } - } - schemaRef = baseSchemaUrl +"/"+ schemaRef; - return schemaRef; + + private static URL determineSchemaUrl(JsonSchema parentSchema, String refUrl) { + URL schemaUrl; + try { + // If the refUrl is an absolute url, then this will succeed. + schemaUrl = URLFactory.toURL(refUrl); + } catch (MalformedURLException e) { + try { + // If the refUrl is a valid relative url in the context of the parent schema's url, + // then this will succeed. + schemaUrl = URLFactory.toURL(parentSchema.getCurrentUrl(), refUrl); + } catch (MalformedURLException e2) { + // We are unable to resolve the reference at this point. + schemaUrl = null; + } + } + return schemaUrl; } public Set validate(JsonNode node, JsonNode rootNode, String at) { diff --git a/src/main/java/com/networknt/schema/SchemaValidatorsConfig.java b/src/main/java/com/networknt/schema/SchemaValidatorsConfig.java index bdb16ba67..63e440fbb 100644 --- a/src/main/java/com/networknt/schema/SchemaValidatorsConfig.java +++ b/src/main/java/com/networknt/schema/SchemaValidatorsConfig.java @@ -16,9 +16,9 @@ package com.networknt.schema; +import java.net.URL; import java.util.HashMap; import java.util.Map; -import java.net.URL; public class SchemaValidatorsConfig { /** @@ -60,7 +60,7 @@ public Map getUrlMappings() { public void setUrlMappings(Map urlMappings) { this.urlMappings = urlMappings; } - + public boolean isMissingNodeAsError() { return missingNodeAsError; } diff --git a/src/main/java/com/networknt/schema/UnionTypeValidator.java b/src/main/java/com/networknt/schema/UnionTypeValidator.java index 159f3648f..5d6d97729 100644 --- a/src/main/java/com/networknt/schema/UnionTypeValidator.java +++ b/src/main/java/com/networknt/schema/UnionTypeValidator.java @@ -50,7 +50,7 @@ public UnionTypeValidator(String schemaPath, JsonNode schemaNode, JsonSchema par sep = ", "; if (n.isObject()) - schemas.add(new JsonSchema(validationContext, ValidatorTypeCode.TYPE.getValue(), n, parentSchema)); + schemas.add(new JsonSchema(validationContext, ValidatorTypeCode.TYPE.getValue(), parentSchema.getCurrentUrl(), n, parentSchema)); else schemas.add(new TypeValidator(schemaPath + "/" + i, n, parentSchema, validationContext)); diff --git a/src/main/java/com/networknt/schema/url/URLFactory.java b/src/main/java/com/networknt/schema/url/URLFactory.java index d78deecc0..430980c1a 100644 --- a/src/main/java/com/networknt/schema/url/URLFactory.java +++ b/src/main/java/com/networknt/schema/url/URLFactory.java @@ -32,13 +32,24 @@ public class URLFactory { private static final ClasspathURLStreamHandler sClasspathURLStreamHandler = new ClasspathURLStreamHandler(); + /** + * Creates an {@link URL} based on the provided string and parent url. + * @param parentUrl the parent URL of the given url (if no parent exists, then this can be null). + * @param url the url + * @return a {@link URL} + * @throws MalformedURLException if the url is not a proper URL + */ + public static URL toURL(final URL parentUrl, final String url) throws MalformedURLException { + return new URL(parentUrl, url, sClasspathURLStreamHandler.supports(url) ? sClasspathURLStreamHandler : null); + } + /** * Creates an {@link URL} based on the provided string - * @param pURL the url + * @param url the url * @return a {@link URL} * @throws MalformedURLException if the url is not a proper URL */ - public static URL toURL(final String pURL) throws MalformedURLException { - return new URL(null, pURL, sClasspathURLStreamHandler.supports(pURL) ? sClasspathURLStreamHandler : null); + public static URL toURL(final String url) throws MalformedURLException { + return new URL(null, url, sClasspathURLStreamHandler.supports(url) ? sClasspathURLStreamHandler : null); } } \ No newline at end of file diff --git a/src/test/java/com/networknt/schema/JsonSchemaTest.java b/src/test/java/com/networknt/schema/JsonSchemaTest.java index 636f55163..1b64a25fb 100644 --- a/src/test/java/com/networknt/schema/JsonSchemaTest.java +++ b/src/test/java/com/networknt/schema/JsonSchemaTest.java @@ -265,6 +265,11 @@ public void testRefRemoteValidator() throws Exception { runTestFile("tests/refRemote.json"); } + @Test + public void testRelativeRefRemoteValidator() throws Exception { + runTestFile("tests/relativeRefRemote.json"); + } + @Test public void testRequiredValidator() throws Exception { runTestFile("tests/required.json"); diff --git a/src/test/java/com/networknt/schema/SelfRefTest.java b/src/test/java/com/networknt/schema/SelfRefTest.java index 70f6e27de..5e591392a 100644 --- a/src/test/java/com/networknt/schema/SelfRefTest.java +++ b/src/test/java/com/networknt/schema/SelfRefTest.java @@ -16,16 +16,56 @@ package com.networknt.schema; -import com.fasterxml.jackson.databind.JsonNode; +import java.net.MalformedURLException; +import java.net.URL; + import org.junit.Test; +import com.fasterxml.jackson.databind.JsonNode; +import com.networknt.schema.url.URLFactory; + /** * Created by stevehu on 2016-12-20. */ public class SelfRefTest extends BaseJsonSchemaValidatorTest { @Test - public void testSelfRef() throws Exception { - JsonNode node = getJsonNodeFromClasspath("selfref.json"); - System.out.println("node = " + node); + public void urlBehavior() throws MalformedURLException + { + final URL rootUrl = new URL("http://localhost:1234"); + final URL rootIdUrl = new URL("http://localhost:1234/asdfasdf"); + final URL relUrl = new URL(rootUrl, "foo/"); + final URL domainUrl = new URL(relUrl, "/asdf"); + + final URL fooUrl = new URL(relUrl, "foo.json"); + final URL barUrl = new URL(fooUrl, "bar.json"); + final URL subUrl = new URL(fooUrl, "../bar"); + + System.out.println(rootUrl); + System.out.println(rootIdUrl); + System.out.println(relUrl); + System.out.println(domainUrl); + System.out.println(fooUrl); + System.out.println(barUrl); + System.out.println(subUrl); + + System.out.println(URLFactory.toURL("classpath:/tests/schema.json")); + System.out.println(URLFactory.toURL("resource:/tests/schema.json")); + } + @Test + public void urlBehavior2() throws MalformedURLException + { + System.out.println(isAbsolute("http://localhost:1234")); + System.out.println(isAbsolute("/asdfasdf")); + System.out.println(isAbsolute("asdfasdf.json")); + } + + private static boolean isAbsolute(String url) + { + try { + new URL(url); + return true; + } catch (MalformedURLException e) { + return false; + } } } diff --git a/src/test/resources/selfref.json b/src/test/resources/selfref.json deleted file mode 100644 index edd98edd5..000000000 --- a/src/test/resources/selfref.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "tree": { - "$ref": "#/definitions/tree" - } - }, - "definitions": { - "tree": { - "type": "object", - "properties": { - "value": { - "type": "string" - }, - "branches": { - "type": "array", - "items": { - "$ref": "#/definitions/tree" - }, - "minItems": 1 - } - }, - "required": [ - "value" - ] - } - } -} diff --git a/src/test/resources/tests/refRemoteSchema.json b/src/test/resources/tests/refRemoteSchema.json new file mode 100644 index 000000000..f4447ef31 --- /dev/null +++ b/src/test/resources/tests/refRemoteSchema.json @@ -0,0 +1,3 @@ +{ + "$ref" : "subschemas.json#/integer" +} \ No newline at end of file diff --git a/src/test/resources/tests/relativeRefRemote.json b/src/test/resources/tests/relativeRefRemote.json new file mode 100644 index 000000000..da853adef --- /dev/null +++ b/src/test/resources/tests/relativeRefRemote.json @@ -0,0 +1,105 @@ +[ + { + "description": "remote ref", + "schema": {"$ref": "integer.json"}, + "tests": [ + { + "description": "remote ref valid", + "data": 1, + "valid": true + }, + { + "description": "remote ref invalid", + "data": "a", + "valid": false + } + ] + }, + { + "description": "fragment within remote ref", + "schema": {"$ref": "subSchemas.json#/integer"}, + "tests": [ + { + "description": "remote fragment valid", + "data": 1, + "valid": true + }, + { + "description": "remote fragment invalid", + "data": "a", + "valid": false + } + ] + }, + { + "description": "ref within remote ref", + "schema": { + "$ref": "refRemoveSchema.json" + }, + "tests": [ + { + "description": "ref within ref valid", + "data": 1, + "valid": true + }, + { + "description": "ref within ref invalid", + "data": "a", + "valid": false + } + ] + }, + { + "description": "change resolution scope", + "schema": { + "items": { + "id": "folder/", + "items": {"$ref": "folderInteger.json"} + } + }, + "tests": [ + { + "description": "changed scope ref valid", + "data": [[1]], + "valid": true + }, + { + "description": "changed scope ref invalid", + "data": [["a"]], + "valid": false + } + ] + }, + { + "description": "sub directory reference with ref", + "schema": {"$ref": "self_ref/../subSchemas.json#/integer"}, + "tests": [ + { + "description": "remote fragment valid", + "data": 1, + "valid": true + }, + { + "description": "remote fragment invalid", + "data": "a", + "valid": false + } + ] + }, + { + "description": "domain reference with ref", + "schema": {"$ref": "/tests/integer.json"}, + "tests": [ + { + "description": "remote ref valid", + "data": 1, + "valid": true + }, + { + "description": "remote ref invalid", + "data": "a", + "valid": false + } + ] + } +] From 708bec8b1723f089703979d409d1aa9f0985d5e4 Mon Sep 17 00:00:00 2001 From: Jake Waffle Date: Fri, 3 May 2019 15:12:45 -0700 Subject: [PATCH 2/9] Fixed some issues with the previous commit and made it so that schemas have to be valid for the unit tests. --- .../java/com/networknt/schema/JsonSchema.java | 2 +- .../networknt/schema/JsonSchemaFactory.java | 78 ++++++++++++------- .../com/networknt/schema/JsonSchemaTest.java | 28 ++++--- .../com/networknt/schema/SelfRefTest.java | 71 ----------------- .../resources/tests/folder/folderInteger.json | 3 + .../resources/tests/relativeRefRemote.json | 2 +- 6 files changed, 72 insertions(+), 112 deletions(-) delete mode 100644 src/test/java/com/networknt/schema/SelfRefTest.java create mode 100644 src/test/resources/tests/folder/folderInteger.json diff --git a/src/main/java/com/networknt/schema/JsonSchema.java b/src/main/java/com/networknt/schema/JsonSchema.java index bc9e6a23a..cafd6b7e9 100644 --- a/src/main/java/com/networknt/schema/JsonSchema.java +++ b/src/main/java/com/networknt/schema/JsonSchema.java @@ -73,8 +73,8 @@ private JsonSchema(ValidationContext validationContext, String schemaPath, URL super(schemaPath, schemaNode, parent, null, suppressSubSchemaRetrieval); this.validationContext = validationContext; this.config = validationContext.getConfig(); - this.validators = Collections.unmodifiableMap(this.read(schemaNode)); this.currentUrl = this.combineCurrentUrlWithIds(currentUrl, schemaNode); + this.validators = Collections.unmodifiableMap(this.read(schemaNode)); } private URL combineCurrentUrlWithIds(URL currentUrl, JsonNode schemaNode) { diff --git a/src/main/java/com/networknt/schema/JsonSchemaFactory.java b/src/main/java/com/networknt/schema/JsonSchemaFactory.java index 763b7e5fe..908ec5308 100644 --- a/src/main/java/com/networknt/schema/JsonSchemaFactory.java +++ b/src/main/java/com/networknt/schema/JsonSchemaFactory.java @@ -42,7 +42,6 @@ public static class Builder { private String defaultMetaSchemaURI; private Map jsonMetaSchemas = new HashMap(); private Map urlMap = new HashMap(); - private URL rootSchemaUrl = null; public Builder objectMapper(ObjectMapper objectMapper) { this.objectMapper = objectMapper; @@ -76,12 +75,6 @@ public Builder addUrlMappings(Map map) { return this; } - public Builder setRootSchemaUrl(URL rootSchemaUrl) - { - this.rootSchemaUrl = rootSchemaUrl; - return this; - } - public JsonSchemaFactory build() { // create builtin keywords with (custom) formats. return new JsonSchemaFactory( @@ -89,8 +82,7 @@ public JsonSchemaFactory build() { urlFetcher == null ? new StandardURLFetcher(): urlFetcher, defaultMetaSchemaURI, jsonMetaSchemas, - urlMap, - rootSchemaUrl + urlMap ); } } @@ -100,14 +92,12 @@ public JsonSchemaFactory build() { private final String defaultMetaSchemaURI; private final Map jsonMetaSchemas; private final Map urlMap; - private final URL rootSchemaUrl; private JsonSchemaFactory( ObjectMapper mapper, URLFetcher urlFetcher, String defaultMetaSchemaURI, - Map jsonMetaSchemas, Map urlMap, - URL rootSchemaUrl) { + Map jsonMetaSchemas, Map urlMap) { if (mapper == null) { throw new IllegalArgumentException("ObjectMapper must not be null"); } @@ -131,7 +121,6 @@ private JsonSchemaFactory( this.urlFetcher = urlFetcher; this.jsonMetaSchemas = jsonMetaSchemas; this.urlMap = urlMap; - this.rootSchemaUrl = rootSchemaUrl; } /** @@ -163,14 +152,13 @@ public static Builder builder(JsonSchemaFactory blueprint) { .urlFetcher(blueprint.urlFetcher) .defaultMetaSchemaURI(blueprint.defaultMetaSchemaURI) .objectMapper(blueprint.mapper) - .addUrlMappings(blueprint.urlMap) - .setRootSchemaUrl(blueprint.rootSchemaUrl); + .addUrlMappings(blueprint.urlMap); } - private JsonSchema newJsonSchema(JsonNode schemaNode, SchemaValidatorsConfig config) { + private JsonSchema newJsonSchema(URL schemaUrl, JsonNode schemaNode, SchemaValidatorsConfig config) { final ValidationContext validationContext = createValidationContext(schemaNode); validationContext.setConfig(config); - JsonSchema jsonSchema = new JsonSchema(validationContext, this.rootSchemaUrl, schemaNode); + JsonSchema jsonSchema = new JsonSchema(validationContext, schemaUrl, schemaNode); return jsonSchema; } @@ -188,11 +176,21 @@ private JsonMetaSchema findMetaSchemaForSchema(JsonNode schemaNode) { } return jsonMetaSchema; } - + public JsonSchema getSchema(String schema, SchemaValidatorsConfig config) { try { final JsonNode schemaNode = mapper.readTree(schema); - return newJsonSchema(schemaNode, config); + return newJsonSchema(null, schemaNode, config); + } catch (IOException ioe) { + logger.error("Failed to load json schema!", ioe); + throw new JsonSchemaException(ioe); + } + } + + public JsonSchema getSchema(URL schemaUrl, String schema, SchemaValidatorsConfig config) { + try { + final JsonNode schemaNode = mapper.readTree(schema); + return newJsonSchema(schemaUrl, schemaNode, config); } catch (IOException ioe) { logger.error("Failed to load json schema!", ioe); throw new JsonSchemaException(ioe); @@ -200,13 +198,27 @@ public JsonSchema getSchema(String schema, SchemaValidatorsConfig config) { } public JsonSchema getSchema(String schema) { - return getSchema(schema, null); + return getSchema(null, schema, null); + } + + public JsonSchema getSchema(URL schemaUrl, String schema) { + return getSchema(schemaUrl, schema, null); } public JsonSchema getSchema(InputStream schemaStream, SchemaValidatorsConfig config) { try { final JsonNode schemaNode = mapper.readTree(schemaStream); - return newJsonSchema(schemaNode, config); + return newJsonSchema(null, schemaNode, config); + } catch (IOException ioe) { + logger.error("Failed to load json schema!", ioe); + throw new JsonSchemaException(ioe); + } + } + + public JsonSchema getSchema(URL schemaUrl, InputStream schemaStream, SchemaValidatorsConfig config) { + try { + final JsonNode schemaNode = mapper.readTree(schemaStream); + return newJsonSchema(schemaUrl, schemaNode, config); } catch (IOException ioe) { logger.error("Failed to load json schema!", ioe); throw new JsonSchemaException(ioe); @@ -214,7 +226,11 @@ public JsonSchema getSchema(InputStream schemaStream, SchemaValidatorsConfig con } public JsonSchema getSchema(InputStream schemaStream) { - return getSchema(schemaStream, null); + return getSchema(null, schemaStream, null); + } + + public JsonSchema getSchema(URL schemaUrl, InputStream schemaStream) { + return getSchema(schemaUrl, schemaStream, null); } public JsonSchema getSchema(URL schemaURL, SchemaValidatorsConfig config) { @@ -232,7 +248,7 @@ public JsonSchema getSchema(URL schemaURL, SchemaValidatorsConfig config) { return new JsonSchema(new ValidationContext(jsonMetaSchema, this), mappedURL, schemaNode, true /*retrieved via id, resolving will not change anything*/); } - return newJsonSchema(schemaNode, config); + return newJsonSchema(mappedURL, schemaNode, config); } finally { if (inputStream != null) { inputStream.close(); @@ -245,15 +261,23 @@ public JsonSchema getSchema(URL schemaURL, SchemaValidatorsConfig config) { } public JsonSchema getSchema(URL schemaURL) { - return getSchema(schemaURL, null); + return getSchema(schemaURL, new SchemaValidatorsConfig()); } public JsonSchema getSchema(JsonNode jsonNode, SchemaValidatorsConfig config) { - return newJsonSchema(jsonNode, config); + return newJsonSchema(null, jsonNode, config); } - + public JsonSchema getSchema(JsonNode jsonNode) { - return newJsonSchema(jsonNode, null); + return newJsonSchema(null, jsonNode, null); + } + + public JsonSchema getSchema(URL schemaUrl, JsonNode jsonNode, SchemaValidatorsConfig config) { + return newJsonSchema(schemaUrl, jsonNode, config); + } + + public JsonSchema getSchema(URL schemaUrl, JsonNode jsonNode) { + return newJsonSchema(schemaUrl, jsonNode, null); } private boolean idMatchesSourceUrl(JsonMetaSchema metaSchema, JsonNode schema, URL schemaUrl) { diff --git a/src/test/java/com/networknt/schema/JsonSchemaTest.java b/src/test/java/com/networknt/schema/JsonSchemaTest.java index 1b64a25fb..df7961980 100644 --- a/src/test/java/com/networknt/schema/JsonSchemaTest.java +++ b/src/test/java/com/networknt/schema/JsonSchemaTest.java @@ -16,15 +16,7 @@ package com.networknt.schema; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ArrayNode; -import io.undertow.Undertow; -import io.undertow.server.handlers.resource.FileResourceManager; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; +import static io.undertow.Handlers.resource; import java.io.File; import java.io.InputStream; @@ -32,7 +24,18 @@ import java.util.ArrayList; import java.util.List; -import static io.undertow.Handlers.resource; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.networknt.schema.url.URLFactory; + +import io.undertow.Undertow; +import io.undertow.server.handlers.resource.FileResourceManager; public class JsonSchemaTest { protected ObjectMapper mapper = new ObjectMapper(); @@ -67,6 +70,7 @@ public static void tearDown() throws Exception { } private void runTestFile(String testCaseFile) throws Exception { + final URL testCaseFileUrl = URLFactory.toURL("classpath:" + testCaseFile); InputStream in = Thread.currentThread().getContextClassLoader() .getResourceAsStream(testCaseFile); ArrayNode testCases = (ArrayNode) mapper.readTree(in); @@ -84,7 +88,7 @@ private void runTestFile(String testCaseFile) throws Exception { // Configure the schemaValidator to set typeLoose's value based on the test file, // if test file do not contains typeLoose flag, use default value: true. config.setTypeLoose((typeLooseNode == null) ? true : typeLooseNode.asBoolean()); - JsonSchema schema = validatorFactory.getSchema(testCase.get("schema"), config); + JsonSchema schema = validatorFactory.getSchema(testCaseFileUrl, testCase.get("schema"), config); List errors = new ArrayList(); errors.addAll(schema.validate(node)); @@ -106,7 +110,7 @@ private void runTestFile(String testCaseFile) throws Exception { } } } catch (JsonSchemaException e) { - System.out.println("Bypass validation due to invalid schema: " + e.getMessage()); + throw new IllegalStateException(String.format("Current schema should not be invalid: %s", testCaseFile), e); } } } diff --git a/src/test/java/com/networknt/schema/SelfRefTest.java b/src/test/java/com/networknt/schema/SelfRefTest.java deleted file mode 100644 index 5e591392a..000000000 --- a/src/test/java/com/networknt/schema/SelfRefTest.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2016 Network New Technologies Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.networknt.schema; - -import java.net.MalformedURLException; -import java.net.URL; - -import org.junit.Test; - -import com.fasterxml.jackson.databind.JsonNode; -import com.networknt.schema.url.URLFactory; - -/** - * Created by stevehu on 2016-12-20. - */ -public class SelfRefTest extends BaseJsonSchemaValidatorTest { - @Test - public void urlBehavior() throws MalformedURLException - { - final URL rootUrl = new URL("http://localhost:1234"); - final URL rootIdUrl = new URL("http://localhost:1234/asdfasdf"); - final URL relUrl = new URL(rootUrl, "foo/"); - final URL domainUrl = new URL(relUrl, "/asdf"); - - final URL fooUrl = new URL(relUrl, "foo.json"); - final URL barUrl = new URL(fooUrl, "bar.json"); - final URL subUrl = new URL(fooUrl, "../bar"); - - System.out.println(rootUrl); - System.out.println(rootIdUrl); - System.out.println(relUrl); - System.out.println(domainUrl); - System.out.println(fooUrl); - System.out.println(barUrl); - System.out.println(subUrl); - - System.out.println(URLFactory.toURL("classpath:/tests/schema.json")); - System.out.println(URLFactory.toURL("resource:/tests/schema.json")); - } - @Test - public void urlBehavior2() throws MalformedURLException - { - System.out.println(isAbsolute("http://localhost:1234")); - System.out.println(isAbsolute("/asdfasdf")); - System.out.println(isAbsolute("asdfasdf.json")); - } - - private static boolean isAbsolute(String url) - { - try { - new URL(url); - return true; - } catch (MalformedURLException e) { - return false; - } - } -} diff --git a/src/test/resources/tests/folder/folderInteger.json b/src/test/resources/tests/folder/folderInteger.json new file mode 100644 index 000000000..85d2db663 --- /dev/null +++ b/src/test/resources/tests/folder/folderInteger.json @@ -0,0 +1,3 @@ +{ + "type": "integer" +} \ No newline at end of file diff --git a/src/test/resources/tests/relativeRefRemote.json b/src/test/resources/tests/relativeRefRemote.json index da853adef..81277d895 100644 --- a/src/test/resources/tests/relativeRefRemote.json +++ b/src/test/resources/tests/relativeRefRemote.json @@ -34,7 +34,7 @@ { "description": "ref within remote ref", "schema": { - "$ref": "refRemoveSchema.json" + "$ref": "refRemoteSchema.json" }, "tests": [ { From 298fc58ff1c7e11bbed3e357cfa89fd8992496c5 Mon Sep 17 00:00:00 2001 From: Jake Waffle Date: Fri, 3 May 2019 15:22:01 -0700 Subject: [PATCH 3/9] Removed unused imports and variables. --- src/main/java/com/networknt/schema/RefValidator.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/java/com/networknt/schema/RefValidator.java b/src/main/java/com/networknt/schema/RefValidator.java index f3e61c260..539467070 100644 --- a/src/main/java/com/networknt/schema/RefValidator.java +++ b/src/main/java/com/networknt/schema/RefValidator.java @@ -16,9 +16,7 @@ package com.networknt.schema; -import java.io.InputStream; import java.net.MalformedURLException; -import java.net.URI; import java.net.URL; import java.text.MessageFormat; import java.util.Collections; @@ -35,9 +33,7 @@ public class RefValidator extends BaseJsonValidator implements JsonValidator { protected JsonSchema schema; - private static final String REF_DOMAIN = "/"; private static final String REF_CURRENT = "#"; - private static final String REF_RELATIVE = "../"; public RefValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { From c74aadf14f89c1612ece9def2c7f3d37913fc1b8 Mon Sep 17 00:00:00 2001 From: Jake Waffle Date: Fri, 3 May 2019 16:14:11 -0700 Subject: [PATCH 4/9] Added a test that I previously deleted and fixed it so that it correctly reproduces the problem described in issue #12. --- .../com/networknt/schema/SelfRefTest.java | 32 +++++++++++++++++++ src/test/resources/selfRef.json | 31 ++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 src/test/java/com/networknt/schema/SelfRefTest.java create mode 100644 src/test/resources/selfRef.json diff --git a/src/test/java/com/networknt/schema/SelfRefTest.java b/src/test/java/com/networknt/schema/SelfRefTest.java new file mode 100644 index 000000000..b1165558f --- /dev/null +++ b/src/test/java/com/networknt/schema/SelfRefTest.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2016 Network New Technologies Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.networknt.schema; + +import org.junit.Ignore; +import org.junit.Test; + +/** + * Created by stevehu on 2016-12-20. + */ +public class SelfRefTest extends BaseJsonSchemaValidatorTest { + @Ignore("This test currently is failing because of a StackOverflow caused by a recursive $ref.") + @Test() + public void testSelfRef() throws Exception { + JsonSchema node = getJsonSchemaFromClasspath("selfRef.json"); + System.out.println("node = " + node); + } +} \ No newline at end of file diff --git a/src/test/resources/selfRef.json b/src/test/resources/selfRef.json new file mode 100644 index 000000000..385c25d84 --- /dev/null +++ b/src/test/resources/selfRef.json @@ -0,0 +1,31 @@ +{ + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "tree": { + "$ref": "#/definitions/tree" + } + }, + "definitions": { + "tree": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "branches": { + "type": "array", + "items": { + "$ref": "#/definitions/tree" + }, + "minItems": 1 + } + }, + "required": [ + "value" + ] + } + } +} \ No newline at end of file From 4adbc380bc3101a3a60444cd3449b026014df390 Mon Sep 17 00:00:00 2001 From: Jake Waffle Date: Fri, 3 May 2019 17:20:40 -0700 Subject: [PATCH 5/9] Updated the travis JDK version to OpenJDK11. Java 1.8 now requires a special license in order to use in production, so it's probably safe to eliminate full support for it. The issues that exist in Java 1.8 are only relevant to relative values that have upper case characters. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 8bc14a93e..7820926c3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,4 +5,4 @@ cache: - $HOME/.m2 jdk: - - oraclejdk8 + - openjdk11 From bb6cbf326c1c66e2f62d5b9d593e53e77f096be7 Mon Sep 17 00:00:00 2001 From: Jake Waffle Date: Fri, 3 May 2019 17:33:27 -0700 Subject: [PATCH 6/9] Fixed the actual problem that I was running into and reverted the JDK version back to 1.8. I just was skipping the problematic unit test due to some problems in my dev environment. --- .travis.yml | 2 +- src/test/resources/tests/refRemoteSchema.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7820926c3..8bc14a93e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,4 +5,4 @@ cache: - $HOME/.m2 jdk: - - openjdk11 + - oraclejdk8 diff --git a/src/test/resources/tests/refRemoteSchema.json b/src/test/resources/tests/refRemoteSchema.json index f4447ef31..7dc6b7593 100644 --- a/src/test/resources/tests/refRemoteSchema.json +++ b/src/test/resources/tests/refRemoteSchema.json @@ -1,3 +1,3 @@ { - "$ref" : "subschemas.json#/integer" + "$ref" : "subSchemas.json#/integer" } \ No newline at end of file From 8be9498c4f6831333cb3c11f0c0921741609e7da Mon Sep 17 00:00:00 2001 From: Jake Waffle Date: Mon, 6 May 2019 08:10:29 -0700 Subject: [PATCH 7/9] Removed the factory methods that I added previously. Someone could get the same behavior by supplying a schemaUrl and utilizing a custom URLFetcher. --- .../networknt/schema/JsonSchemaFactory.java | 40 +------------------ 1 file changed, 2 insertions(+), 38 deletions(-) diff --git a/src/main/java/com/networknt/schema/JsonSchemaFactory.java b/src/main/java/com/networknt/schema/JsonSchemaFactory.java index 908ec5308..79317f6aa 100644 --- a/src/main/java/com/networknt/schema/JsonSchemaFactory.java +++ b/src/main/java/com/networknt/schema/JsonSchemaFactory.java @@ -187,24 +187,10 @@ public JsonSchema getSchema(String schema, SchemaValidatorsConfig config) { } } - public JsonSchema getSchema(URL schemaUrl, String schema, SchemaValidatorsConfig config) { - try { - final JsonNode schemaNode = mapper.readTree(schema); - return newJsonSchema(schemaUrl, schemaNode, config); - } catch (IOException ioe) { - logger.error("Failed to load json schema!", ioe); - throw new JsonSchemaException(ioe); - } - } - public JsonSchema getSchema(String schema) { - return getSchema(null, schema, null); + return getSchema(schema, null); } - public JsonSchema getSchema(URL schemaUrl, String schema) { - return getSchema(schemaUrl, schema, null); - } - public JsonSchema getSchema(InputStream schemaStream, SchemaValidatorsConfig config) { try { final JsonNode schemaNode = mapper.readTree(schemaStream); @@ -215,24 +201,10 @@ public JsonSchema getSchema(InputStream schemaStream, SchemaValidatorsConfig con } } - public JsonSchema getSchema(URL schemaUrl, InputStream schemaStream, SchemaValidatorsConfig config) { - try { - final JsonNode schemaNode = mapper.readTree(schemaStream); - return newJsonSchema(schemaUrl, schemaNode, config); - } catch (IOException ioe) { - logger.error("Failed to load json schema!", ioe); - throw new JsonSchemaException(ioe); - } - } - public JsonSchema getSchema(InputStream schemaStream) { - return getSchema(null, schemaStream, null); + return getSchema(schemaStream, null); } - public JsonSchema getSchema(URL schemaUrl, InputStream schemaStream) { - return getSchema(schemaUrl, schemaStream, null); - } - public JsonSchema getSchema(URL schemaURL, SchemaValidatorsConfig config) { try { InputStream inputStream = null; @@ -271,14 +243,6 @@ public JsonSchema getSchema(JsonNode jsonNode, SchemaValidatorsConfig config) { public JsonSchema getSchema(JsonNode jsonNode) { return newJsonSchema(null, jsonNode, null); } - - public JsonSchema getSchema(URL schemaUrl, JsonNode jsonNode, SchemaValidatorsConfig config) { - return newJsonSchema(schemaUrl, jsonNode, config); - } - - public JsonSchema getSchema(URL schemaUrl, JsonNode jsonNode) { - return newJsonSchema(schemaUrl, jsonNode, null); - } private boolean idMatchesSourceUrl(JsonMetaSchema metaSchema, JsonNode schema, URL schemaUrl) { From e3b4c4a862534e6fc06ccda3a84b402b1c24a900 Mon Sep 17 00:00:00 2001 From: Jake Waffle Date: Mon, 6 May 2019 08:18:18 -0700 Subject: [PATCH 8/9] I was a bit hasty in my last commit. There is a use case for supplying a URL along with a JsonNode. The schema could be embedded into a json file and may still need to have a URL location (we use this for testing purposes and I broke our tests with the last commit). --- .../java/com/networknt/schema/JsonSchemaFactory.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/java/com/networknt/schema/JsonSchemaFactory.java b/src/main/java/com/networknt/schema/JsonSchemaFactory.java index 79317f6aa..d8d5bf1e0 100644 --- a/src/main/java/com/networknt/schema/JsonSchemaFactory.java +++ b/src/main/java/com/networknt/schema/JsonSchemaFactory.java @@ -236,9 +236,18 @@ public JsonSchema getSchema(URL schemaURL) { return getSchema(schemaURL, new SchemaValidatorsConfig()); } + public JsonSchema getSchema(URL schemaUrl, JsonNode jsonNode, SchemaValidatorsConfig config) { + return newJsonSchema(schemaUrl, jsonNode, config); + } + + public JsonSchema getSchema(JsonNode jsonNode, SchemaValidatorsConfig config) { return newJsonSchema(null, jsonNode, config); } + + public JsonSchema getSchema(URL schemaUrl, JsonNode jsonNode) { + return newJsonSchema(schemaUrl, jsonNode, null); + } public JsonSchema getSchema(JsonNode jsonNode) { return newJsonSchema(null, jsonNode, null); From dc9137f29418b7ee55491fc43501130f94e44c6c Mon Sep 17 00:00:00 2001 From: Jake Waffle Date: Fri, 17 May 2019 09:59:56 -0700 Subject: [PATCH 9/9] Updated my RefValidator implementation to utilize the recently introduced URL mapping changes. --- src/main/java/com/networknt/schema/RefValidator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/networknt/schema/RefValidator.java b/src/main/java/com/networknt/schema/RefValidator.java index 539467070..4d1c7af4d 100644 --- a/src/main/java/com/networknt/schema/RefValidator.java +++ b/src/main/java/com/networknt/schema/RefValidator.java @@ -64,7 +64,7 @@ static JsonSchema getRefSchema(JsonSchema parentSchema, ValidationContext valida } // This should retrieve schemas regardless of the protocol that is in the url. - parentSchema = validationContext.getJsonSchemaFactory().getSchema(schemaUrl); + parentSchema = validationContext.getJsonSchemaFactory().getSchema(schemaUrl, validationContext.getConfig()); if (index < 0) { return parentSchema.findAncestor();