Reputation: 37
I have two maps ,
def configmap = [ "env" :["required": ["team" : "k", "test": "sample"], "optional" : ["anotherkey" : ""]]]
def valuesReplacementMap=[ "env.required.team":"s","env.required.test":"new", "env.optional.anotherkey":"newvalue" ]
valuesReplacementMap
has path to a key in configmap
and the new value which needs to be updated.
i need to update the value in configmap
to the value given in valuesReplacementMap
here is my code, which works
def m = [ "env" :["required": ["team" : "k", "test": "sample"], "optional" : ["anotherkey" : ""]]]
def valuesReplacementMap=[ "env.required.team":"s",
"env.required.test":"new",
"env.optional.anotherkey":"newvalue" ]
def copyofOrigMap
valuesReplacementMap.each{ key, value->
copyofOrigMap = m
key.tokenize(".").inject{ attr, val ->
if(copyofOrigMap[attr][val] instanceof java.lang.String ){
copyofOrigMap[attr][val] = value
}else
copyofOrigMap = copyofOrigMap[attr]
val
}
}
My question is
instanceof java.lang.String
, this i am doing to see if leaf node/key is reachedI went through some of the earlier posted questions , but didnt find any optimized way
Upvotes: 2
Views: 1573
Reputation: 4482
One way to solve this would be Eval.me
. The following code:
def m = [ "env" :["required": ["team" : "k", "test": "sample"], "optional" : ["anotherkey" : ""]]]
def valuesReplacementMap=[ "env.required.team":"s",
"env.required.test":"new",
"env.optional.anotherkey":"newvalue" ]
valuesReplacementMap.each { k, v ->
Eval.me('m', m, "m.${k} = '${v}'")
}
m.each { k, v ->
println "$k -> $v"
}
when executed results in:
─➤ groovy solution.groovy
env -> [required:[team:s, test:new], optional:[anotherkey:newvalue]]
─➤
(on Groovy Version: 3.0.5 JVM: 11.0.8 Vendor: Amazon.com Inc. OS: Linux)
where the first argument 'm'
param to the Eval.me
method tells eval that we want a value in the string expression bound to the name m
and the second argument is the value itself. The third argument is the expression to evaluate.
It's possible there is something more elegant than eval for this, but this is pretty concise and gives you the result you are looking for.
Is should also be noted that this only works for string values and that using Eval can be dangerous from a security perspective if any of the keys or values come from user input.
edit with potentially better security implications
As an alternative you can do this:
def m = [ "env" :["required": ["team" : "k", "test": "sample"], "optional" : ["anotherkey" : ""]]]
def valuesReplacementMap=[ "env.required.team":"s",
"env.required.test":"new",
"env.optional.anotherkey":"newvalue" ]
valuesReplacementMap.each { k, v ->
def tokens = k.tokenize('.')
def last = tokens.init().inject(m) { a, t -> a[t] }
last[tokens.last()] = v
}
m.each { k, v ->
println "$k -> $v"
}
Which produces output identical to the Eval.me
example above.
Upvotes: 4