Copy Object Properties to a Map by Value not by Reference - grails

I'm not sure where i'm going wrong, but it seems that I'm not able to copy properties from an object instance and assign them to a map without the values being changed after saving the instance.
This is a sample class:
class Product {
String productName
String proudctDescription
int quantityOnHand
}
Once the form is submitted and it's sent to my controller, I can access the values and manipulate them from the productInstance.properties map that is available from the instance. I want to copy the properties to another map to preserve the values before committing them during an edit. So let's say we are editing a record and these are the values stored in the db: productName = "My Product", productDescription = "My Product Description" and quantityOnHand = 100.
I want to copy them to:
def propertiesBefore = productInstance.properties
This did not work, because when I save the productInstance, the values in propertiesBefore change to whatever the instance had.
So I tried this:
productInstance.properties.each { k,v -> propertiesBefore[k] = v }
Same thing happened again. I am not sure how to copy by value, it seems no matter what I try it copies by reference instead.
EDIT
As per the request of Pawel P., this is the code that I tested:
class Product {
String productName
String productDescription
int quantityOnHand
}
def productInstance = new Product(productName: "Some name", productDescription: "Desciption", quantityOnHand: 10)
def propertiesBefore = [:]
productInstance.properties.each { k,v -> propertiesBefore[k] = (v instanceof Cloneable) ? v.clone() : v }
productInstance.productName = "x"
productInstance.productDescription = "y"
productInstance.quantityOnHand = 9
println propertiesBefore.quantityOnHand // this will print the same as the one after the save()
productInstance.save(flush:true)
println propertiesBefore.quantityOnHand // this will print the same as the one above the save()

Without cloning, copying hash-map [:]'s values to a new hash-map [:]'s space can also be done by "pushing" the first one over, which would achieve the same result that you desired (copy by value)!
def APE = [:]
APE= [tail: 1, body: "hairy", hungry: "VERY!!!"]
def CAVEMAN = [:]
CAVEMAN << APE //push APE to CAVEMAN's space
//modify APE's values for CAVEMAN
CAVEMAN.tail = 0
CAVEMAN.body = "need clothes"
println "'APE': ${APE}"
println "'CAVEMAN': ${CAVEMAN}"
Output ==>
'APE': [tail:1, body:hairy, hungry:VERY!!!]
'CAVEMAN': [tail:0, body:need clothes, hungry:VERY!!!]

The problem is that you actually copy references to variables. To obtain copy of variable you should use clone(). Take a look:
class Product {
String productName
String productDescription
int quantityOnHand
}
def productInstance = new Product(productName: "Some name", productDescription: "Desciption", quantityOnHand: 10)
def propertiesBefore = [:]
productInstance.properties.each { k,v -> propertiesBefore[k] = (v instanceof Cloneable) ? v.clone() : v }
productInstance.productName = "x"
productInstance.productDescription = "y"
productInstance.quantityOnHand = 9
println productInstance.properties
println propertiesBefore
It prints:
[quantityOnHand:9, class:class Product, productName:x, productDescription:y]
[quantityOnHand:10, class:class Product, productName:Some name, productDescription:Desciption]

A simpler example for groovy using Hash-Map [:] can be like this:
def APE = [:]
APE= [tail: 1, body: "hairy", hungry: "VERY!!!"]
def CloneMe = APE //*APE as clone*
def CAVEMAN = [:] //*copy APE's values over thru mapping the clone*
CloneMe.each { key,value -> CAVEMAN[key] = (value instanceof Cloneable) ? value.clone() : value }
println "'CloneMe': ${CloneMe}"
//change some of the clone's values for CAVEMAN
CAVEMAN.tail = 0
CAVEMAN.body = "need clothes"
println "'APE': ${APE}"
println "'CAVEMAN': ${CAVEMAN}"
Output ==>
'CloneMe': [tail:1, body:hairy, hungry:VERY!!!]
'APE': [tail:1, body:hairy, hungry:VERY!!!]
'CAVEMAN': [tail:0, body:need clothes, hungry:VERY!!!]

Related

KeyboardOptions.Default.copy() vs KeyboardOptions(). When to use?

This is from a TextField composable
When to use "Default Copy"? Does it matter?
keyboardOptions = KeyboardOptions.Default.copy(
imeAction = ImeAction.Done,
keyboardType = KeyboardType.Text
)
// vs //
keyboardOptions = KeyboardOptions(
imeAction = ImeAction.Done,
keyboardType = KeyboardType.Text
)
if you want to keep same instance and want to update one of the properties and preserve other ones you can use .copy().
Consider this example with a data class Person
data class Person(
val name: String = "",
val age: Int = 1
)
and some use-case like this
val johnPerson = Person("John", 21)
val unknownPerson = Person(age = 23)
I can simply copy unknownPerson and keep the age 23 and finally set the person's name like this
val knownPerson = unknownPerson.copy(name = "Mr. Kebab")
prints
Person(name=Mr. Kebab, age=23)
It does not matter. They both end up doing the same thing. KeyboardOptions class is not a data class, and even if it were, the copy() method would still create a new instance.

Hi Team, am new in groovy, i know that its simple, but I got confused.in my controller i have 2list of values. thats shown like

