I am using Gson to parse JSON in my application. I have a particular use case where I want to take a JsonObject and effectively deep clone it, except alter the a key/value that matches some particular criteria.
For example, imagine the source object is something like this:
{
"foo": {
"bar": {
"baz": "some value here"
},
"baz": "another value here"
}
}
I want to iterate through every key (regardless how nested it might be) and if there is a key called baz
I'll run my transformation function, and my output object would look like:
{
"foo": {
"bar": {
"bazTransformed": "this got altered by my function"
},
"bazTransformed": "so did this"
}
}
I'm aware I could do something like convert the JsonObject to string and use a RegEx pattern to find and replace, but that doesn't feel right.
I'm really struggling to get my head around creating a recursive function, or at least a better solution than string manipulation.
I can start the iteration with JsonObject.entrySet()
but this returns a Map<String, JsonElement> - that seems to add more complexity because I'd need to check if the JsonElement is a JsonObject first before somehow continuing to recurse.
EDIT:
To me it seems best to convert the JsonObject to a Map like so:
gson.fromJson(sourceObj, Map::class.java) as MutableMap<*, *>
I can write a function that iterates recursively like so:
fun generateObject(sourceObj: JsonElement): JsonObject {
val inputMap = gson.fromJson(sourceObj, Map::class.java) as MutableMap<*, *>
val outputMap: MutableMap<String, Any> = mutableMapOf()
fun go(toReturn: MutableMap<String,Any>,
input: MutableMap<String, Any>) {
for ((key, value) in input) {
if (key == "baz") {
println("baz key found")
//do my transformation here
}
if (value is Map<*, *>) {
println("nested map")
go(toReturn, value as MutableMap<String, Any>)
}
// this part is wrong however, because `key` is potentially nested
outputMap[key] = value
}
}
go(outputMap, inputMap as MutableMap<String, Any>)
return gson.toJsonTree(outputMap).asJsonObject
}