Example (thought of) taken from groovy ws-lite git hub project.
Say I have the following code block to send a RESTful post request:
void 'Holiday Service get holidays by country, year and month'() {
given:
def client = new RESTClient('http://www.holidaywebservice.com/HolidayService_v2/HolidayService2.asmx')
when:
def response = client.post(path: '/GetHolidaysForMonth') {
type ContentType.JSON
json files: ['spec_test.txt':[content: "2014-12-12"]]
}
then:
200 == response.statusCode
'text/xml' == response.contentType
'Christmas' == response.xml
.Holiday
.find { it.HolidayCode.text() == 'CHRISTMAS-ACTUAL'}
.Descriptor.text()
}
Here is what's generated in the request body:
{"files":{"spec_test.txt":{"content":"2014-12-12"}}}
How can I change the code to generate this json array instead:
[{"files":{"spec_test.txt":{"content":"2014-12-12"}}}]
Note the following code can do the trick:
def sampleRequest = '[{"files":{"spec_test.txt":{"content":"2014-12-12"}}}]'
def jsonArray = new JsonSlurper().parseText( sampleRequest )
void 'Holiday Service get holidays by country, year and month'() {
given:
def client = new RESTClient('http://www.holidaywebservice.com/HolidayService_v2/HolidayService2.asmx')
when:
def response = client.post(path: '/GetHolidaysForMonth') {
type ContentType.JSON
json jsonArray
}
then:
200 == response.statusCode
'text/xml' == response.contentType
'Christmas' == response.xml
.Holiday
.find { it.HolidayCode.text() == 'CHRISTMAS-ACTUAL'}
.Descriptor.text()
}
But I want to know if there is another way to do this?
As far as I understood well You just need to replace the following line:
files: ['spec_test.txt':[content: "2014-12-12"]]
with this one:
[[files: ['spec_test.txt':[content: "2014-12-12"]]]]
It just passed a list instead of map to json key, but double square brackets are needed because one pair will be used to indicate a map and the second one to create a list.
Related
I have a json and its response is {"canMerge":false,"conflicted":true,"outcome":"CONFLICTED","vetoes":[{"summaryMessage":"Requires approvals","detailedMessage":"You need 2 more approvals before this pull request can be merged."}]}
and I want to filter out data on the basis of "outcome":"CONFLICTED" for this I have tried following ways-
def mergeResponse = readJSON file:mergeFileName
for(mergenew in mergeResponse.values)
{
if(mergenew.outcome == "CONFLICTED") {
echo "pull request can not merged"
}
when I am trying above it is skipping if loop directly eventhough condition match properly I am not getting why?
ALSO TRIED BELOW
import groovy.json.JsonSlurper
def slurper = new JsonSlurper().parseText(mergenew)
assert slurper.outcome == "CONFLICTED"
String id = mergenew.getString("id");
echo "pull request can not merged"
getting error for above is
hudson.remoting.ProxyException: groovy.lang.MissingMethodException: No signature of method: groovy.json.JsonSlurper.parseFile() is applicable for argument types: (org.apache.commons.collections.map.ListOrderedMap$ListOrderedMapEntry) values: [canMerge=false]
Possible solutions: parse([B), parse([C), parse(java.io.File), parse(java.io.InputStream), parse(java.io.Reader), parse(java.net.URL)
I also approved script in jenkins script approval for JsonSlurper.parseText
Please help me. Any help is appreciated.
try this : (set the file name var to whatever the file is)
import groovy.json.JsonSlurper
def jsonSlurper = new JsonSlurper()
data = jsonSlurper.parse(new File(mergeFileName))
assert data.outcome == "CONFLICTED"
println("pull request can not merged")
You can use Pipeline Utility Steps to read a json file. This works for me:
def data = readJSON file: "${WORKSPACE}/data.json" // here just read the json file
def outcome = "${data.outcome}"
if(outcome == "CONFLICTED") {
echo "pull request can not merged"
}
I created a method as shown online:
#NonCPS
def parseJsonString(String jsonString) {
def lazyMap = new JsonSlurper().parseText(jsonString)
// JsonSlurper returns a non-serializable LazyMap, so copy it into a regular map before returning
def m = [:]
m.putAll(lazyMap)
return m
}
But I get the following error:
ERROR: java.io.NotSerializableException: groovy.json.internal.LazyMap
To work around this, I have to create an entire method to perform an entire step. For instance, in a method, I would do the same as above, parse the information I want, and finally return it as a string.
This, however, presents another issue, especially if you wrap this method inside a withCredentials, which would then require another withCredentials.
I finally find a BETTER solution!
readJSON() method from the Jenkins "Pipeline Utility Steps" plugin as shown here:
https://jenkins.io/doc/pipeline/steps/pipeline-utility-steps/#readjson-read-json-from-files-in-the-workspace
Here is a sample where we can finally ditch that ugly GROOVY JSONPARSE crap.
node() {
stage("checkout") {
def jsonString = '{"name":"katone","age":5}'
def jsonObj = readJSON text: jsonString
assert jsonObj['name'] == 'katone' // this is a comparison. It returns true
sh "echo ${jsonObj.name}" // prints out katone
sh "echo ${jsonObj.age}" // prints out 5
}
}
I'm busy working on a function that sends a map (and other irrelevant values) through a json web service but the problem is that on the receiving side it sees it as JSONObject (using the getClass() method) and coz of this it adds extra properties to the object thus causing the service to return an error. So on the sending side the map println's like this:
[21:{adultValue=1, kidValue=0}, 11:{adultValue=0, kidValue=4}]
But on the receiving side it println's like this:
[11:[metaPropertyValues:[[name:adultValue, modifiers:1, type:java.lang.Object], [name:kidValue, modifiers:1, type:java.lang.Object]], properties:[kidValue:4, adultValue:0]], 21:[metaPropertyValues:[[name:adultValue, modifiers:1, type:java.lang.Object], [name:kidValue, modifiers:1, type:java.lang.Object]], properties:[kidValue:0, adultValue:1]]]
So on the receiving side there is code that does the following (simplified for this question):
map.each { key, value ->
def adultValue = value.adultValue.toInteger()
}
But it obviously throws a NullPointer exception coz according to the receiving side there's no map.adultValue, there's only a map.properties.adultValue
So my question is, what can I do on the sending side so that the receiving side receives it the same way that it was sent? I'm not allowed to change the receiving side's code but I can look at the output.
For extra clarification, here's the code I use on the sending side to make the web service call:
def addAddons(map, anotherVar1, anotherVar2) {
println(map) // outputs the map as shown above
try {
def result
def http = new HTTPBuilder("the real url, not shown here")
http.request(Method.POST, groovyx.net.http.ContentType.JSON) { req ->
body = [anotherVar1: anotherVar1, anotherVar2: anotherVar2, map: map]
response.success = { resp, json ->
result = json
}
}
println("result: ${result}")
return result
} catch (all) {
all.printStackTrace()
return null
}
}
Please let me know if there's anything else I need to add
You may also consider to use a JSON converter, so you still can create a Map and create the string out of the map.
import groovy.json.JsonOutput
def json = JsonOutput.toJson(map)
Turns out I was looking at it all wrong. I didn't realise but I was supposed to send a Json object instead of anything else which is why a map didn't work, and neither would an Arraylist (I tried that too, not shown in my question). So I tried to convert it to json using groovy.json.JsonBuilder but I couldn't figure that out so I ended up manually converting my map to json with the following code:
def json = '{'
def counter = 0
map.each { key, value ->
if(counter == map.size()-1) {
json += "\"$key\":{\"adultValue\":${value.adultValue},\"kidValue\":${value.kidValue}}"
} else {
json += "\"$key\":{\"adultValue\":${value.adultValue},\"kidValue\":${value.kidValue}},"
}
counter++
}
json += '}'
And that solved my problem
In the response Json, getting an array list of items as shown.
What you see in the question is not xml, it is a json string. So, xpath does not work.
For your request test step, you can add the Script Assertion as shown below:
//Check the response
assert context.response, 'Response is empty or null'
//Expected subscription id, change it if needed
def expectedSubscriptionId = '2c92c0f95ae1445b015af2320235689f'
def parsedJson = new groovy.json.JsonSlurper().parseText(json)
def ids = [] as Set
parsedJson.each { item ->
item.amendments.each { amendment ->
if (amendment.subscriptionId == expectedSubscriptionId ) {
ids << item.id
}
}
}
assert ids.size(), "id's are not found in the response for matching subscription"
log.info "Matching id's are : ${ids}"
You may quickly try online Demo
I'm new to grails, the problem i'm trying to solve is pretty simple : my server should receive some json data in a request validate the data and save it to a DB.
To my best understanding I use Command Object to validate the data. the problem is that if my Command object contains a list of another class ( a secondary command object ) the parser would put in that field a jsonArray and this would ignore my secondary validation.
Parsing json ->
void handleRequest(){
def jsonObject = request.JSON
doSomething(new PrimaryCommandObject(jsonObject))
}
def doSomething(PrimaryCommandObject cmd){
if (cmd.validate()) {
respond cmd
}else{
cmd.errors.allErrors.each {
println it
}
}
}
Main Command object ->
class PrimaryCommandObject{
int val1
List<SecondaryCommandObject> collection
}
Right now in order to bypass this issue I added a setter
Setter ->
void setCollection(JSONArray jsonArray){
this.collection = []
jsonArray.each { item ->
SecondaryCommandObject obj = item as SecondaryCommandObject
if (obj.validate()) {
this.collection << obj
}else {
obj.errors.allErrors.each {
println it
}
}
}
This doesn't feel right for me, I would except a cleaner simpler way to get it done. this
can someone please help ? thanks