Build JSON as an array element - json

I have this JSON Builder Groovy code:
import groovy.json.JsonBuilder
import groovy.json.JsonOutput
import groovy.json.StreamingJsonBuilder
class JSONTest {
public static main(args) {
StringWriter writer = new StringWriter()
StreamingJsonBuilder builder = new StreamingJsonBuilder(writer)
builder.requests {
name 'HSV Maloo'
make 'Holden'
year 2006
country 'Australia'
}
String json = JsonOutput.prettyPrint(writer.toString())
println json
}
}
It produces output like this:
{
"requests": {
"name": "HSV Maloo",
"make": "Holden",
"year": 2006,
"country": "Australia"
}
}
But I want to make the output like this with the requests value as an array element:
{
"requests": [{
"name": "HSV Maloo",
"make": "Holden",
"year": 2006,
"country": "Australia"
}]
}
How I can change the output?

You can do this by using the form of the StreamingJsonBuilder DSL that allows you to pass an element name, a collection, and a closure to iterate over the collection with.
def requests = [
[name: 'HSV Maloo', make: 'Holden', year: 2006, country: 'Australia']
]
StringWriter writer = new StringWriter()
StreamingJsonBuilder builder = new StreamingJsonBuilder(writer)
builder.requests requests, { request ->
name request.name
make request.make
year request.year
country request.country
}
String json = JsonOutput.prettyPrint(writer.toString())
println json
Which will produce:
{
"requests": [
{
"name": "HSV Maloo",
"make": "Holden",
"year": 2006,
"country": "Australia"
}
]
}

Related

Groovy Modifying Json

I'm trying to modify a json which I'm reading from a file:
String response = new File("response.json").text
here is what response looks like:
{
"TerminatingInstances": [
{
"InstanceId": "id",
"CurrentState": {
"Code": 32,
"Name": "shutting-down"
},
"PreviousState": {
"Code": 16,
"Name": "running"
}
}
]
}
To modify it I did as follows:
def slurped = new JsonSlurper().parseText(response)
def builder = new JsonBuilder(slurped)
builder.content.TerminatingInstances.InstanceId = "id-updated"
but I get argument type mismatch error, not sure why.
That's because it's an array of instances inside TerminatingInstances
You can either set all of them to the new id with *.:
builder.content.TerminatingInstances*.InstanceId = "id-updated"
Or set just the first one with
builder.content.TerminatingInstances[0].InstanceId = "id-updated"

Groovy script to compare 2 JSON array objects

I am trying to find the best way to compare 2 JSON Array objects using Groovy script.
JSON Obj1 =
{
"PO":
[
{
"OrderNumber": "12345",
"Location": "US",
}
{
"OrderNumber": "11223",
"Location": "US",
}
]
}
JSON Obj2 = {
"ResultPO":
[
{
"OrderNumber": "12345_00001",
"Location": "US",
"Customer": "ABC"
}
{
"OrderNumber": "98765_00002",
"Location": "US",
"Customer": "XYZ"
}
]
}
I need to return the JSON Output as below after finding the obj1 value in obj2 where OrderNumber is key identifier.
{
"ResultPO":
[
{
"OrderNumber": "12345_00001",
"Location": "US",
"Customer": "ABC"
}
]
}
Below is the sample code I have tried using JsonSlurper and findall but not able to get desired outcome.
def builder
def filterJson
filterJson = Obj2.findAll(){ it.OrderNumber.substring(0,4) == Obj1.OrderNumber.text()}
builder = new JsonBuilder(filterJson)
Try this one:
class OrderFilterSpec extends Specification {
def str1 = """{"PO":[
{"OrderNumber": "12345","Location": "US"},
{"OrderNumber": "11223","Location": "US"}
]}"""
def str2 = """{"ResultPO":[
{"OrderNumber": "12345_00001","Location": "US","Customer": "ABC"},
{"OrderNumber": "98765_00002","Location": "US","Customer": "XYZ"}
]}"""
def slurper = new JsonSlurper()
def buildResult(String first, String second) {
def (parsed1, parsed2) = [slurper.parseText(first), slurper.parseText(second)]
def filteredOrders = parsed2.ResultPO.findAll {
it.OrderNumber[0..4] in parsed1.PO.collect { it.OrderNumber }
}
return [ResultPO: filteredOrders]
}
def 'test order filtering'() {
expect:
buildResult(str1, str2) == [ResultPO: [[OrderNumber: '12345_00001', Location: 'US', Customer: 'ABC']]]
}
}

