How can I stop JsonSlurper from converting objects/maps to arrays? - groovy

I have a JSON response item from a web service that looks like this:
[
{
"field1":"value",
"field2":"value2",
"field3":"value3",
"field4":"value4"
},
{
"field1":"value",
"field2":"value2",
"field3":"value3",
"field4":"value4"
},
...
]
Before conversion my response string looks normal (like this):
[{"field1":"value","field2":"value2","field3":"value3", "field4":"value4"},{...},...]
However after I run def allData = new JsonSlurper().parseText(response)
and then log allData it appears that it's converting my objects to arrays:
Example:
[["field1":"value","field2":"value2","field3":"value3", "field4":"value4"],[...],...]
Does anyone know why this is happening?
Edit:
Imports:
import groovy.json.JsonSlurper

To clarify the (admittedly long) comments above for anyone who has this problem in the future:
That is an array of maps. The confusion came from a difference in String representation between JSON and Groovy, but the underlying data structure was already correct.

Related

Groovy script assertion that validates the presence of some values in a JSON response

So I'm using an testing tool called ReadyAPI and for scripting it uses the Groovy language. I'm not familiar with the language and the fact that it's based on Java it somehow makes it even worse.
Now I'm trying to validate a REST response in JSON with an assertion that checks that certain elements exist in the response.
This is the code that I have now:
import groovy.json.*
def response = context.expand( 'RequestResponseHere' )
def object = new JsonSlurper().parseText(response)
assert response.contains("CODE1")
assert response.contains("CODE2")
assert response.contains("CODE3")
assert response.contains("CODE4")
The assertion seems to work but I was wondering if there is maybe a simpler way to do it than to have to write so many lines and making it less 'bulky'?
Any help is greatly appreciated.
Thank you!
Added an example of the json data that I have to parse:
What I need is to check that the value of "code" is always part of a list of acceptable values e.i. CODE1, CODE2, etc.
{
"_embedded": {
"taskList": [
{
"code": "CODE1",
"key": 123
},
{
"code": "CODE2",
"key": "234"
},
{
"code": "CODE3",
"key": "2323"
},
{
"code": "CODE4",
"key": "7829"
},
{
"code": "CODE5",
"key": "8992"
}
]
}
}
If you want to check for certain things to be there, you can DRY that
code with:
["code1","code2"].each{ assert response.contains(it) }
And as stated in the comments, if you want to make sure, "all are there,
but I don't care for the order", extracting the values and comparing it
as results can shorten this:
assert response._embeded.taskList*.code.toSet() == ["code1", ...].toSet()
Note the use of *., which is the "spread operator". It is basically
the same as ...collect{ it.code }. Then comparing the string sets
does the rest (this is fine if you are comparing not to many items since
the power assert will print all the items along the failed assertion; if
you have to find the proverbial needle in the haystack, you are better
off writing something smarter to check the two sets).
The assertion seems to work but I was wondering if there is maybe a
simpler way to do it than to have to write so many lines and making it
less 'bulky'?
Unclear what it is that is bulky but if what you want is to lessen the number of statements, one thing you could do is use a single assert.
Instead of this:
assert response.contains("CODE1")
assert response.contains("CODE2")
assert response.contains("CODE3")
assert response.contains("CODE4")
You could have this:
assert response.contains("CODE1") &&
response.contains("CODE2") &&
response.contains("CODE3") &&
response.contains("CODE4") &&

Using 'eachWithindex' groovy instead of For loops to read in json data

