Skip to content

Commit 8664d3c

Browse files
authored
Fix hasAdjacentKeywordInEvaluationPath optimisation (#1124)
1 parent c7b264e commit 8664d3c

File tree

2 files changed

+94
-13
lines changed

2 files changed

+94
-13
lines changed

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

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -392,29 +392,18 @@ public String toString() {
392392
*/
393393
protected boolean hasAdjacentKeywordInEvaluationPath(String keyword) {
394394
JsonSchema schema = getEvaluationParentSchema();
395-
boolean checkInstance = false;
396-
boolean anchor = false;
397-
boolean stop = false;
398395
while (schema != null) {
399396
for (JsonValidator validator : schema.getValidators()) {
400397
if (keyword.equals(validator.getKeyword())) {
401398
return true;
402399
}
403-
if (checkInstance) {
404-
if ("properties".equals(validator.getKeyword()) || "items".equals(validator.getKeyword())) {
405-
stop = true;
406-
} else if ("$dynamicAnchor".equals(validator.getKeyword()) || "$recursiveAnchor".equals(validator.getKeyword())) {
407-
anchor = true;
408-
}
409-
}
410400
}
411-
if (stop && !anchor) {
401+
Object element = schema.getEvaluationPath().getElement(-1);
402+
if ("properties".equals(element) || "items".equals(element)) {
412403
// If there is a change in instance location then return false
413404
return false;
414405
}
415406
schema = schema.getEvaluationParentSchema();
416-
checkInstance = true;
417-
anchor = false;
418407
}
419408
return false;
420409
}

src/test/java/com/networknt/schema/UnevaluatedPropertiesValidatorTest.java

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,18 @@
1717
package com.networknt.schema;
1818

1919
import static org.junit.jupiter.api.Assertions.assertEquals;
20+
import static org.junit.jupiter.api.Assertions.assertTrue;
2021

22+
import java.util.HashMap;
2123
import java.util.List;
24+
import java.util.Map;
2225
import java.util.Set;
2326
import java.util.stream.Collectors;
2427

2528
import org.junit.jupiter.api.Test;
2629

2730
import com.networknt.schema.SpecVersion.VersionFlag;
31+
import com.networknt.schema.output.OutputUnit;
2832

2933
/**
3034
* UnevaluatedPropertiesValidatorTest.
@@ -148,4 +152,92 @@ void unevaluatedPropertiesSchema() {
148152
assertEquals("type", assertions.get(0).getType());
149153
assertEquals("$.unevaluatedProperties.type", assertions.get(0).getEvaluationPath().toString());
150154
}
155+
156+
@Test
157+
void ref() {
158+
String schemaData = "{\r\n"
159+
+ " \"definitions\": {\r\n"
160+
+ " \"other\": {\r\n"
161+
+ " \"type\": \"object\",\r\n"
162+
+ " \"properties\": {\r\n"
163+
+ " \"surfboard\": {\r\n"
164+
+ " \"type\": \"string\"\r\n"
165+
+ " }\r\n"
166+
+ " }\r\n"
167+
+ " }\r\n"
168+
+ " },\r\n"
169+
+ " \"allOf\": [\r\n"
170+
+ " {\r\n"
171+
+ " \"$ref\": \"#/definitions/other\"\r\n"
172+
+ " },\r\n"
173+
+ " {\r\n"
174+
+ " \"properties\": {\r\n"
175+
+ " \"wheels\": {},\r\n"
176+
+ " \"headlights\": {}\r\n"
177+
+ " }\r\n"
178+
+ " },\r\n"
179+
+ " {\r\n"
180+
+ " \"properties\": {\r\n"
181+
+ " \"pontoons\": {}\r\n"
182+
+ " }\r\n"
183+
+ " },\r\n"
184+
+ " {\r\n"
185+
+ " \"properties\": {\r\n"
186+
+ " \"wings\": {}\r\n"
187+
+ " }\r\n"
188+
+ " }\r\n"
189+
+ " ],\r\n"
190+
+ " \"unevaluatedProperties\": false\r\n"
191+
+ "}";
192+
String inputData = "{ \"pontoons\": {}, \"wheels\": {}, \"surfboard\": \"2\" }";
193+
JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V201909).getSchema(schemaData);
194+
Set<ValidationMessage> messages = schema.validate(inputData, InputFormat.JSON);
195+
assertEquals(0, messages.size());
196+
}
197+
198+
@Test
199+
void nestedRef() {
200+
String schemaData = "{\r\n"
201+
+ " \"$schema\": \"https://json-schema.org/draft/2019-09/schema\",\r\n"
202+
+ " \"type\": \"object\",\r\n"
203+
+ " \"allOf\": [ { \"$ref\": \"https://www.example.org/PrimaryDeviceConfiguration.json#PrimaryDeviceConfiguration\" } ],\r\n"
204+
+ " \"properties\": {\r\n"
205+
+ " \"__type\": { \"const\": \"dk.cachet.carp.common.application.devices.Smartphone\" }\r\n"
206+
+ " },\r\n"
207+
+ " \"unevaluatedProperties\": false\r\n"
208+
+ "}";
209+
String primaryDeviceConfiguration = "{\r\n"
210+
+ " \"$schema\": \"https://json-schema.org/draft/2019-09/schema\",\r\n"
211+
+ " \"PrimaryDeviceConfiguration\": {\r\n"
212+
+ " \"$anchor\": \"PrimaryDeviceConfiguration\",\r\n"
213+
+ " \"allOf\": [ { \"$ref\": \"DeviceConfiguration.json#DeviceConfiguration\" } ],\r\n"
214+
+ " \"properties\": {\r\n"
215+
+ " \"isPrimaryDevice\": { \"const\": true }\r\n"
216+
+ " },\r\n"
217+
+ " \"required\": [ \"isPrimaryDevice\" ]\r\n"
218+
+ " }\r\n"
219+
+ " }";
220+
String deviceConfiguration = "{\r\n"
221+
+ " \"$schema\": \"https://json-schema.org/draft/2019-09/schema\",\r\n"
222+
+ " \"DeviceConfiguration\": {\r\n"
223+
+ " \"properties\": {\r\n"
224+
+ " \"roleName\": { \"type\": \"string\" }\r\n"
225+
+ " }\r\n"
226+
+ " }\r\n"
227+
+ "}";
228+
Map<String, String> schemas = new HashMap<>();
229+
schemas.put("https://www.example.org/PrimaryDeviceConfiguration.json", primaryDeviceConfiguration);
230+
schemas.put("https://www.example.org/DeviceConfiguration.json", deviceConfiguration);
231+
JsonSchema schema = JsonSchemaFactory
232+
.getInstance(VersionFlag.V201909,
233+
builder -> builder.schemaLoaders(schemaLoaders -> schemaLoaders.schemas(schemas)))
234+
.getSchema(schemaData);
235+
String inputData = "{ \"isPrimaryDevice\": true, \"roleName\": \"hello\" }";
236+
OutputUnit outputUnit = schema.validate(inputData, InputFormat.JSON, OutputFormat.HIERARCHICAL,
237+
executionContext -> {
238+
executionContext.getExecutionConfig().setAnnotationCollectionEnabled(false);
239+
executionContext.getExecutionConfig().setAnnotationCollectionFilter(keyword -> true);
240+
});
241+
assertTrue(outputUnit.isValid());
242+
}
151243
}

0 commit comments

Comments
 (0)