Unexpected character (g) at position 0 when trying to parse json - HttpResponseDecorator

Whenever I try to execute below script I keep getting error, saying unexpected character (g).
Basically I want to be able to parse the json response and be able to get the upstream job name from it.
Script:
#Grapes([
#Grab(group='org.codehaus.groovy.modules.http-builder', module='http-builder', version='0.7.1'),
#Grab(group='commons-collections', module='commons-collections', version='3.2.1'),
#Grab(group='org.jsoup', module='jsoup', version='1.10.2'),
#Grab(group='org.json', module='json', version='20190722'),
#Grab(group='com.googlecode.json-simple', module='json-simple', version='1.1.1')
])
import static groovyx.net.http.ContentType.*
import groovyx.net.http.HttpResponseException
import groovyx.net.http.RESTClient
import groovy.json.JsonSlurper
import groovy.json.JsonOutput
import java.net.*
import java.util.*
import org.json.simple.*
import org.json.simple.parser.JSONParser;
def getRestClient(){
String jenkinsUrl="http://somedomainname:8080"
def restClient = new RESTClient(jenkinsUrl)
return restClient
}
def getJobsInfo(String jobname,RESTClient restClient){
def requrl= '/job/'+jobname+'/lastBuild/api/json/?pretty=true'
def response = restClient.get( path : requrl)
return response
}
def writeToPropertyFile(){
def jsonResponseObject = getJobsInfo("sampleJobName",getRestClient())
println "\n\n\n\n\n Json String :---- "+ jsonResponseObject.toString()
JSONParser jsonParser = new JSONParser();
JSONObject jsonObject = (JSONObject) jsonParser.parse(jsonResponseObject.toString());
JSONArray upstreamJobInfoArray = jsonObject.getJSONArray("causes");
for (int i = 0; i < upstreamJobInfoArray.length(); i++) {
JSONObject jobCauses = upstreamJobInfoArray.getJSONObject(i);
String upstreamProjectName = jobCauses.getString("upstreamProject");
println upstreamProjectName
}
}
writeToPropertyFile()
Error :
Json String :---- groovyx.net.http.HttpResponseDecorator#6b063470
Caught: Unexpected character (g) at position 0.
Unexpected character (g) at position 0.
at org.json.simple.parser.Yylex.yylex(Yylex.java:610)
at org.json.simple.parser.JSONParser.nextToken(JSONParser.java:269)
at org.json.simple.parser.JSONParser.parse(JSONParser.java:118)
at org.json.simple.parser.JSONParser.parse(JSONParser.java:81)
at org.json.simple.parser.JSONParser.parse(JSONParser.java:75)
at org.json.simple.parser.JSONParser$parse.call(Unknown Source)
at getUpstreamJob.writeToPropertyFile(getUpstreamJob.groovy:39)
at getUpstreamJob.run(getUpstreamJob.groovy:50)
EDIT 1 : START
JSON response that I am trying to parse :
{
"_class": "hudson.model.FreeStyleBuild",
"actions": [
{
"_class": "hudson.model.CauseAction",
"causes": [
{
"_class": "hudson.model.Cause$UpstreamCause",
"shortDescription": "Started by upstream project \"sampleJobName\" build number 712",
"upstreamBuild": 712,
"upstreamProject": "sampleJobName",
"upstreamUrl": "job/sampleJobName/"
},
{
"_class": "hudson.model.Cause$UserIdCause",
"shortDescription": "Started by user Malick, Asif",
"userId": "asifma00",
"userName": "Malick, Asif"
},
{
"_class": "com.sonyericsson.rebuild.RebuildCause",
"shortDescription": "Rebuilds build #300",
"upstreamBuild": 300,
"upstreamProject": "sampleJobName",
"upstreamUrl": "view/ABCProjectView/job/sampleJobName/"
}
]
},
{
"_class": "hudson.model.ParametersAction",
"parameters": [
{
"_class": "hudson.model.StringParameterValue",
"name": "SNAPSHOTNAME",
"value": "ABCDE_12121.2000-2121212121212"
},
{
"_class": "hudson.model.StringParameterValue",
"name": "BUILD_LABEL",
"value": "ABCDE_12121.2000"
}
]
},
{},
{},
{},
{},
{
"_class": "hudson.plugins.parameterizedtrigger.BuildInfoExporterAction"
},
{},
{},
{},
{}
],
"artifacts": [],
"building": false,
"description": null,
"displayName": "#301",
"duration": 1199238,
"estimatedDuration": 1194905,
"executor": null,
"fullDisplayName": "sampleJobName #301",
"id": "301",
"keepLog": false,
"number": 301,
"queueId": 189076,
"result": "SUCCESS",
"timestamp": 1583500786857,
"url": "http://somedomainname:8080/job/sampleJobName/301/",
"builtOn": "Server12345",
"changeSet": {
"_class": "hudson.scm.EmptyChangeLogSet",
"items": [],
"kind": null
},
"culprits": []
}
EDIT 1 : END
I have tried looking at several Stack Overflow issues, but still haven't been able to resolve it.
Please guide.
It's because you're not getting the actual JSON string, you're getting the toString() output on a groovyx.net.http.HttpResponseDecorator class.
You can see it printing it out here (it's easy to miss though... I missed it the first look 🙂):
Json String :---- groovyx.net.http.HttpResponseDecorator#6b063470
I think you need to call jsonResponseObject.data to get the parsed data, and it might even return you a Map parsed form the JSON (so you can get rid of all your JSONObject code). Test it by changing to:
def data = jsonResponseObject.data
println "\n\n\n\n\n Json ${data.getClass().name} :---- $data" jsonResponseObject.toString()
If it is a java.util.Map, you can simplify your second part from:
JSONParser jsonParser = new JSONParser();
JSONObject jsonObject = (JSONObject) jsonParser.parse(jsonResponseObject.toString());
JSONArray upstreamJobInfoArray = jsonObject.getJSONArray("causes");
for (int i = 0; i < upstreamJobInfoArray.length(); i++) {
JSONObject jobCauses = upstreamJobInfoArray.getJSONObject(i);
String upstreamProjectName = jobCauses.getString("upstreamProject");
println upstreamProjectName
}
To (using data from above):
data.actions.causes.upstreamProject.flatten().each { println it }

How to parse just part of JSON with Klaxon?

I'm trying to parse some JSON to kotlin objects. The JSON looks like:
{
data: [
{ "name": "aaa", "age": 11 },
{ "name": "bbb", "age": 22 },
],
otherdata : "don't need"
}
I just need to data part of the entire JSON, and parse each item to a User object:
data class User(name:String, age:Int)
But I can't find an easy way to do it.
Here's one way you can achieve this
import com.beust.klaxon.Klaxon
import java.io.StringReader
val json = """
{
"data": [
{ "name": "aaa", "age": 11 },
{ "name": "bbb", "age": 22 },
],
"otherdata" : "not needed"
}
""".trimIndent()
data class User(val name: String, val age: Int)
fun main(args: Array<String>) {
val klaxon = Klaxon()
val parsed = klaxon.parseJsonObject(StringReader(json))
val dataArray = parsed.array<Any>("data")
val users = dataArray?.let { klaxon.parseFromJsonArray<User>(it) }
println(users)
}
This will work as long as you can fit the whole json string in memory. Otherwise you may want to look into the streaming API: https://github.com/cbeust/klaxon#streaming-api

Merge JSON files

Does anybody know the best way to merge 2 JSON files? I am looking to move the 'awardClaimForms' from file 1 to file 2 while keeping the same 'number'. Would consider manual work if it was a few but I'm dealing with just over 1k entries. Any direction or help would be appreciated!
File 1 contains:
{
"Notices": [
{
"awardClaimForms": "form-21",
"number": "2015-031"
},
{
"awardClaimForms": "form22",
"number": "2015-030"
},
]
}
File 2 contains:
{
"Notices": [
{
"number": "2015-031",
"link": "http://www.yahoo.com",
"title": "myother sample title",
"awardClaimDueDate": "March 01, 2013",
"datePosted": "12/01/2012"
},
{
"number": "2015-030",
"link": "http://www.google.com",
"title": "my sample title",
"awardClaimDueDate": "March 01, 2013",
"datePosted": "12/01/2012"
},
]
}
Desired Outcome:
{
"Notices": [
{
"number": "2015-031",
"link": "http://www.yahoo.com",
"title": "myother sample title",
"awardClaimDueDate": "March 01, 2013",
"awardClaimForms": "form-21",
"datePosted": "12/01/2012"
},
{
"number": "2015-030",
"link": "http://www.google.com",
"title": "my sample title",
"awardClaimDueDate": "March 01, 2013",
"awardClaimForms": "form-22",
"datePosted": "12/01/2012"
},
]
}
import org.apache.commons.io.IOUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class JsonMerge {
public static void main(String[] args) throws IOException, JSONException {
// Read the json from the files
FileInputStream fileOne = new FileInputStream(new File("D:\\jsonOne.json"));
FileInputStream fileTwo = new FileInputStream(new File("D:\\jsonTwo.json"));
String stringOne = null, stringTwo = null;
try {
stringOne = IOUtils.toString(fileOne);
stringTwo = IOUtils.toString(fileTwo);
} finally {
fileOne.close();
fileTwo.close();
}
// Convert them into json objects
JSONObject jsonOne = new JSONObject(stringOne);
JSONObject jsonTwo = new JSONObject(stringTwo);
// Extract the arrays from the Notices Array
JSONArray jsonOneNoticesArray = jsonOne.getJSONArray("Notices");
JSONArray jsonTwoNoticesArray = jsonTwo.getJSONArray("Notices");
JSONObject mergedJsonArray = new JSONObject();
// Iterate and compare the required condition
for (int i = 0; i < jsonOneNoticesArray.length(); i++) {
for (int j = 0; j < jsonTwoNoticesArray.length(); j++) {
JSONObject mergedJson = new JSONObject();
if (jsonOneNoticesArray.getJSONObject(i).getString("number").equals(jsonTwoNoticesArray.getJSONObject(j).getString("number"))) {
mergedJson.accumulate("number", jsonOneNoticesArray.getJSONObject(i).getString("number"));
mergedJson.accumulate("link", jsonOneNoticesArray.getJSONObject(i).getString("link"));
mergedJson.accumulate("title", jsonOneNoticesArray.getJSONObject(i).getString("title"));
mergedJson.accumulate("awardClaimDueDate", jsonOneNoticesArray.getJSONObject(i).getString("awardClaimDueDate"));
mergedJson.accumulate("datePosted", jsonOneNoticesArray.getJSONObject(i).getString("datePosted"));
mergedJson.accumulate("awardClaimForms", jsonTwoNoticesArray.getJSONObject(j).getString("awardClaimForms"));
mergedJsonArray.append("Notices", mergedJson);
break;
}
}
}
System.out.println("Done merging.. " + mergedJsonArray);
}
}
Adding the below line (instead of System.out.println line) could write the output to the file
FileUtils.write(new File("D:\\mergedJson.json"), mergedJsonArray.toString());
and here is the output of the mergedJsonArray from the above code.