I'm having trouble with converting an existing FOR loop to use the 'eachWithIndex' groovy function.
I'm not sure how to go about doing this successfully, examples I've seen are quite straightforward on tutorials but I'm not sure how to make them work with groovy json files.
The current solution uses a For loop which reads in data from 3 different groovy files
Add_Page1_data = data.get("json_Page1")
Add_Page2_data = data.get("json_Page2")
Add_Page3_data = data.get("json_Page3")
for (int i=0; i< Add_Page1_data.size(); i++) {
execute(w, Add_Page1_data[i],
Add_Page2_data[i],
Add_Page3_data[i])
}
I then use the following code to populate data inside windows by accessing the page objects of the file before :
def execute(w, data1) {
def page1 = new PO_Add_Page1(wrapper: w)
page1.typeInSomeText(data1.sometext)
}
PageObject file looks like this:
class PO_Add_Page1 {
def typeInSomeText(val) {
wrapper.findWithLabel("Some Text . .").rightEditable().type(val)
}
Json file used contains multiple records like this:
{
"json_Page1": [
{
"sometext": "text1"
},
{
"sometext": "text2"
},
The json is fed in as the "data" which maps to elements on the page using the page object groovy file.
I wanted to be able to repeat the same functionality in a more groovy idiomatic way.
Any help would be much appreciated.

Can groovy heredocs be internationalized?

Have some multiline strings that are presented to the user and stored as Heredocs. So rather than a 'normal' (Java) property file, a groovy-based one (see here) to be consumed by ConfigSlurper was used and works great. Sorry if this is a dumb question, but can that be easily internationalized? If so, can you outline how that is accomplished?
My solution: In your ConfigSlurper you should store keys to the internalized strings. Inject messageSourceand localResolver in your controller/service, get key from your ConfigSlurper and find localized string in your i18n messages.property file. Example (not sure that code is correct, but it's the main idea):
def config = new ConfigSlurper().parse(new File('src/Config.groovy').toURL())
//localized string1 value
def msg = messageSource.getMessage(config.data1.string1, null, localeResolver.defaultLocale)
As far as I know the ConfigSlurper does not have special support for i18n.
You may achieve it by using the leveraging its support for environments by creating an environment closure per locale. For example:
environments {
english {
sample {
hello = "hello"
}
}
spanish {
sample {
hello = "hola"
}
}
}
When creating the ConfigSlurper you will need to pass the desired language:
def config = new ConfigSlurper("spanish")

AngularJS - How to send multidimensional $http.get() data

So I have a JSON array that looks something like this:
var myData = {
foo : {
biz : 'baz',
fig : 'tree'
}
}
This could be typed into the address bar like:
http://www.mysite.com/index?foo[biz]=baz&foo[fig]=tree
And this will work as expected.
The problem is that when I supply this myData object to AngularJS's $http service like:
$http.get('http://www.mysite.com', {
data : myData
});
It escapes the query string and doesn't appear to even be the right format even if it weren't esaped in the weird way it is. It looks something like:
url?foo=%7B%22biz%22%3A%22baz%22%2C%22fig%22%3A%22tree%22%7D
How can I make this work?
This is actually in the right format. Assuming your back-end is PHP, when you do $_GET['foo'] you will get %7B%22biz%22%3A%22baz%22%2C%22fig%22%3A%22tree%22%7D. The strange characters you see are because Angular is url encoding the string for you. This has to be done before transmitting the data. If you type it out as foo[biz]=baz&foo[fig]=tree in your browser, the browser usually urlencodes it automatically.
After urldecoding and json_decoding this, you will get the data you expect.
$foo = json_decode(urldecode($input), true);
Array
(
[biz] => baz
[fig] => tree
)
You can then access these as $foo['biz'] and $foo['fig']
Demo

Cannot access properties on a populate()'d object from Mongoose?

This is very odd... I'm using populate() with a ref to fill in an array within my schema, but then the properties are inaccessible. In other words, the schema is like this:
new Model('User',{
'name': String,
'installations': [ {type: String, ref: 'Installations'} ],
'count': Number,
}
Of course, Insallations is another model.
Then I find & populate a set of users...
model.find({count: 0}).populate('installations').exec( function(e, d){
for(var k in d)
{
var user = d[k];
for(var i in user.installations)
{
console.log(user.installations[i]);
}
}
} );
So far so good! I see nice data printed out, like this:
{ runs: 49,
hardware: 'macbookpro10,1/x86_64',
mode: 'debug',
version: '0.1' }
However, if I try to actually ACCESS any of those properties, they're all undefined! For example, if I add another console log:
console.log(user.installations[i].mode);
Then I see "undefined" printed for this log.
If I try to operate on the object, like this:
Object.keys(user.installations[i]).forEach(function(key) { } );
Then I get a typical "[TypeError: Object.keys called on non-object]" error, indicating that user.installations[i] is not an object (even though it is outputted to the console as if it were). So, I even tried something ugly like...
var install = JSON.parse(JSON.stringify(user.installations[i]));
console.log(install, install.mode);
And, again, the first output (install) is a nice object containing the property 'mode'... but the 2nd output is undefined.
What gives?
Finally, I solved this...
I tried doing a console.log(typeof user.installations[i]); and got "string" as the output. This seemed odd, given that printing the object directly created console output (above) that looked like a normal object, not a string. So, I tried doing a JSON.parse(); on the object, but received the error "SyntaxError: Unexpected token r"
Finally, I realized what was going on. The "pretty console output" I described above was the result of a string formatted with \n (newlines). I had not expected that, for whatever reason. The JSON.parse() error is due to the fact that there is a known necessity with the node.js parser when attempting to parse object keys without quotations; see the SO question here:
Why does JSON.parse('{"key" : "value"}') do just fine but JSON.parse('{key : "value"}') doesn't? .
Specifically, note that the JSON parser in my case is failing on the character 'r', the fist character of "runs," which is the first key in my JSON string (above). At first I was afraid I needed to get a custom JSON parser, but then the problem hit me.
Look back to my original schema. I used a String-type to define the installation ref, because the array field was storing the installations's _id property as a String. I assume the .populate() field is converting the object to a String on output.
Finally, I looked at the Mongoose docs a little closer and realized I'm supposed to be referencing the objects based upon Schema.ObjectID. This explains everything, but certainly gives me some fixing to do in my schemas and code elsewhere...

Resources