Ratios:[2,9,3.5]//double value// AND uom:[1,2,3,4]
now need to get these through map like this,
Ratios:[2]`Ratios:[9]`Ratios:[3.5]`
uom:[1]`uom:[2]`uom:[3]`uom:[4]`
and Finally need to associate all these in one array , LIKE
MyArray[ Ratios:[2]
Ratios:[9]
Ratios:[3.5]
uom:[1]
uom:[2]
uom:[3]
uom:[4] ]
how do i get like this.PLEASE HELP ME
my code is,
def jsonSlurperjson = new groovy.json.JsonSlurper();
def jsonData = [];
def Ratios;
def UOM;
def RatioMap=[];
def Obj = jsonSlurperjson.parseText(params.Selected);
if (Obj.uom!= null || Obj.uom!= "") {
UOM= Obj.uom;
}
if (Obj.ratio != null || Obj.ratio != "") {
Ratios = Obj.ratio;
}
for(int i=0; i<Ratios.size(); i++) {
RatioMap.add(Ratios[i]);
}
You can collect over both lists to create the maps and add the two
resulting lists to get the final list
[2,9,3.5].collect{ [Ratios: it] } + [1,2,3,4].collect{ [uom: it] }
// → [[Ratios:2], [Ratios:9], [Ratios:3.5], [uom:1], [uom:2], [uom:3], [uom:4]]

Gatling: How to pass jsonPath saved variable to another exec

I am new to Gatling and scala. facing issue on passing jsonpath saved variable from one repeat section to another forEach repeat section.
following variable "dcIds" is not able to pass to forEach section. Also please direct me to make the below code more better.
var dcIdd = ""
val r = new scala.util.Random
def orderRef() = r.nextInt(100)
def getCreateRequest: String = {
val data = s"""
[{
"name":"DC_${orderRef()}",
"location":"Seattle, Washington, USA",
"type":"Colocation"
}]
""".stripMargin
data
}
def createAppRequest: String = {
val data = s"""
[{
"name":"App_${orderRef()}",
"owner":"a#a.com",
"dataCenterId":"${dcIdd}",
"strategy":"Rehost",
"migrationStrategy":"Rehost"}]
}]
""".stripMargin
data
}
val scn = scenario("Add DC")
.repeat(DcIterations, "index") {
exec(
http("List_plans")
.get(uri2 + "?plan_id=")
.headers(headers_sec)
.resources(
http("DC add")
.post(uri2)
.headers(headers_sec)
.body(StringBody(session => getCreateRequest))
.check(jsonPath("$.ids[*]").findAll.saveAs("dcIds"))))
}
.foreach("${dcIds}", "dcId") {
dcIdd = "${dcId}"
repeat(AppIterations, "index") {
exec(http("Add Application")
.post(uri1 + "/applications/${dcId}")
.headers(headers_sec)
.body(StringBody(session => createAppRequest))
)
}
}

Update each element in linked list with the data of the previous element

Given a one-way linked list, I want to update each element's value with the value of the previous node, for instance, if I have list 1 -> 2 -> 3 -> null, so after the run it'll be new_value -> 1 -> 2 -> null where new_value is given in each iteration.
What I've tried to do (pseudo-code) is:
list_head = head
for i = length-1 to 0:
current = head
do i times:
prev_data = current.data
current = current.next
current.data = prev_data
It doesn't seem to work properly, though...what am I missing? is there another way to do it?
EDIT: assume that new_value is already assigned to head at this point
Thanks in advance
You can implement list with arrays as well. Here is an implementation in javascript. Hope it helps.
var array = [1,2,3]; // list with array
var newValue = 4;
function push(value){
array.pop(); // to remove the last element
array.unshift(value); // to add the new element
console.log(array);
}
push(newValue);
I do not see a reason why you would need to use two loops - I suspect your issue has to do with the "do i times". Instead I would suggest to simply push the values through the list until the tail has been reached (and the last value is dropped). The following is an implementation of that idea using a very simple Node class:
function Node(data,next=null) {
this.data = data;
this.next = next;
this.toString = function() {
if(this.next) return this.data + " -> " + this.next.toString();
else return this.data + " -> null";
}
}
var head = new Node(1,new Node(2,new Node(3)));
console.log(head.toString())
var new_value = 0;
var curr = head;
do{
var old_value = curr.data;
curr.data = new_value;
new_value = old_value;
curr = curr.next;
} while(curr)
console.log(head.toString());

Calculate no of attachments and show it in tree view in openerp 7.0

I am using the following code to add a new column in stock.picking.in object and update the no of attachments to it (to show in tree view the count of attachments).
class stock_picking(osv.osv):
_inherit = "stock.picking.in"
_name = 'stock.picking.in'
def count_attachments(self, cr, uid, ids, fields, arg, context):
obj_attachment = self.pool.get('ir.attachment')
for record in self:
_logger.info("record now in tree view:"+record)
record.attachment_count =0
attachment_ids = obj_attachment.search([('res_model','=','stock.picking.in'),('res_id','=',record.id)]).ids
if attachment_ids:
record.attachment_count =len(attachment_ids)
return record
_columns = {
'attachment_count' :fields.function(count_attachments,method=True,string="Attachment Count" ,type='integer')
}
stock_picking()
Then I have added the following line to the tree view.
<field name="attachment_count">
to show the count in tree view.
However the values are not getting updated and the count_attachments is not getting called.
Any help is appreciated. Thanks in advance!
Try following,
class stock_picking(osv.osv):
_inherit = "stock.picking.in"
_name = 'stock.picking.in'
def count_attachments(self, cr, uid, ids, fields, arg, context=None):
obj_attachment = self.pool.get('ir.attachment')
res = {}
for record in self:
res[record.id] = 0
_logger.info("record now in tree view:"+record)
attachment_ids = obj_attachment.search([('res_model','=','stock.picking.in'),('res_id','=',record.id)]).ids
if attachment_ids:
res[record.id] = len(attachment_ids)
return res
_columns = {
'attachment_count' :fields.function(count_attachments,method=True,string="Attachment Count" ,type='integer')
}

Resources