Serializing groovy map to string with quotes - serialization

I'm trying to persist a groovy map to a file. My current attempt is to write the string representation out and then read it back in and call evaluate on it to recreate the map when I'm ready to use it again.
The problem I'm having is that the toString() method of the map removes vital quotes from the values of the elements. When my code calls evaluate, it complains about an unknown identifier.
This code demonstrates the problem:
m = [a: 123, b: 'test']
print "orig: $m\n"
s = m.toString()
print " str: $s\n"
m2 = evaluate(s)
print " new: ${m2}\n"
The first two print statements almost work -- but the quotes around the value for the key b are gone. Instead of showing [a: 123, b: 'test'], it shows [a: 123, b: test].
At this point the damage is done. The evaluate call chokes when it tries to evaluate test as an identifier and not a string.
So, my specific questions:
Is there a better way to serialize/de-serialize maps in Groovy?
Is there a way to produce a string representation of a map with proper quotes?

Groovy provides the inspect() method returns an object as a parseable string:
// serialize
def m = [a: 123, b: 'test']
def str = m.inspect()
// deserialize
m = Eval.me(str)
Another way to serialize a groovy map as a readable string is with JSON:
// serialize
import groovy.json.JsonBuilder
def m = [a: 123, b: 'test']
def builder = new JsonBuilder()
builder(m)
println builder.toString()
// deserialize
import groovy.json.JsonSlurper
def slurper = new JsonSlurper()
m = slurper.parseText('{"a": 123, "b": "test"}')

You can use myMap.toMapString()

Related

Array assertion without knowing the position of the object

I am making a post call and after post call the object goes into array at random position so how can I assert for that object.without knowing it's response. message[position?].
Please suggest me what can I do.
Use JsonPath. Here is one example: https://stackoverflow.com/a/64373344/143475
Keep in mind there are plenty of ways to extract data from JSON that ignores the exact path or position. For example:
* def response = { a: 1, b: 2, c: 3, d: { a: 1, b: 2, e: 5 } }
* def extracted = $..e
* match extracted contains 5
If you are just concerned about arrays, use contains: https://github.com/karatelabs/karate#match-contains

Retrieving data from CBOR ByteArray

I am trying to serialize a map into CBOR in Kotlin with the Jackson CBOR Dataformats Library, this works fine if the key is a String , I can retrieve the value of that key easily but when the key in an Int, it returns null to me for every get I do, If I print out the output from values(), it gives me all values from all keys.
Code looks like this :
val mapper = CBORMapper()
val map = HashMap<Any,Any>()
map[123] = intArrayOf(22,67,2)
map[456] = intArrayOf(34,12,1)
val cborData = mapper.writeValueAsBytes(map)
println(cborData.toHex())
val deserialized = mapper.readValue(cborData, HashMap<Any,Any>().javaClass)
println(deserialized.get(123)) // returns null
println(values()) // returns all values
Try to iterate over keys and check the type:
deserialized.keys.iterator().next().javaClass
Above code, in your case should print:
123 - class java.lang.String
456 - class java.lang.String
And:
println(deserialized.get("123"))
prints:
[22, 67, 2]
Take a look on documentation:
Module extends standard Jackson streaming API (JsonFactory,
JsonParser, JsonGenerator), and as such works seamlessly with all the
higher level data abstractions (data binding, tree model, and
pluggable extensions).
You can force type using Kotlin's readValue method:
import com.fasterxml.jackson.module.kotlin.readValue
and use it like this:
val deserialized = mapper.readValue<Map<Int, IntArray>>(cborData)
deserialized.keys.forEach { key -> println("$key - ${key.javaClass}") }
println(Arrays.toString(deserialized[123]))
Above code prints:
456 - int
123 - int
[22, 67, 2]
See also:
How to use jackson to deserialize to Kotlin collections

Unable to Parse the variable value to the array variable

I was trying to pass the variable 'i' value to a array index 'locations[i]' using below karate code. but throwing an error saying unable to parse. Please suggest be for any changes.
Feature: Verify Branches
Background: For loop implementation
Given url ''
When method GET
Then status 200
* def i = 0
* def z = $.locations[i].zip
* def p = $.locations[i].phone
* def fun =
"""
function(locations){
for (var i = 0; i < locations.length; i++)
{
print(i)
print('Element at Location ' + i +':' + p)
}
}
"""
Scenario: Validate the locations
Given url ''
When method GET
Then status 200
* call fun p
It is hard to make out anything since you have not provided the value of the response. There are many things wrong here. But I'll try.
Take this line:
* def z = $.locations[i].zip
This will not work, Karate does not support variables within JsonPath by default, refer the docs: https://github.com/intuit/karate#jsonpath-filters
And I think you are un-necessarily using JsonPath where normal JavaScript would have been sufficient:
* def z = response.locations[i].zip
Also it seems you are just trying to loop over an array and call a feature. Please refer to the documentation on Data Driven Features.
Take some time and read the docs and examples please, it will be worth your time. One more tip - before I leave you to understand Karate a little better. There is a way to convert a JSON array into another JSON array should you need it:
* def fun = function(x){ return { value: x } }
* def list = [1, 2, 3]
* def res = karate.map(list, fun)
* match res == [{ value: 1 }, { value: 2 }, { value: 3 }]
So there should never be a need for you to manually do a for loop at all.

What does [:] mean in groovy?

While reading some groovy code of another developer I encountered the following definition:
def foo=[:]
What does it mean?
[:] is shorthand notation for creating a Map.
You can also add keys and values to it:
def foo = [bar: 'baz']
[:] creates an empty Map. The colon is there to distinguish it from [], which creates an empty List.
This groovy code:
def foo = [:]
is roughly equivalent to this java code:
Object foo = new java.util.LinkedHashMap();
Quoting the doc:
Notice that [:] is the empty map expression.
... which is the only Map with size() returning 0. ) By itself, it's rarely useful, but you can add values into this Map, of course:
def emptyMap = [:]
assert emptyMap.size() == 0
emptyMap.foo = 5
assert emptyMap.size() == 1
assert emptyMap.foo == 5

Import a dictionary into the current scope as variables

I have a .mat file in which I put data previously processed. When I perform
dict = scipy.io.loadmat('training_data.mat')
I get back a dict that is like this
{'encoders' : ......, 'decoders' : ........, 'stuff' : .....}
I want to selectively import the encoders and decoders variables into my current scope. The effect is the same as:
encoders = dict['encoders']
decoders = dict['decoders']
How do I cleanly do this without typing 10-15 lines?
You could import a dictionary d into the global scope using
globals().update(d)
The same thing is impossible for local scopes, since modifying the dictionary returned by locals() results in undefined behaviour.
A slightly hacky trick you could use in this situation is to import the names into the dictionary of an on-the-fly created type:
d = {"encoders": 1, "decoders": 2}
t = type("", (), d)
print t.encoders
print t.decoders
This will at least be slightly more convenient than using d["decoders"] etc.
Alternatively, you could use exec statements to create your variables:
d = {"encoders": 1, "decoders": 2}
for k, v in d.iteritems():
exec k + " = v"
This could also be done selectively.