Skip to content

Commit 6ed56f9

Browse files
committed
initial classpath-based schema client implementation
1 parent ea06c38 commit 6ed56f9

File tree

10 files changed

+164
-12
lines changed

10 files changed

+164
-12
lines changed

core/pom.xml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,18 @@
128128
<breakBuildOnSourceIncompatibleModifications>
129129
true
130130
</breakBuildOnSourceIncompatibleModifications>
131+
<overrideCompatibilityChangeParameters>
132+
<overrideCompatibilityChangeParameter>
133+
<compatibilityChange>METHOD_NEW_DEFAULT</compatibilityChange>
134+
<binaryCompatible>true</binaryCompatible>
135+
<sourceCompatible>true</sourceCompatible>
136+
</overrideCompatibilityChangeParameter>
137+
<overrideCompatibilityChangeParameter>
138+
<compatibilityChange>METHOD_ABSTRACT_NOW_DEFAULT</compatibilityChange>
139+
<binaryCompatible>true</binaryCompatible>
140+
<sourceCompatible>true</sourceCompatible>
141+
</overrideCompatibilityChangeParameter>
142+
</overrideCompatibilityChangeParameters>
131143
</parameter>
132144
</configuration>
133145
<executions>
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package org.everit.json.schema.loader;
2+
3+
import static java.util.Arrays.asList;
4+
import static java.util.Collections.unmodifiableList;
5+
import static java.util.Objects.requireNonNull;
6+
7+
import java.io.InputStream;
8+
import java.util.List;
9+
import java.util.Optional;
10+
11+
class ClassPathAwareSchemaClient implements SchemaClient {
12+
13+
private static final List<String> HANDLED_PREFIXES = unmodifiableList(asList("classpath://", "classpath:/", "classpath:"));
14+
15+
private final SchemaClient fallbackClient;
16+
17+
ClassPathAwareSchemaClient(SchemaClient fallbackClient) {
18+
this.fallbackClient = requireNonNull(fallbackClient, "fallbackClient cannot be null");
19+
}
20+
21+
@Override public InputStream get(String url) {
22+
return handleProtocol(url)
23+
.map(this::loadFromClasspath)
24+
.orElseGet(() -> fallbackClient.get(url));
25+
}
26+
27+
private InputStream loadFromClasspath(String str) {
28+
return getClass().getResourceAsStream(str);
29+
}
30+
31+
private Optional<String> handleProtocol(String url) {
32+
return HANDLED_PREFIXES.stream().filter(url::startsWith)
33+
.map(prefix -> "/" + url.substring(prefix.length()))
34+
.findFirst();
35+
}
36+
37+
}

core/src/main/java/org/everit/json/schema/loader/SchemaClient.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import java.io.InputStream;
44
import java.util.function.Function;
55

6+
import org.everit.json.schema.loader.internal.DefaultSchemaClient;
7+
68
/**
79
* This interface is used by {@link SchemaLoader} to fetch the contents denoted by remote JSON
810
* pointer.
@@ -13,6 +15,10 @@
1315
@FunctionalInterface
1416
public interface SchemaClient extends Function<String, InputStream> {
1517

18+
static SchemaClient classPathAwareClient() {
19+
return new ClassPathAwareSchemaClient(new DefaultSchemaClient());
20+
}
21+
1622
@Override
1723
default InputStream apply(final String url) {
1824
return get(url);
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package org.everit.json.schema.loader;
2+
3+
import static org.everit.json.schema.JSONMatcher.sameJsonAs;
4+
import static org.junit.Assert.assertSame;
5+
import static org.junit.Assert.assertThat;
6+
import static org.mockito.Mockito.mock;
7+
import static org.mockito.Mockito.when;
8+
9+
import java.io.InputStream;
10+
11+
import org.everit.json.schema.ResourceLoader;
12+
import org.json.JSONObject;
13+
import org.json.JSONTokener;
14+
import org.junit.Before;
15+
import org.junit.Test;
16+
import org.junit.runner.RunWith;
17+
18+
import junitparams.JUnitParamsRunner;
19+
import junitparams.Parameters;
20+
21+
@RunWith(JUnitParamsRunner.class)
22+
public class ClassPathAwareSchemaClientTest {
23+
24+
private static final JSONObject EXPECTED = ResourceLoader.DEFAULT.readObj("constobject.json");
25+
26+
private SchemaClient fallbackClient;
27+
28+
@Before
29+
public void before() {
30+
fallbackClient = mock(SchemaClient.class);
31+
}
32+
33+
@Test
34+
public void delegatesUnhandledProtocolsToFallback() {
35+
InputStream expected = ResourceLoader.DEFAULT.getStream("arraytestcases.json");
36+
when(fallbackClient.get("http://example.org")).thenReturn(expected);
37+
ClassPathAwareSchemaClient subject = new ClassPathAwareSchemaClient(fallbackClient);
38+
InputStream actual = subject.get("http://example.org");
39+
assertSame(expected, actual);
40+
}
41+
42+
@Test
43+
@Parameters({
44+
"classpath:/org/everit/jsonvalidator/constobject.json",
45+
"classpath://org/everit/jsonvalidator/constobject.json",
46+
"classpath:org/everit/jsonvalidator/constobject.json"
47+
})
48+
public void success(String url) {
49+
ClassPathAwareSchemaClient subject = new ClassPathAwareSchemaClient(fallbackClient);
50+
JSONObject actual = new JSONObject(new JSONTokener(subject.get(url)));
51+
assertThat(actual, sameJsonAs(EXPECTED));
52+
}
53+
54+
}

core/src/test/java/org/everit/json/schema/loader/internal/ReferenceResolverTest.java

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,26 +15,25 @@
1515
*/
1616
package org.everit.json.schema.loader.internal;
1717

