private static void applyMask(Map.Entry<String, JsonNode> entry, DocumentContext ctx) { Object value; String jsonPath = entry.getKey(); try { value = ctx.read(jsonPath); if (!(value instanceof String || value instanceof Integer || value instanceof List<?>)) { logger.error("The value specified by path {} cannot be masked", jsonPath); } else { if (!(value instanceof List<?>)) { ctx.set(jsonPath, replaceWithMask(value.toString(), MASK_REPLACEMENT_CHAR.charAt(0), entry.getValue().asText())); } else if(value instanceof List<?>){ for(Object ele : (List)value) { if(!(ele instanceof String)) { logger.error("json path: {} is incorrect, cannot mask an object", jsonPath); return; } } maskList(ctx, jsonPath, entry.getValue().asText()); } } } catch (PathNotFoundException e) { logger.warn("JsonPath {} could not be found.", jsonPath); } } private static void maskList(DocumentContext ctx, String jsonPath, String expression) {
@Test public void issue_171() { String json = "{\n" + " \"can delete\": \"this\",\n" + " \"can't delete\": \"this\"\n" + "}"; DocumentContext context = using(JACKSON_JSON_NODE_CONFIGURATION).parse(json); context.set("$.['can delete']", null); context.set("$.['can\\'t delete']", null); ObjectNode objectNode = context.read("$"); assertThat(objectNode.get("can delete").isNull()); assertThat(objectNode.get("can't delete").isNull()); }
@Test(expected = InvalidModificationException.class) public void root_object_can_not_be_updated() { Map model = new HashMap(); model.put("a", "a-val"); parse(model).set("$[?(@.a == 'a-val')]", 1); }
@Test public void an_array_index_can_be_updated() { String res = parse(JSON_DOCUMENT).set("$.store.book[0]", "a").read("$.store.book[0]"); assertThat(res).isEqualTo("a"); }
private static void maskList(DocumentContext ctx, String jsonPath, String expression) { ctx.configuration().addOptions(Option.AS_PATH_LIST); Configuration conf = Configuration.builder().options(Option.AS_PATH_LIST).build(); DocumentContext context = JsonPath.using(conf).parse(ctx.jsonString()); List<String> pathList = context.read(jsonPath); /** * when reach here, ctx.read(jsonPath) should only give us a list of strings so that we can replace with MASK_REPLACEMENT_CHAR * list of values can belongs to a same path or different paths, we should treat differently. * two situations: * an array contains multiple String values like: "list": ["ab", "cd", "ef] * or single value belongs to different paths. */ if(pathList != null && pathList.size() == 1) { String path = pathList.get(0); List values = ctx.read(path); JSONArray maskedValue = new JSONArray(); //mask each value in the list of the same path values.forEach(o -> maskedValue.add(replaceWithMask(o.toString(), MASK_REPLACEMENT_CHAR.charAt(0), expression))); ctx.set(path, maskedValue); } else { for (String path : Optional.ofNullable(pathList).orElse(Collections.emptyList())) { Object value = ctx.read(path); ctx.set(path, replaceWithMask(value.toString(), MASK_REPLACEMENT_CHAR.charAt(0), expression)); } } }
@Test public void issue_309(){ String json = "{\n" + "\"jsonArr\": [\n" + " {\n" + " \"name\":\"nOne\"\n" + " },\n" + " {\n" + " \"name\":\"nTwo\"\n" + " }\n" + " ]\n" + "}"; DocumentContext doc = JsonPath.parse(json).set("$.jsonArr[1].name", "Jayway"); assertThat((String)doc.read("$.jsonArr[0].name")).isEqualTo("nOne"); assertThat((String)doc.read("$.jsonArr[1].name")).isEqualTo("Jayway"); }
@Test public void issue_170() { String json = "{\n" + " \"array\": [\n" + " 0,\n" + " 1,\n" + " 2\n" + " ]\n" + "}"; DocumentContext context = using(JACKSON_JSON_NODE_CONFIGURATION).parse(json); context = context.set("$.array[0]", null); context = context.set("$.array[2]", null); List<Integer> list = context.read("$.array", List.class); assertThat(list).containsExactly(null, 1, null); }
@Test public void an_array_criteria_can_be_updated() { List<String> res = parse(JSON_DOCUMENT) .set("$.store.book[?(@.category == 'fiction')]", "a") .read("$.store.book[?(@ == 'a')]"); assertThat(res).containsExactly("a", "a", "a"); }
@Test public void an_root_property_can_be_updated() { Object o = parse(JSON_DOCUMENT).set("$.int-max-property", 1).json(); Integer result = parse(o).read("$.int-max-property"); assertThat(result).isEqualTo(1); }
@Test public void an_array_slice_can_be_updated() { List<String> res = parse(JSON_DOCUMENT).set("$.store.book[0:2]", "a").read("$.store.book[0:2]"); assertThat(res).containsExactly("a", "a"); }
@Test public void an_array_can_be_updated() { List<Integer> ints = parse("[0,1,2,3]").set("$[?(@ == 1)]", 9).json(); assertThat(ints).containsExactly(0, 9, 2, 3); }
@Test public void an_array_child_property_can_be_updated() { Object o = parse(JSON_DOCUMENT).set("$.store.book[*].display-price", 1).json(); List<Integer> result = parse(o).read("$.store.book[*].display-price"); assertThat(result).containsExactly(1, 1, 1, 1); }
@Test public void an_deep_scan_can_update() { Object o = parse(JSON_DOCUMENT).set("$..display-price", 1).json(); List<Integer> result = parse(o).read("$..display-price"); assertThat(result).containsExactly(1, 1, 1, 1, 1); }
@Test public void an_filter_can_update() { Object o = parse(JSON_DOCUMENT).set("$.store.book[?(@.display-price)].display-price", 1).json(); List<Integer> result = parse(o).read("$.store.book[?(@.display-price)].display-price"); assertThat(result).containsExactly(1, 1, 1, 1); }
@Test public void multi_prop_update() { Map<String, Object> expected = new HashMap<String, Object>(){{ put("author", "a"); put("category", "a"); }}; List<Map<String, Object>> res = parse(JSON_DOCUMENT).set("$.store.book[*]['author', 'category']", "a").read("$.store.book[*]['author', 'category']"); assertThat(res).containsExactly(expected, expected, expected, expected); }
@Test public void multi_prop_update_not_all_defined() { Map<String, Object> expected = new HashMap<String, Object>(){{ put("author", "a"); put("isbn", "a"); }}; List<Map<String, Object>> res = parse(JSON_DOCUMENT).set("$.store.book[*]['author', 'isbn']", "a").read("$.store.book[*]['author', 'isbn']"); assertThat(res).containsExactly(expected, expected, expected, expected); }
@Test public void operations_can_chained() { Object o = parse(JSON_DOCUMENT) .delete("$.store.book[*].display-price") .set("$.store.book[*].category", "A") .json(); List<Integer> prices = parse(o).read("$.store.book[*].display-price"); List<String> categories = parse(o).read("$.store.book[*].category"); assertThat(prices).isEmpty(); assertThat(categories).containsExactly("A", "A", "A", "A"); }
public static String forCards(String body) { DocumentContext context = JsonPath.using(configuration).parse(body); context.set("$.cards[?(@.id =~ /" + UUID_PATTERN + "/)].id", DUMMY_UUID); context.set("$.cards[?(@.creation_date =~ /" + DATE_PATTERN + "/)].creation_date", DUMMY_DATE_TIME); context.set("$.cards[?(@.expiration_date =~ /" + DATE_PATTERN + "/)].expiration_date", DUMMY_DATE_TIME); context.set("$.cards[*].actions[?(@.id =~ /" + UUID_PATTERN + "/)].id", DUMMY_UUID); return context.jsonString(); } }
/** * Sets a new value at the given path. * @param path The JSON path * @param value The new value * @param filters Optional JSON path filters * @return The new JSON fixture */ public JsonFixture set(final String path, final Object value, final Predicate... filters) { return new JsonFixture(cloneContext().set(path, value, filters)); }
private static void replace(DocumentContext dc, Rule rule) { Object oldValue = dc.read(rule.getPath()); if (oldValue instanceof Collection && !(rule.getValue() instanceof Collection)) { throw new IllegalTemplateConfigurationException("cannot replace collection value with non-collection value"); } else if (oldValue instanceof Map && !(rule.getValue() instanceof Map)) { throw new IllegalTemplateConfigurationException("cannot replace map value with non-map value"); } dc.set(rule.getPath(), rule.getValue()); } }