Groovy parse Json preserve keys order - json

I try to parse a Json in groovy/Jenkins(I have no access to readJSON step) and keep the json keys order.
After my research, I found that groovy Map/HashMap objects are not preserving the order of the keys.
The only type which keeping order is LinkedHashMap So I try to convert the output of JsonSlurper.parseText to linkedhashmap but it still changing the items order
def jsonstr = """
{
"Id": 533,
"StartTime": "2022-05-10 11:56:18",
"EndTime": "2022-05-10 11:58:49",
"TimeShift": "N/A",
"Run": "123",
"Setup": "Test",
"Version": "3.17",
"Result": "pass",
"DebugMode": 1,
"NumberOfCores": 3,
}
"""
//init as LinkedHashMap
LinkedHashMap map = new LinkedHashMap()
map = (LinkedHashMap) (new JsonSlurperClassic().parseText(jsonstr))
println(map)
/*
the output is in incorrect order, I expect to get `Id` attribute as a first key but I'm getting:
[EndTime:2022-05-10 11:58:49, Version:3.17, TimeShift:N/A, StartTime:2022-05-10 11:56:18, DebugMode:1, Run:123, NumberOfCores:3, Id:533, Setup:Test, Result:pass]
*/

Here is the solution:
I realized that readJSON step is keeping the order so I try to take a look at its implementation.
readJSON uses net.sf.json.* library, in this library there is an option to parse string to jsonObject (with keeping the order of the keys!) by:
import net.sf.json.JSONSerializer
def map = JSONSerializer.toJSON(jsonstr)
println(map)
NOTES:
if you want use it during a pipeline I suggest you to use readJSON step itself, otherwise, you'll need to approve this function from Manage Jenkins -> script approval
In this method empty properties will be net.sf.json.JSONNull
which holds a textual value "null" -> if (someEmptyKey != null) always returns true (also when null) to avoid that, use:
if (!someEmptyKey instanceof JSONNull )
Sources: docs, jenkins-implementation

Related

How to validate entire JSON with 1 dynamic field with JMeter

I have a JSR223 Assertion in JMeter that validates entire JSON response and its working.
The problem is that each time I insert data in DB one of JSON fields changes and validation fails.
How could I skip that dynamic field from response validation?
Response JSON example:
[
{
"id": "273444",
"trxDateTime": "2019-03-25T22:38:16Z",
"merchantName": "MerchECOM1",
"merchantTransId": "1r1vXue4qn",
"trxType": "Payment",
"paymentBrand": "MasterCard",
"amount": 20.00,
"currencyCode": "AUD",
"status": "Declined",
"statusResponseMessage": null,
"customerAccount": "123456"
}
]
JSR223 Assertion:
def expected = new groovy.json.JsonSlurper().parseText(vars.get('expected1'))
def actual = new groovy.json.JsonSlurper().parse(prev.getResponseData())
if (expected != actual) {
AssertionResult.setFailure(true)
AssertionResult.setFailureMessage('Mismatch between expected and actual JSON')
}
just with this I'm not able to validate the dynamic "id" field
any idea?
Thanks in advance
If you're not interested in this id field - just remove it from the expected variable and the actual response, to wit amend first 2 lines of your assertion to look like:
def expected = new groovy.json.JsonSlurper().parseText(vars.get('expected1')).each {entry -> entry.remove('id')}
def actual = new groovy.json.JsonSlurper().parse(prev.getResponseData()).each {entry -> entry.remove('id')}
More information:
Groovy: Parsing and Producing JSON
Apache Groovy - Why and How You Should Use It
Demo:
If value is not your concern for id field you can directly use regex matcher to check the field using Jsonassertion by specifying jsonpath and check match as regex use regex

Using JPATH, how do I select a JSON value inside another JSON string?

I have the following JSON (simplified / minimized to show only pertinent parts) returned from a web service:
{
"results": [{
"paramName": "OutputPolyline",
"dataType": "String",
"value": "#{\"hasM\":true,\"paths\":[[[135.24,246.13,null],[135.24,246.13,null] ... [135.24,246.13,null]]]}"
}],
"messages": []
}
I use the following code to parse the JSON and grab the value of the "value" key:
JObject obj = JObject.Parse(json);
JToken token = obj.SelectToken("$.results[?(#.paramName == 'OutputPolyline')]['value']");
Console.WriteLine(token.Path + " -> " + token);
The above code returns the entire value string as expected, like such "#{\"hasM\":true,\"paths\":[[[135.24,246.13,null],[135.24,246.13,null] ... [135.24,246.13,null]]]}"
Building on the above code, how do I get only the value of the paths key? In this example, return only [[[135.24,246.13,null],[135.24,246.13,null] ... [135.24,246.13,null]]]
You cannot extract the path values from the root object via a single JsonPath query since the value of the value property is just a string literal that happens itself to be re-serialized JSON. It needs to be extracted and recursively parsed as JSON after first trimming off the # character, and Json.NET has no built-in query operator to do that as of the current version, 9.0.1.
Thus you need to do something like:
JToken token = obj.SelectToken("$.results[?(#.paramName == 'OutputPolyline')]['value']");
var paths = JToken.Parse(token.ToString().Trim('#')).SelectToken("paths");
Sample fiddle.

Dynamically build json using groovy