18-
import org.junit.Assert;
19-
import org.junit.Test;
20-
import org.junit.runner.RunWith;
21-
import org.junit.runners.Parameterized;
22-
import org.junit.runners.Parameterized.Parameters;
18+
import static java.util.Arrays.asList;
19+
import static org.junit.Assert.assertEquals;
20+
import static org.junit.Assert.fail;
2321

2422
import java.net.URI;
2523
import java.net.URISyntaxException;
26-
import java.util.Arrays;
2724
import java.util.List;
2825

29-
import static org.junit.Assert.assertEquals;
30-
import static org.junit.Assert.fail;
26+
import org.junit.Test;
27+
import org.junit.runner.RunWith;
28+
import org.junit.runners.Parameterized;
29+
import org.junit.runners.Parameterized.Parameters;
3130

3231
@RunWith(Parameterized.class)
3332
public class ReferenceResolverTest {
3433

3534
@Parameters(name = "{0}")
3635
public static List<Object[]> params() {
37-
return Arrays.asList(
36+
return asList(
3837
parList("fragment id", "http://x.y.z/root.json#foo", "http://x.y.z/root.json", "#foo"),
3938
parList("rel path", "http://example.org/foo", "http://example.org/bar", "foo"),
4039
parList("file name change", "http://x.y.z/schema/child.json",
@@ -44,10 +43,18 @@ public static List<Object[]> params() {
4443
"http://x.y.z/schema/", "child.json"),
4544
parList("new root", "http://bserver.com", "http://aserver.com/",
4645
"http://bserver.com"),
47-
parList("null parent", "http://a.b.c", null, "http://a.b.c"));
46+
parList("null parent", "http://a.b.c", null, "http://a.b.c"),
47+
parList("classpath single-slash",
48+
"classpath:/hello/world.json/definitions/A",
49+
"classpath:/hello/world.json/", "definitions/A"
50+
),
51+
parList("classpath double-slash",
52+
"classpath://hello/world.json#/definitions/A",
53+
"classpath://hello/world.json", "#/definitions/A"
54+
));
4855
}
4956

50-
private static Object[] parList(final String... params) {
57+
private static Object[] parList(String... params) {
5158
return params;
5259
}
5360

@@ -57,7 +64,7 @@ private static Object[] parList(final String... params) {
5764

5865
private final String encounteredSegment;
5966

60-
public ReferenceResolverTest(final String testcaseName, final String expectedOutput,
67+
public ReferenceResolverTest(String testcaseName, String expectedOutput,
6168
final String parentScope,
6269
final String encounteredSegment) {
6370
this.expectedOutput = expectedOutput;

tests/vanilla/src/main/java/org/everit/json/schema/IssueTest.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import java.util.stream.Collectors;
2323

2424
import org.apache.commons.io.IOUtils;
25+
import org.everit.json.schema.loader.SchemaClient;
2526
import org.everit.json.schema.loader.SchemaLoader;
2627
import org.everit.json.schema.regexp.RE2JRegexpFactory;
2728
import org.json.JSONArray;
@@ -135,6 +136,11 @@ private void consumeValidatorConfig() {
135136
loaderBuilder.draftV7Support();
136137
}
137138
});
139+
configKeyHandlers.put("schemaClient", value -> {
140+
if ("classPathAware".equals(value)) {
141+
loaderBuilder.schemaClient(SchemaClient.classPathAwareClient());
142+
}
143+
});
138144
fileByName("validator-config.json").map(file -> streamAsJson(file)).ifPresent(configJson -> {
139145
configKeyHandlers.entrySet()
140146
.stream()
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"definitions": {
3+
"Str": {
4+
"type": "string",
5+
"maxLength": 3
6+
},
7+
"Num": {
8+
"type": "integer",
9+
"maximum": 3
10+
}
11+
}
12+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"type": "object",
3+
"properties": {
4+
"str": {
5+
"$ref": "classpath://org/everit/json/schema/issues/issue245/definitions.json#/definitions/Str"
6+
},
7+
"num": {
8+
"$ref": "classpath:/org/everit/json/schema/issues/issue245/definitions.json#/definitions/Num"
9+
}
10+
}
11+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"str": "aaaaa",
3+
"num": 10
4+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"schemaClient": "classPathAware"
3+
}

0 commit comments

Comments
 (0)