Groovy JsonSlurper Issue involving commas in JSON - json

I have some JSON coming into my controller, call it params.formData, it looks like this:
'{"year":"2014","resource":["Smith, John","Foo, Bar"]}'
My code to parse it:
....
def slurper = new JsonSlurper()
def data = slurper.parseText(params.formData)
...
data looks like:
[resource:["Smith", "John", "Foo", "Bar"], year:"2014"]
Notice that there were two JSON entries, and the parser made it into an array of four entries. I want it to look like this:
[resource:["Smith, John", "Foo, Bar"], year:"2014"]
Does anyone know how to handle this situation?

I don't think it does.
assert data.resource.size() == 2
Should prove me right ;-)
My guess is the output of printing data:
[resource:[Smith, John, Foo, Bar], year:2014]
Confused things. It looks like 4, but it's 2

I can't reproduce this behaviour. Run this code in the Groovy console
import groovy.json.JsonSlurper
def json = '{"resource":["Smith, John","Foo, Bar"]}'
def slurper = new JsonSlurper()
def data = slurper.parseText(json)
assert data.resource.size() == 2
The assertion passes, indicating that there are 2 entries. Why do you think there are four?

Definitely a Map rendering "optical illusion"
data.resource.each {
println it
}
Smith, John
Foo, Bar

Related

Django View: Return Queryset in JSON Format

i am trying to make the following view with return JsonResponse() at the end work correctly:
def get_data(request):
full_data = Fund.objects.all()
data = {
"test2": full_data.values('investment_strategy').annotate(sum=Sum('commitment')),
}
return JsonResponse(data)
However, I get an error message saying "Object of type QuerySet is not JSON serializable".
When I put the above Queryset in a view with return render() at the end:
def get_more_data(request):
full_data = Fund.objects.all()
data = {"test2": full_data.values('investment_strategy').annotate(sum=Sum('commitment'))}
return render (request, 'test.html', data)
I get the the following result: <QuerySet [{'investment_strategy': 'Buyout', 'sum': 29}, {'investment_strategy': 'Growth', 'sum': 13}, {'investment_strategy': 'Miscellaneous', 'sum': 14}, {'investment_strategy': 'Venture Capital', 'sum': 23}, {'investment_strategy': 'n/a', 'sum': 36}]>
So the queryset works fine, I just have no clue how to return the data in proper Json format (which I would need to use the data charts.js)
I looked through answers for similar questions such as:
TypeError: object is not JSON serializable in DJango 1.8 Python 3.4
Output Django queryset as JSON
etc.
but could not find a meaningful solution for my problem.
Any help would be much appreciated!
So I managed to find a solution, that worked for me - in case anyone else has the same problem. I changed my view to the following:
def get_data(request):
full_data = Fund.objects.all()
full_data_filtered = full_data.values('investment_strategy').annotate(sum=Sum('commitment'))
labels = []
values = []
for d in full_data_filtered:
labels.append(d['investment_strategy'])
values.append(d['sum'])
data = {
"labels": labels,
"values": values,
}
return JsonResponse(data)
So basically I iterate over the Queryset and assign the values I need to lists, which can be passed to JsonResponse. I don't know if this is the most elegant way to do this (sure not), but it works and I can render my data in charts.js
JsonResponse(list(data)) will evaluate the Queryset (actually perform the query to the database) and turn it into a list that can be passed to JsonResponse.
This works because you use values and annotate, so the list is a list of dictionaries containing serializable fields.
In the example you mentioned, it didn't work because the Queryset was just returning a list of model instances, so wrapping in list() isn't enough. If you hadn't added values, you'd have had a list of Fund instances which are not serializable.
The best way I found was to create a custom QuerySet and Manager, it's not a lot of code and it is reusable!
I began by creating the custom QuerySet:
# managers.py but you can do that in the models.py too
from django.db import models
class DictQuerySet(models.QuerySet):
def dict(self):
values = self.values()
result = {}
for value in values:
id = value['id']
result[id] = value # you can customize the content of your dictionary here
return result
Then I created a custom Manager, it is optional but i prefer this way.
# managers.py, also optional
class DictManager(models.Manager):
def get_queryset(self):
return DictQuerySet(self.model, using=self._db)
Change the default manager in your model:
# models.py
from .managers import DictManager
class Fund(models.Model):
# ...
objects = DictManager()
# ...
And now you can call the dict() method from the query
# views.py
def get_data(request):
full_data = Fund.objects.all().dict()
return JsonResponse(full_data)
The response will be the full_data as a dictionary of dictionaries and each key is the primary key of the corresponding object.
If you intend to keep the same format for your JSONs, then you can use the same custom manager for all your models.

Count child nodes of a JSON response using groovy in soapui

