Skip to content

Commit 767f24f

Browse files
committed
Merge branch 'develop' of github.com:networknt/json-schema-validator into develop
2 parents a000f78 + e97d280 commit 767f24f

File tree

7 files changed

+229
-4
lines changed

7 files changed

+229
-4
lines changed

src/main/java/com/networknt/schema/JsonSchemaFactory.java

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ public static class Builder {
4141
private URLFetcher urlFetcher;
4242
private String defaultMetaSchemaURI;
4343
private Map<String, JsonMetaSchema> jsonMetaSchemas = new HashMap<String, JsonMetaSchema>();
44+
private Map<URL, URL> urlMap = new HashMap<URL, URL>();
4445

4546
public Builder objectMapper(ObjectMapper objectMapper) {
4647
this.objectMapper = objectMapper;
@@ -69,13 +70,19 @@ public Builder addMetaSchemas(Collection<? extends JsonMetaSchema> jsonMetaSchem
6970
return this;
7071
}
7172

73+
public Builder addUrlMappings(Map<URL, URL> map) {
74+
this.urlMap.putAll(map);
75+
return this;
76+
}
77+
7278
public JsonSchemaFactory build() {
7379
// create builtin keywords with (custom) formats.
7480
return new JsonSchemaFactory(
7581
objectMapper == null ? new ObjectMapper() : objectMapper,
7682
urlFetcher == null ? new StandardURLFetcher(): urlFetcher,
7783
defaultMetaSchemaURI,
78-
jsonMetaSchemas
84+
jsonMetaSchemas,
85+
urlMap
7986
);
8087
}
8188
}
@@ -84,8 +91,9 @@ public JsonSchemaFactory build() {
8491
private final URLFetcher urlFetcher;
8592
private final String defaultMetaSchemaURI;
8693
private final Map<String, JsonMetaSchema> jsonMetaSchemas;
94+
private final Map<URL, URL> urlMap;
8795

88-
private JsonSchemaFactory(ObjectMapper mapper, URLFetcher urlFetcher, String defaultMetaSchemaURI, Map<String, JsonMetaSchema> jsonMetaSchemas) {
96+
private JsonSchemaFactory(ObjectMapper mapper, URLFetcher urlFetcher, String defaultMetaSchemaURI, Map<String, JsonMetaSchema> jsonMetaSchemas, Map<URL, URL> urlMap) {
8997
if (mapper == null) {
9098
throw new IllegalArgumentException("ObjectMapper must not be null");
9199
}
@@ -101,10 +109,14 @@ private JsonSchemaFactory(ObjectMapper mapper, URLFetcher urlFetcher, String def
101109
if (jsonMetaSchemas.get(defaultMetaSchemaURI) == null) {
102110
throw new IllegalArgumentException("Meta Schema for default Meta Schema URI must be provided");
103111
}
112+
if (urlMap == null) {
113+
throw new IllegalArgumentException("URL Mappings must not be null");
114+
}
104115
this.mapper = mapper;
105116
this.defaultMetaSchemaURI = defaultMetaSchemaURI;
106117
this.urlFetcher = urlFetcher;
107118
this.jsonMetaSchemas = jsonMetaSchemas;
119+
this.urlMap = urlMap;
108120
}
109121

110122
/**
@@ -135,7 +147,8 @@ public static Builder builder(JsonSchemaFactory blueprint) {
135147
.addMetaSchemas(blueprint.jsonMetaSchemas.values())
136148
.urlFetcher(blueprint.urlFetcher)
137149
.defaultMetaSchemaURI(blueprint.defaultMetaSchemaURI)
138-
.objectMapper(blueprint.mapper);
150+
.objectMapper(blueprint.mapper)
151+
.addUrlMappings(blueprint.urlMap);
139152
}
140153

141154
private JsonSchema newJsonSchema(JsonNode schemaNode, SchemaValidatorsConfig config) {
@@ -191,8 +204,11 @@ public JsonSchema getSchema(InputStream schemaStream) {
191204
public JsonSchema getSchema(URL schemaURL, SchemaValidatorsConfig config) {
192205
try {
193206
InputStream inputStream = null;
207+
Map<URL, URL> map = (config != null) ? config.getUrlMappings() : new HashMap<URL, URL>(urlMap);
208+
map.putAll(urlMap);
209+
URL mappedURL = map.getOrDefault(schemaURL, schemaURL);
194210
try {
195-
inputStream = urlFetcher.fetch(schemaURL);
211+
inputStream = urlFetcher.fetch(mappedURL);
196212
JsonNode schemaNode = mapper.readTree(inputStream);
197213
final JsonMetaSchema jsonMetaSchema = findMetaSchemaForSchema(schemaNode);
198214

src/main/java/com/networknt/schema/SchemaValidatorsConfig.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@
1616

1717
package com.networknt.schema;
1818

19+
import java.util.HashMap;
20+
import java.util.Map;
21+
import java.net.URL;
22+
1923
public class SchemaValidatorsConfig {
2024
/**
2125
* when validate type, if TYPE_LOOSE = true, will try to convert string to different types to match the type defined in schema.
@@ -34,6 +38,13 @@ public class SchemaValidatorsConfig {
3438
*/
3539
private boolean elementValidationError = false;
3640

41+
/**
42+
* Map of public, normally internet accessible schema URLs to alternate locations; this allows for offline
43+
* validation of schemas that refer to public URLs. This is merged with any mappings the {@link JsonSchemaFactory}
44+
* may have been built with.
45+
*/
46+
private Map<URL, URL> urlMappings = new HashMap<URL, URL>();
47+
3748
public boolean isTypeLoose() {
3849
return typeLoose;
3950
}
@@ -42,6 +53,14 @@ public void setTypeLoose(boolean typeLoose) {
4253
this.typeLoose = typeLoose;
4354
}
4455

56+
public Map<URL, URL> getUrlMappings() {
57+
return new HashMap<URL, URL>(urlMappings);
58+
}
59+
60+
public void setUrlMappings(Map<URL, URL> urlMappings) {
61+
this.urlMappings = urlMappings;
62+
}
63+
4564
public boolean isMissingNodeAsError() {
4665
return missingNodeAsError;
4766
}
@@ -64,5 +83,6 @@ public SchemaValidatorsConfig() {
6483

6584
private void loadDefaultConfig() {
6685
this.typeLoose = true;
86+
this.urlMappings = new HashMap<URL, URL>();
6787
}
6888
}
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
package com.networknt.schema;
2+
3+
import java.io.FileNotFoundException;
4+
import java.io.IOException;
5+
import java.net.MalformedURLException;
6+
import java.net.URL;
7+
import java.net.UnknownHostException;
8+
import java.util.HashMap;
9+
import java.util.Map;
10+
11+
import com.fasterxml.jackson.databind.JsonNode;
12+
import com.fasterxml.jackson.databind.ObjectMapper;
13+
import com.networknt.schema.JsonSchemaFactory.Builder;
14+
import com.networknt.schema.url.URLFactory;
15+
16+
import org.junit.Test;
17+
18+
import static org.junit.Assert.assertEquals;
19+
import static org.junit.Assert.fail;
20+
21+
public class UrlMappingTest {
22+
23+
private final ObjectMapper mapper = new ObjectMapper();
24+
25+
/**
26+
* Validate that a JSON URL Mapping file containing the URL Mapping schema is
27+
* schema valid.
28+
*
29+
* @throws IOException if unable to parse the mapping file
30+
*/
31+
@Test
32+
public void testBuilderUrlMappingUrl() throws IOException {
33+
URL mappings = URLFactory.toURL("resource:tests/url_mapping/url-mapping.json");
34+
JsonMetaSchema draftV4 = JsonMetaSchema.getDraftV4();
35+
Builder builder = JsonSchemaFactory.builder()
36+
.defaultMetaSchemaURI(draftV4.getUri())
37+
.addMetaSchema(draftV4)
38+
.addUrlMappings(getUrlMappingsFromUrl(mappings));
39+
JsonSchemaFactory instance = builder.build();
40+
JsonSchema schema = instance.getSchema(new URL(
41+
"https://raw.githubusercontent.com/networknt/json-schema-validator/master/src/test/resources/tests/url_mapping/url-mapping.schema.json"));
42+
assertEquals(0, schema.validate(mapper.readTree(mappings)).size());
43+
}
44+
45+
/**
46+
* Validate that local URL is used when attempting to get a schema that is not
47+
* available publicly. Use the URL http://example.com/invalid/schema/url to use
48+
* a public URL that returns a 404 Not Found. The locally mapped schema is a
49+
* valid, but empty schema.
50+
*
51+
* @throws IOException if unable to parse the mapping file
52+
*/
53+
@Test
54+
public void testBuilderExampleMappings() throws IOException {
55+
JsonSchemaFactory instance = JsonSchemaFactory.getInstance();
56+
URL example = new URL("http://example.com/invalid/schema/url");
57+
// first test that attempting to use example URL throws an error
58+
try {
59+
JsonSchema schema = instance.getSchema(example);
60+
schema.validate(mapper.createObjectNode());
61+
fail("Expected exception not thrown");
62+
} catch (JsonSchemaException ex) {
63+
Throwable cause = ex.getCause();
64+
if (!(cause instanceof FileNotFoundException || cause instanceof UnknownHostException)) {
65+
fail("Unexpected cause for JsonSchemaException");
66+
}
67+
// passing, so do nothing
68+
} catch (Exception ex) {
69+
fail("Unexpected exception thrown");
70+
}
71+
URL mappings = URLFactory.toURL("resource:tests/url_mapping/invalid-schema-url.json");
72+
JsonMetaSchema draftV4 = JsonMetaSchema.getDraftV4();
73+
Builder builder = JsonSchemaFactory.builder()
74+
.defaultMetaSchemaURI(draftV4.getUri())
75+
.addMetaSchema(draftV4)
76+
.addUrlMappings(getUrlMappingsFromUrl(mappings));
77+
instance = builder.build();
78+
JsonSchema schema = instance.getSchema(example);
79+
assertEquals(0, schema.validate(mapper.createObjectNode()).size());
80+
}
81+
82+
/**
83+
* Validate that a JSON URL Mapping file containing the URL Mapping schema is
84+
* schema valid.
85+
*
86+
* @throws IOException if unable to parse the mapping file
87+
*/
88+
@Test
89+
public void testValidatorConfigUrlMappingUrl() throws IOException {
90+
JsonSchemaFactory instance = JsonSchemaFactory.getInstance();
91+
URL mappings = URLFactory.toURL("resource:tests/url_mapping/url-mapping.json");
92+
SchemaValidatorsConfig config = new SchemaValidatorsConfig();
93+
config.setUrlMappings(getUrlMappingsFromUrl(mappings));
94+
JsonSchema schema = instance.getSchema(new URL(
95+
"https://raw.githubusercontent.com/networknt/json-schema-validator/master/src/test/resources/tests/url_mapping/url-mapping.schema.json"),
96+
config);
97+
assertEquals(0, schema.validate(mapper.readTree(mappings)).size());
98+
}
99+
100+
/**
101+
* Validate that local URL is used when attempting to get a schema that is not
102+
* available publicly. Use the URL http://example.com/invalid/schema/url to use
103+
* a public URL that returns a 404 Not Found. The locally mapped schema is a
104+
* valid, but empty schema.
105+
*
106+
* @throws IOException if unable to parse the mapping file
107+
*/
108+
@Test
109+
public void testValidatorConfigExampleMappings() throws IOException {
110+
JsonSchemaFactory instance = JsonSchemaFactory.getInstance();
111+
SchemaValidatorsConfig config = new SchemaValidatorsConfig();
112+
URL example = new URL("http://example.com/invalid/schema/url");
113+
// first test that attempting to use example URL throws an error
114+
try {
115+
JsonSchema schema = instance.getSchema(example, config);
116+
schema.validate(mapper.createObjectNode());
117+
fail("Expected exception not thrown");
118+
} catch (JsonSchemaException ex) {
119+
Throwable cause = ex.getCause();
120+
if (!(cause instanceof FileNotFoundException || cause instanceof UnknownHostException)) {
121+
fail("Unexpected cause for JsonSchemaException");
122+
}
123+
// passing, so do nothing
124+
} catch (Exception ex) {
125+
fail("Unexpected exception thrown");
126+
}
127+
URL mappings = URLFactory.toURL("resource:tests/url_mapping/invalid-schema-url.json");
128+
config.setUrlMappings(getUrlMappingsFromUrl(mappings));
129+
JsonSchema schema = instance.getSchema(example, config);
130+
assertEquals(0, schema.validate(mapper.createObjectNode()).size());
131+
}
132+
133+
private Map<URL, URL> getUrlMappingsFromUrl(URL url) throws MalformedURLException, IOException {
134+
HashMap<URL, URL> map = new HashMap<URL, URL>();
135+
for (JsonNode mapping : mapper.readTree(url)) {
136+
map.put(URLFactory.toURL(mapping.get("publicURL").asText()),
137+
URLFactory.toURL(mapping.get("localURL").asText()));
138+
}
139+
return map;
140+
}
141+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-04/schema#"
3+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[
2+
{
3+
"publicURL": "http://json-schema.org/draft-04/schema#",
4+
"localURL": "resource:/draftv4.schema.json"
5+
},
6+
{
7+
"publicURL": "http://example.com/invalid/schema/url",
8+
"localURL": "resource:/tests/url_mapping/example-schema.json"
9+
}
10+
]
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[
2+
{
3+
"publicURL": "http://json-schema.org/draft-04/schema#",
4+
"localURL": "resource:/draftv4.schema.json"
5+
},
6+
{
7+
"publicURL": "https://raw.githubusercontent.com/networknt/json-schema-validator/master/src/test/resources/tests/url_mapping/url-mapping.schema.json",
8+
"localURL": "resource:/tests/url_mapping/url-mapping.schema.json"
9+
}
10+
]
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-04/schema#",
3+
"title": "json-schema-validator-url-mapping",
4+
"type": "array",
5+
"description": "Data portion of message from JMRI to client for type \"node\"",
6+
"items": {
7+
"type": "object",
8+
"uniqueItems": true,
9+
"properties": {
10+
"publicURL": {
11+
"type": "string",
12+
"description": "Public, presumably internet-accessible, URL for schema"
13+
},
14+
"localURL": {
15+
"type": "string",
16+
"description": "Local URL for schema that will be used when a schema references the public URL"
17+
}
18+
},
19+
"additionalProperties": false,
20+
"required": [
21+
"publicURL",
22+
"localURL"
23+
]
24+
}
25+
}

0 commit comments

Comments
 (0)