• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.networknt.schema;
2 
3 import com.fasterxml.jackson.databind.JsonNode;
4 import com.fasterxml.jackson.databind.ObjectMapper;
5 import com.fasterxml.jackson.databind.node.ObjectNode;
6 import com.networknt.schema.walk.JsonSchemaWalkListener;
7 import com.networknt.schema.walk.WalkEvent;
8 import com.networknt.schema.walk.WalkFlow;
9 
10 import org.junit.jupiter.api.BeforeEach;
11 import org.junit.jupiter.api.Test;
12 
13 import java.io.IOException;
14 import java.io.InputStream;
15 import java.util.LinkedHashSet;
16 import java.util.Set;
17 import java.util.TreeSet;
18 
19 import static org.junit.jupiter.api.Assertions.assertEquals;
20 
21 public class JsonWalkTest {
22 
23     private JsonSchema jsonSchema;
24 
25     private JsonSchema jsonSchema1;
26 
27     private static final String SAMPLE_WALK_COLLECTOR_TYPE = "sampleWalkCollectorType";
28 
29     private static final String CUSTOM_KEYWORD = "custom-keyword";
30 
31     @BeforeEach
setup()32     public void setup() {
33         setupSchema();
34     }
35 
setupSchema()36     private void setupSchema() {
37         final JsonMetaSchema metaSchema = getJsonMetaSchema();
38         // Create Schema.
39         SchemaValidatorsConfig schemaValidatorsConfig = new SchemaValidatorsConfig();
40         schemaValidatorsConfig.addKeywordWalkListener(new AllKeywordListener());
41         schemaValidatorsConfig.addKeywordWalkListener(ValidatorTypeCode.REF.getValue(), new RefKeywordListener());
42         schemaValidatorsConfig.addKeywordWalkListener(ValidatorTypeCode.PROPERTIES.getValue(),
43                 new PropertiesKeywordListener());
44         final JsonSchemaFactory schemaFactory = JsonSchemaFactory
45                 .builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V201909)).metaSchema(metaSchema)
46                 .build();
47         this.jsonSchema = schemaFactory.getSchema(getSchema(), schemaValidatorsConfig);
48         // Create another Schema.
49         SchemaValidatorsConfig schemaValidatorsConfig1 = new SchemaValidatorsConfig();
50         schemaValidatorsConfig1.addKeywordWalkListener(ValidatorTypeCode.REF.getValue(), new RefKeywordListener());
51         schemaValidatorsConfig1.addKeywordWalkListener(ValidatorTypeCode.PROPERTIES.getValue(),
52                 new PropertiesKeywordListener());
53         this.jsonSchema1 = schemaFactory.getSchema(getSchema(), schemaValidatorsConfig1);
54     }
55 
getJsonMetaSchema()56     private JsonMetaSchema getJsonMetaSchema() {
57         return JsonMetaSchema.builder(
58                 "https://github.com/networknt/json-schema-validator/tests/schemas/example01", JsonMetaSchema.getV201909())
59                 .keyword(new CustomKeyword()).build();
60     }
61 
62     @Test
testWalk()63     public void testWalk() throws IOException {
64         ObjectMapper objectMapper = new ObjectMapper();
65         ValidationResult result = jsonSchema.walk(
66                 objectMapper.readTree(getClass().getClassLoader().getResourceAsStream("data/walk-data.json")), false);
67         JsonNode collectedNode = (JsonNode) result.getCollectorContext().get(SAMPLE_WALK_COLLECTOR_TYPE);
68         assertEquals(collectedNode, (objectMapper.readTree("{" +
69                 "    \"PROPERTY1\": \"sample1\","
70                 + "    \"PROPERTY2\": \"sample2\","
71                 + "    \"property3\": {"
72                 + "        \"street_address\":\"test-address\","
73                 + "        \"phone_number\": {"
74                 + "            \"country-code\": \"091\","
75                 + "            \"number\": \"123456789\""
76                 + "          }"
77                 + "     }"
78                 + "}")));
79     }
80 
81     @Test
testWalkWithDifferentListeners()82     public void testWalkWithDifferentListeners() throws IOException {
83         ObjectMapper objectMapper = new ObjectMapper();
84         // This instance of schema contains all listeners.
85         ValidationResult result = jsonSchema.walk(
86                 objectMapper.readTree(getClass().getClassLoader().getResourceAsStream("data/walk-data.json")), false);
87         JsonNode collectedNode = (JsonNode) result.getCollectorContext().get(SAMPLE_WALK_COLLECTOR_TYPE);
88         assertEquals(collectedNode, (objectMapper.readTree("{" +
89                 "    \"PROPERTY1\": \"sample1\","
90                 + "    \"PROPERTY2\": \"sample2\","
91                 + "    \"property3\": {"
92                 + "        \"street_address\":\"test-address\","
93                 + "        \"phone_number\": {"
94                 + "            \"country-code\": \"091\","
95                 + "            \"number\": \"123456789\""
96                 + "          }"
97                 + "     }"
98                 + "}")));
99         // This instance of schema contains one listener removed.
100         result = jsonSchema1.walk(objectMapper.readTree(getClass().getClassLoader().getResourceAsStream("data/walk-data.json")), false);
101         collectedNode = (JsonNode) result.getExecutionContext().getCollectorContext().get(SAMPLE_WALK_COLLECTOR_TYPE);
102         assertEquals(collectedNode, (objectMapper.readTree("{"
103                 + "    \"property3\": {"
104                 + "        \"street_address\":\"test-address\","
105                 + "        \"phone_number\": {"
106                 + "            \"country-code\": \"091\","
107                 + "            \"number\": \"123456789\""
108                 + "          }"
109                 + "     }"
110                 + "}")));
111     }
112 
getSchema()113     private InputStream getSchema() {
114         return getClass().getClassLoader().getResourceAsStream("schema/walk-schema.json");
115     }
116 
117     /**
118      * Our own custom keyword.
119      */
120     private static class CustomKeyword implements Keyword {
121         @Override
getValue()122         public String getValue() {
123             return "custom-keyword";
124         }
125 
126         @Override
newValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext)127         public JsonValidator newValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode,
128                                           JsonSchema parentSchema, ValidationContext validationContext) throws JsonSchemaException {
129             if (schemaNode != null && schemaNode.isArray()) {
130                 return new CustomValidator(schemaLocation, evaluationPath, schemaNode);
131             }
132             return null;
133         }
134 
135         /**
136          * We will be collecting information/data by adding the data in the form of
137          * collectors into collector context object while we are validating this node.
138          * This will be helpful in cases where we don't want to revisit the entire JSON
139          * document again just for gathering this kind of information.
140          */
141         private static class CustomValidator extends AbstractJsonValidator {
142 
CustomValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode)143             public CustomValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode) {
144                 super(schemaLocation, evaluationPath, new CustomKeyword(), schemaNode);
145             }
146 
147             @Override
validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation)148             public Set<ValidationMessage> validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation) {
149                 return new TreeSet<ValidationMessage>();
150             }
151 
152             @Override
walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation, boolean shouldValidateSchema)153             public Set<ValidationMessage> walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode,
154                     JsonNodePath instanceLocation, boolean shouldValidateSchema) {
155                 return new LinkedHashSet<ValidationMessage>();
156             }
157         }
158     }
159 
160     private static class AllKeywordListener implements JsonSchemaWalkListener {
161         @Override
onWalkStart(WalkEvent keywordWalkEvent)162         public WalkFlow onWalkStart(WalkEvent keywordWalkEvent) {
163             ObjectMapper mapper = new ObjectMapper();
164             String keyWordName = keywordWalkEvent.getKeyword();
165             JsonNode schemaNode = keywordWalkEvent.getSchema().getSchemaNode();
166             CollectorContext collectorContext = keywordWalkEvent.getExecutionContext().getCollectorContext();
167             if (collectorContext.get(SAMPLE_WALK_COLLECTOR_TYPE) == null) {
168                 collectorContext.add(SAMPLE_WALK_COLLECTOR_TYPE, mapper.createObjectNode());
169             }
170             if (keyWordName.equals(CUSTOM_KEYWORD) && schemaNode.get(CUSTOM_KEYWORD).isArray()) {
171                 ObjectNode objectNode = (ObjectNode) collectorContext.get(SAMPLE_WALK_COLLECTOR_TYPE);
172                 objectNode.put(keywordWalkEvent.getSchema().getSchemaNode().get("title").textValue().toUpperCase(),
173                         keywordWalkEvent.getInstanceNode().textValue());
174             }
175             return WalkFlow.CONTINUE;
176         }
177 
178         @Override
onWalkEnd(WalkEvent keywordWalkEvent, Set<ValidationMessage> validationMessages)179         public void onWalkEnd(WalkEvent keywordWalkEvent, Set<ValidationMessage> validationMessages) {
180 
181         }
182     }
183 
184     private static class RefKeywordListener implements JsonSchemaWalkListener {
185 
186         @Override
onWalkStart(WalkEvent keywordWalkEvent)187         public WalkFlow onWalkStart(WalkEvent keywordWalkEvent) {
188             ObjectMapper mapper = new ObjectMapper();
189             CollectorContext collectorContext = keywordWalkEvent.getExecutionContext().getCollectorContext();
190             if (collectorContext.get(SAMPLE_WALK_COLLECTOR_TYPE) == null) {
191                 collectorContext.add(SAMPLE_WALK_COLLECTOR_TYPE, mapper.createObjectNode());
192             }
193             ObjectNode objectNode = (ObjectNode) collectorContext.get(SAMPLE_WALK_COLLECTOR_TYPE);
194             objectNode.set(keywordWalkEvent.getSchema().getSchemaNode().get("title").textValue().toLowerCase(),
195                     keywordWalkEvent.getInstanceNode());
196             return WalkFlow.SKIP;
197         }
198 
199         @Override
onWalkEnd(WalkEvent keywordWalkEvent, Set<ValidationMessage> validationMessages)200         public void onWalkEnd(WalkEvent keywordWalkEvent, Set<ValidationMessage> validationMessages) {
201 
202         }
203     }
204 
205     private static class PropertiesKeywordListener implements JsonSchemaWalkListener {
206 
207         @Override
onWalkStart(WalkEvent keywordWalkEvent)208         public WalkFlow onWalkStart(WalkEvent keywordWalkEvent) {
209             JsonNode schemaNode = keywordWalkEvent.getSchema().getSchemaNode();
210             if (schemaNode.get("title").textValue().equals("Property3")) {
211                 return WalkFlow.SKIP;
212             }
213             return WalkFlow.CONTINUE;
214         }
215 
216         @Override
onWalkEnd(WalkEvent keywordWalkEvent, Set<ValidationMessage> validationMessages)217         public void onWalkEnd(WalkEvent keywordWalkEvent, Set<ValidationMessage> validationMessages) {
218 
219         }
220     }
221 
222 }
223