I have a JSON response due to security reasons I had to take a screenshot and post it here.
I need to find number of available itineraryPrice available. Each curly braces refers to a separate itinerary, how to I count those tags in a groovy script step.
Method I have tried
def holder = groovyUtils.getXmlHolder( "air-search#ResponseAsXml" )
def xpath = "//*:search/*:itineraryPrice"
def numberOfRecommendations = holder["count(//*:search/*:itineraryPrice)"]
log.info "Total no of recommendations : "+numberOfRecommendations
But I got the output as 1 :(
Kindly help ! Please refer screenshot as well.
def json = '''{
"pos":"...",
"search":{
"uri":"...",
"itineraryPrice":[
{"a":1},
{"a":22},
{"a":333},
{"a":4},
{"a":56}
]
}
}'''
json = new groovy.json.JsonSlurper().parseText(json)
def count = json.search.itineraryPrice.size()
output: 5

Groovy json string empty

I am working with SoapUI and are really new to this. I am supposed to make a few REST tests, a lot of them have to do with dynamic resources so I have to read some json results on runtime. This works fine the first time I do it:
...
def response = context.expand('${Get ContractModels#Response}')
def slurper = new JsonSlurper().parseText(response)
for (i in slurper.ContractModels){
testRunner.testCase.testSteps["ContractModelOptionStep"].setPropertyValue("id",sprintf('%d',i.ContractModelID));
testRunner.runTestStepByName("ContractModelOptionStep")
def innerResponse = context.expand('${Get ContractModelOptionStep#Response}')
log.info(response)
log.info(innerResponse)
def innerSlurper = new JsonSlurper().parseText(innerResponse);
...
}
This works well up to the last line, where it tells me The JSON input text should neither be null nor empty. Thanks to the log.info I found out the JSON Strong of innerResponse is actually empty. Now my problem is I have no clue why, runTestStepByName works perfectly fine and gives the expected response.
Cheers
In these two lines:
testRunner.runTestStepByName("ContractModelOptionStep")
def innerResponse = context.expand('${Get ContractModelOptionStep#Response}')
the name of the test step does not match! Try:
def innerResponse = context.expand('${ContractModelOptionStep#Response}')

How can I create a two-element object with Groovy's JsonBuilder?

In my Groovy code, I've got two variables declared:
results is an array of maps. It contains a list of rows returned from a SQL query.
overall is a map. It represents a single row of a separate SQL query.
I want to combine these two variables into one and output the whole thing as JSON. In the end, I want it to look something like this:
{"data":[{"results":"array"}],"overall":{"overall":"map"}}
Here's the code I'm trying to use, but it doesn't work:
def json = new groovy.json.JsonBuilder()
def finalJSON = json {
data results
overall overall
}
return json.toString()
But this doesn't work... it throws the following exception:
groovy.lang.MissingPropertyException: No such property: call for class: groovy.sql.GroovyRowResult
I can verify that both variables results and overall have the correct data in them. I guess I'm just not understanding the syntax for JsonBuilder.
Find possible solutions below:
import groovy.json.*
def r = [[l:1],[l:2]]
def o = [over:1,all:2]
def json = new JsonBuilder()
json {
data r
overall o
}
println json.toPrettyString()
def m = [data: r, overall: o]
println JsonOutput.prettyPrint(JsonOutput.toJson(m))
Okay, I figured it out. Groovy's kind of stupid in that you apparently cannot use the same variable name for the value as the key you're assigning. So the real trouble was with the line that read:
overall overall
I changed that variable to overallData and everything started working.

Possible to pretty print JSON in Grails 1.3.7?

The JSON in question is being read in from a RESTful service, and I would like to print it out (to console, although in .gsp would be fine also) for debugging purposes. Groovy 1.3.7 (current as of August 2011) uses Groovy 1.7.8 (which does not have the JsonOutput introduced in 1.8)
Note I am currently reading it in like this, which I am not convinced is the 'grooviest or grail-est' way to do it - perhaps I could take advantage of the converters and pretty printing if done differently? Code sample would be appreciated.
def serviceURL = new URL(theURL)
def json = new JSONObject(serviceURL.text)
println json
You can pretty print JSON with the toString(int indentFactor) method. Example:
def json = new JSONObject()
json.put('foo', 'bar')
json.put('blat', 'greep')
println json
===>{"foo":"bar","blat","greep"}
println json.toString(4)
===>{
"foo": "bar",
"blat": "greep"
}
You can use grails.converters.JSON (which is the most commonly used library for JSON):
In your config.groovy file, add the line to set prettyPrint to true:
grails.converters.default.pretty.print=true
Then, in your controller:
import grails.converters.*
def serviceURL = new URL(theURL)
def json = JSON.parse(serviceURL.text)
println "JSON RESPONSE: ${json.toString()"
If you're in a Grails controller and plan to render the json, then you use something like this (using Grails 2.3.5):
public prettyJson() {
JSON json = ['status': 'OK'] as JSON
json.prettyPrint = true
json.render response
}
I found that solution here: http://www.intelligrape.com/blog/2012/07/16/rendering-json-with-formatting/
Apart from set default pretty print in Config.groovy, JSON's toString() method accepts one boolean parameter. It controls whether pretty print the result or not.
import grails.converters.*
import my.data.*
def accountJson = Account.get(1001) as JSON
println(accountJson.toString(true))
println(accountJson.toString(false))
Tested in Grails 1.3.9.