Requirements:
I want to apply some functions on the inner values of the JsonNode
. The functions can be different eg:- lowercasing
some values or appending something to the values or replace the values with something. How can I achieve that using Jackson
library? Note that the structure of the JSON data can be different which means I want to build a generic system which will accept some path expression which will basically decide where to change. I want to use functional programming style, so that I can pass these functions as arguments.
eg:
input:
{
"name": "xyz",
"values": [
{
"id": "xyz1",
"sal": "1234",
"addresses": [
{
"id": "add1",
"name": "ABCD",
"dist": "123"
},
{
"id": "add2",
"name": "abcd3",
"dist": "345"
}
]
},
{
"id": "xyz2",
"sal": "3456",
"addresses": [
{
"id": "add1",
"name": "abcd",
"dist": "123"
},
{
"id": "add2",
"name": "XXXXX",
"dist": "345"
}
]
}
]
}
In this case I have to two functions basically, lowercase()
and convert_to_number()
. I want to apply lowercase()
function on all the "name"
attribute inside all the "addresses"
of each "value"
.
same goes for convert_to_number()
, but for all the "dist"
attribute.
So, basically the JSON
expressions will be something like below for the functions:
lowercase() : /values/*/addresses/*/name
convert_to_number() : /values/*/addresses/*/dist
output:
{
"name": "xyz",
"values": [
{
"id": "xyz1",
"sal": "1234",
"addresses": [
{
"id": "add1",
"name": "abcd",
"dist": 123
},
{
"id": "add2",
"name": "abcd3",
"dist": 345
}
]
},
{
"id": "xyz2",
"sal": "3456",
"addresses": [
{
"id": "add1",
"name": "abcd",
"dist": 123
},
{
"id": "add2",
"name": "xxxx",
"dist": 345
}
]
}
]
}
Client code:
JsonNode jsonNode = ...
applyFunctionsRecursivelyBasedOnExpr(JsonNode jsonNode, String expr, Function )
JsonPath
You could use
JsonPath
library which has a betterJSON Path
handling. WhenJackson
supports only JSON Pointer draft-ietf-appsawg-json-pointer-03. Take a look on JsonPointer documentation. WithJsonPath
library you could do that in this way:Your path, should work on
JSON object
-s which are represented byMap<String, Object>
. You can replace keys in given object, add them, remove them just like replacing, adding and removing keys inMap
.Jackson
You can of course mock
JsonPath
feature by iterating overJson 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:This solution is slower than with
JsonPath
because we need to travers wholeJSON
treen
times wheren
number of matching nodes. Of course, our implementation could be a much faster usingStreaming API
.As @MichalZiober in his answer already pointed out, JsonPath offers a much more powerful API than Jackson, when you need to do JSON-path-based operations.
Using methods
JsonPath.parse
andDocumentContext.map
you can solve your problem in just a few lines: