Requirements:
I want to apply some functions on the inner values of the JsonNode
. The functions can be different eg:- lowercasing
some values o
You could use JsonPath library which has a better JSON Path
handling. When Jackson
supports only JSON Pointer draft-ietf-appsawg-json-pointer-03. Take a look on JsonPointer documentation. With JsonPath
library you could do that in this way:
import com.jayway.jsonpath.DocumentContext;
import com.jayway.jsonpath.JsonPath;
import net.minidev.json.JSONArray;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
public class JsonPathApp {
public static void main(String[] args) throws Exception {
File jsonFile = new File("./resource/test.json").getAbsoluteFile();
JsonModifier jsonModifier = new JsonModifier(jsonFile);
Function
Your path, should work on JSON object
-s which are represented by Map
. You can replace keys in given object, add them, remove them just like replacing, adding and removing keys in Map
.
You can of course mock JsonPath
feature by iterating over Json Pointer
. For each *
we need to create loop and iterate over it using counter and until node is not missing. Below you can see simple implementation:
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.io.File;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
public class JsonApp {
public static void main(String[] args) throws Exception {
File jsonFile = new File("./resource/test.json").getAbsoluteFile();
ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT);
JsonNode root = mapper.readTree(jsonFile);
Function lowerCaseName = node -> {
final String key = "name";
node.put(key, node.get(key).asText().toLowerCase());
return null;
};
Function changeDistToNumber = node -> {
final String key = "dist";
node.put(key, Integer.parseInt(node.get(key).asText()));
return null;
};
JsonModifier jsonModifier = new JsonModifier(root);
jsonModifier.updateAddresses(Arrays.asList(lowerCaseName, changeDistToNumber));
System.out.println(mapper.writeValueAsString(root));
}
}
class JsonModifier {
private final JsonNode root;
public JsonModifier(JsonNode root) {
this.root = root;
}
public void updateAddresses(List> transformers) {
String path = "/values/%d/addresses/%d";
for (int v = 0; v < 100; v++) {
int a = 0;
do {
JsonNode address = root.at(String.format(path, v, a++));
if (address.isMissingNode()) {
break;
}
if (address.isObject()) {
transformers.forEach(t -> t.apply((ObjectNode) address));
}
} while (true);
if (a == 0) {
break;
}
}
}
}
This solution is slower than with JsonPath
because we need to travers whole JSON
tree n
times where n
number of matching nodes. Of course, our implementation could be a much faster using Streaming API.