Skip to content

Commit 2c1537c

Browse files
committed
improving error handling in LoadingState#childFor()
Properly handling nonexistent map keys and invalid array indices: * added hashCode - equals to SchemaException, for asserts * added #getRawChildOfObject() and #getRawElemOfArray() to LoadingState * a bunch of unittests
1 parent 2bf560d commit 2c1537c

File tree

5 files changed

+97
-14
lines changed

5 files changed

+97
-14
lines changed

core/src/main/java/org/everit/json/schema/SchemaException.java

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
package org.everit.json.schema;
22

3-
import org.json.JSONPointer;
4-
5-
import java.util.Collection;
6-
import java.util.List;
7-
83
import static java.lang.String.format;
94
import static java.util.Arrays.asList;
105
import static java.util.Objects.requireNonNull;
116
import static java.util.stream.Collectors.joining;
127

8+
import java.util.Collection;
9+
import java.util.List;
10+
1311
/**
1412
* Thrown by {@link org.everit.json.schema.loader.SchemaLoader#load()} when it encounters
1513
* un-parseable schema JSON definition.
@@ -102,6 +100,21 @@ public SchemaException(String message, Throwable cause) {
102100
this.schemaLocation = null;
103101
}
104102

103+
@Override public boolean equals(Object o) {
104+
if (this == o)
105+
return true;
106+
if (o == null || getClass() != o.getClass())
107+
return false;
108+
109+
SchemaException that = (SchemaException) o;
110+
111+
return toString().equals(that.toString());
112+
}
113+
114+
@Override public int hashCode() {
115+
return toString().hashCode();
116+
}
117+
105118
public String getSchemaLocation() {
106119
return schemaLocation;
107120
}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ static final JsonPointerEvaluator forURL(SchemaClient schemaClient, String url,
142142
*/
143143
public QueryResult query() {
144144
JsonObject document = documentProvider.get();
145+
System.out.println(document);
145146
if (fragment.isEmpty()) {
146147
return new QueryResult(document, document);
147148
}
@@ -174,10 +175,12 @@ private String unescape(String token) {
174175

175176
private JsonValue queryFrom(JsonValue document, LinkedList<String> tokens) {
176177
String key = unescape(tokens.poll());
178+
System.out.println(key + " , " + document);
177179
JsonValue next = document.canBeMappedTo(JsonObject.class, obj -> obj.childFor(key))
178180
.orMappedTo(JsonArray.class, arr -> arr.at(Integer.parseInt(key)))
179181
.requireAny();
180182

183+
System.out.println("next: " + next);
181184
if (tokens.isEmpty()) {
182185
return next;
183186
}

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

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.everit.json.schema.loader;
22

3+
import static java.lang.String.format;
34
import static java.util.Objects.requireNonNull;
45
import static org.apache.commons.collections.ListUtils.unmodifiableList;
56
import static org.everit.json.schema.loader.SpecificationVersion.DRAFT_6;
@@ -84,14 +85,34 @@ SchemaLoader.SchemaLoaderBuilder initChildLoader() {
8485
return rval;
8586
}
8687

88+
private Object getRawChildOfObject(JsonObject obj, String key) {
89+
if (!((Map<String, Object>) obj.unwrap()).containsKey(key)) {
90+
throw createSchemaException(format("key [%s] not found", key));
91+
}
92+
return ((Map<String, Object>) obj.unwrap()).get(key);
93+
}
94+
95+
private Object getRawElemOfArray(JsonArray array, String rawIndex) {
96+
List<?> raw = (List<?>) array.unwrap();
97+
try {
98+
int index = Integer.parseInt(rawIndex);
99+
if (raw.size() <= index) {
100+
throw createSchemaException(format("array index [%d] is out of bounds", index));
101+
}
102+
return raw.get(index);
103+
} catch (NumberFormatException e) {
104+
throw createSchemaException(format("[%s] is not an array index", rawIndex));
105+
}
106+
}
107+
87108
JsonValue childFor(String key) {
88109
List<String> newPtr = new ArrayList<>(pointerToCurrentObj.size() + 1);
89110
newPtr.addAll(pointerToCurrentObj);
90111
newPtr.add(key);
91112

92113
Object rawChild = schemaJson
93-
.canBeMappedTo(JsonObject.class, schemaJsonObj -> ((Map<String, Object>) schemaJsonObj.unwrap()).get(key))
94-
.orMappedTo(JsonArray.class, schemaJsonArray -> ((List<?>) schemaJsonArray.unwrap()).get(Integer.parseInt(key)))
114+
.canBeMappedTo(JsonObject.class, obj -> getRawChildOfObject(obj, key))
115+
.orMappedTo(JsonArray.class, array -> getRawElemOfArray(array, key))
95116
.requireAny();
96117

97118
LoadingState childLs = new LoadingState(

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ private JsonObject lookupObjById(JsonValue val, String idAttrVal) {
117117
* Returns a schema builder instance after looking up the JSON pointer.
118118
*/
119119
Schema.Builder<?> lookup(String relPointerString, JsonObject ctx) {
120+
System.out.println(ls.rootSchemaJson());
120121
if (isSameDocumentRef(relPointerString)) {
121122
if (ls.pointerSchemas.containsKey(relPointerString)) {
122123
return ls.pointerSchemas.get(relPointerString);
@@ -132,6 +133,7 @@ Schema.Builder<?> lookup(String relPointerString, JsonObject ctx) {
132133
ReferenceSchema.Builder refBuilder = ReferenceSchema.builder()
133134
.refValue(relPointerString);
134135
ls.pointerSchemas.put(relPointerString, refBuilder);
136+
System.out.println(rawInternalReferenced);
135137
Schema referredSchema = new SchemaLoader(rawInternalReferenced.ls).load().build();
136138
refBuilder.build().setReferredSchema(referredSchema);
137139
return refBuilder;

core/src/test/java/org/everit/json/schema/loader/LoadingStateTest.java

Lines changed: 51 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import static java.util.Collections.emptyMap;
66
import static org.everit.json.schema.loader.JsonValueTest.withLs;
77
import static org.junit.Assert.assertEquals;
8+
import static org.junit.Assert.fail;
89

910
import java.util.HashMap;
1011
import java.util.Map;
@@ -27,27 +28,31 @@ private LoadingState emptySubject() {
2728

2829
@Test
2930
public void childForString() {
30-
LoadingState ls = emptySubject();
31+
LoadingState ls = helloWorldObjState();
3132
LoadingState actual = ls.childFor("hello").ls;
3233
assertEquals(asList("hello"), actual.pointerToCurrentObj);
3334
}
3435

3536
@Test
3637
public void childForSecond() {
38+
LoadingState ls = helloWorldObjState();
39+
LoadingState actual = ls.childFor("hello").requireObject().childFor("world").ls;
40+
assertEquals(asList("hello", "world"), actual.pointerToCurrentObj);
41+
}
42+
43+
protected LoadingState helloWorldObjState() {
3744
Map<String, Object> rawObj = new HashMap<>();
3845
Map<String, Object> worldObj = new HashMap<>();
3946
worldObj.put("world", true);
4047
rawObj.put("hello", worldObj);
41-
LoadingState ls = withLs(JsonValue.of(rawObj)).ls;
42-
LoadingState actual = ls.childFor("hello").requireObject().childFor("world").ls;
43-
assertEquals(asList("hello", "world"), actual.pointerToCurrentObj);
48+
return withLs(JsonValue.of(rawObj)).ls;
4449
}
4550

4651
@Test
4752
public void childForArrayIndex() {
48-
LoadingState ls = emptySubject();
49-
LoadingState actual = ls.childFor(42).ls;
50-
assertEquals(asList("42"), actual.pointerToCurrentObj);
53+
LoadingState subject = singleElemArrayState();
54+
LoadingState actual = subject.childFor(0).ls;
55+
assertEquals(asList("0"), actual.pointerToCurrentObj);
5156
}
5257

5358
@Test
@@ -58,4 +63,43 @@ public void testCreateSchemaException() {
5863
assertEquals(JSONPointer.builder().build().toURIFragment(), actual.getSchemaLocation());
5964
}
6065

66+
@Test
67+
public void testChildForFailure_NotFound() {
68+
LoadingState ls = helloWorldObjState();
69+
try {
70+
ls.childFor("nonexistent");
71+
fail("did not throw exception for nonexistent key");
72+
} catch (SchemaException e) {
73+
SchemaException expected = new SchemaException("#", "key [nonexistent] not found");
74+
assertEquals(expected, e);
75+
}
76+
}
77+
78+
@Test
79+
public void testChildForArrayFailure_NotFound() {
80+
LoadingState subject = singleElemArrayState();
81+
try {
82+
subject.childFor(1);
83+
fail("did not throw exception");
84+
} catch (SchemaException e) {
85+
SchemaException expected = new SchemaException("#", "array index [1] is out of bounds");
86+
assertEquals(expected, e);
87+
}
88+
}
89+
90+
@Test
91+
public void invalidArrayIndex() {
92+
try {
93+
singleElemArrayState().childFor("key");
94+
fail("did not throw exception");
95+
} catch (SchemaException e) {
96+
SchemaException expected = new SchemaException("#", "[key] is not an array index");
97+
assertEquals(expected, e);
98+
}
99+
}
100+
101+
protected LoadingState singleElemArrayState() {
102+
return withLs(JsonValue.of(asList("elem"))).ls;
103+
}
104+
61105
}

0 commit comments

Comments
 (0)