I am trying to dynamically build some json based on data I retrieve from a database. Up until the opening '[' is the "root" I guess you could say. The next parts with name and value are dynamic and will be based on the number of results I get from the db. I query the db and then the idea was to iterate through the result adding to the json. Can I use jsonBuilder for the root section and then loop with jsonSlurper to add each additional section? Most of the examples I have seen deal with a root and then a one time "slurp" and then joining the two so wasn't sure if I should try a different method for looping and appending multiple sections.
Any tips would be greatly appreciated. Thanks.
{
"hostname": "$hostname",
"path": "$path",
"extPath": "$extPath",
"appName": "$appName",
"update": {"parameter": [
{
"name": "$name",
"value": "$value"
},
{
"name": "$name",
"value": "$value"
}
]}
}
EDIT: So what I ended up doing was just using StringBuilder to create the initial block and then append the subsequent sections. Maybe not the most graceful way to do it, but it works!
//Create the json string
StringBuilder json = new StringBuilder("""{
"hostname": "$hostname",
"path": "$path",
"extPath": "$extPath",
"appName": "$appName",
"update": {"parameter": ["""
)
//Append
sql.eachRow("""<query>""",
{ params ->
json.append("""{ "name": "params.name", "value": "params.value" },""");
}
)
//Add closing json tags
json.append("""]}}""")
If I got your explanation correctly and if the data is not very big (it can live in memory), I'd build a Map object (which is very easy to work with in groovy) and convert it to JSON afterwards. Something like this:
def data = [
hostname: hostname,
path: path,
extPath: extPath,
appName: appName,
update: [parameter: []]
]
sql.eachRow(sqlStr) { row ->
data.update.parameter << [name: row.name, value: row.value]
}
println JsonOutput.toJson(data)
If you're using Grails and Groovy you can utilize grails.converters.JSON.
First, define a JSON named config:
JSON.createNamedConfig('person') {
it.registerObjectMarshaller(Person) {
Person person ->
def output = [:]
output['name'] = person.name
output['address'] = person.address
output['age'] = person.age
output
}
}
This will result in a statically defined named configuration for the Object type of person. Now, you can simply call:
JSON.use('person') {
Person.findAll() as JSON
}
This will return every person in the database with their name, address and age all in one JSON request. I don't know if you're using grails as well in this situation though, for pure Groovy go with another answer here.

How to unwrap a list from typesafeconfig list to the list of particular type?

I have a config in json format and I am using Typesafe Config library to load this.
Input config in json format
{
"input": {
"Date": "2014-01-01",
"Ids": ["1","2","3","4"]
}
}
Code
import com.typesafe.config.{Config, ConfigFactory}
val config = ConfigFactory.load("test.json")
val ids = config.getList("input.Ids").unwrapped
# ids: java.util.List[Object] = [1, 2, 3, 4]
All I am getting is list of object. When I try to do a map of each element to int it fails because each element is an object.
ids.map(_.toInt)
<console>:14: error: value toInt is not a member of Object
ids.map(_.toInt)
How to convert the object list to integer list in scala ?
You can use the getStringList method and then map the result to int
config.getStringList("input.Ids").map(_.toInt)
or in this case use the getIntList method directly

JSON to Groovy with JsonSlurper and unknown "string"

I am writing a Grails/Groovy app and I have a JSON object with a "string" name (grommet and widget) inside the params member that can change. That is, next time it might be acme and zoom. Here is the JSON:
def jx = """{
"job": "42",
"params": {
"grommet": {"name": "x", "data": "y"},
"widget": { "name": "a", "data": "b"}
}
}"""
I am trying to figure out how to get the string grommet . Code so far:
def dalist = new JsonSlurper().parseText(jx)
println dalist.job // Gives: 42
println dalist.params // Gives: [grommet:[name:x, data:y], widget:[name:a, data:b]]
println dalist.params[0] // Gives: null
Any idea how to get the string grommet? Iama going to keep hitting my head against a wall.
The params key on the JSON object is associated with a JSON object, not an array, so you cannot access it by index. JsonSlurper maps JSON objects to Groovy Maps, so you can access params by its keys, which are strings, e.g. dalist.params.grommet, which will give you the map [name: 'x', data: 'y'].
To access the keys on the params you can do dalist.params.keySet(), which will give you the list ['grommet', 'widget']. If you are interested in just knowing params keys, that should do the trick. If you need to get the 'grommet' string for some reason, you can do it by accessing the first element on that list, i.e. dalist.params.keySet()[0], but i don't know why you would want to know that. And i'm not sure if it is guaranteed that the first key of that map will always be 'grommet', as JSON objects are unordered by the spec (from json.org: An object is an unordered set of name/value pairs), but, in turn, Groovy maps are ordered (the default implementation is LinkedHashMap)... so i would assume that the order is preserved when parsing JSON to the Groovy world, but i'd try not to rely on that particular behavior hehe.
It's Map instance, try:
def params = dalist.params.entrySet() as List // entrySet() returns Set, but it's easier to use it as a List
println params
println params.size()
println params[0]
println params[0].key
println params[0].value
This might help you.
import groovy.json.JsonSlurper;
def jx='{"job":"42","params":{"grommet":{"name":"x","data":"y"},"widget":{"name":"a","data":"b"}}}'
def dalist = new JsonSlurper().parseText( jx )
assert dalist.params.getClass().name == "java.util.HashMap";
assert dalist.params.size() == 2;
def keys = dalist.params.collect{ a, b -> a}; // returns "[grommet, widget]"
assert !!dalist.params.get( "grommet" ) == true