I am trying to generate JSON output in Groovy (4.0.18) from generic SQL requests where the query is provided at runtime.
So I have captured the SQL results in a List (of ResultSets) and I captured the column names in a separate List (of Strings).
Now I just need to output it in JSON and wanted to use Groovy's JsonBuilder so I passed in the two Lists to my outputJsonResults() method where I create a JsonBuilder and try to iterate over the resultSet using the technique Paul King taught me with Groovy's XmlBuilder in a separate post.
Here's a simple example -
List columns = [ "id", "val" ]
List resultSet = [
[ id:"id1", val:"val1" ],
[ id:"id2", val:"val2" ],
[ id:"id3", val:"val3" ]]
void outputJsonResults(columns, resultSet) {
def json = new groovy.json.JsonBuilder()
json {
queryResults(
resultSet.each { row ->
columns.each { col ->
"$col"(row[col])
}
}
)
}
println json.toPrettyString()
}
outputJsonResults(columns, resultSet)
It works and generates the JSON output but in addition to the array of resultSets there is one stray resultSet listed at the root of the JSON output and I can't figure out where it's coming from or how to eliminate it.
Here's the output generated -
{
"id": "id3",
"val": "val3",
"queryResults": [
{
"id": "id1",
"val": "val1"
},
{
"id": "id2",
"val": "val2"
},
{
"id": "id3",
"val": "val3"
}
]
}
And what I am trying to generate is -
{
"queryResults": [
{
"id": "id1",
"val": "val1"
},
{
"id": "id2",
"val": "val2"
},
{
"id": "id3",
"val": "val3"
}
]
}
Any help is appreciated.
What you are calling here is effectively
queryResults(resultSet)plus the side-effects, that change the JSON builder.eachreturns the input (so the originalresultSet) and executes the closure for side-effects. The side-effect here is the change of the current JSON-Node, which is the same place, wherequeryResultsgot added.You can see this, when you replace the
"$col"(row[col])call with something else likebug("fix"). Then the result is:(or add more key-value-pairs to your mock-resultset).
You have to
collect(for a list of maps) andsubMap/collectEntries(for the maps) instead: