Reputation: 11205
I am storing a few GStrings in a map and am trying to evaluate them at runtime as:
//this is in begginning of my class or controller or service and is a global variable
def placeholderStrings=["nameString":"My name is $name","professionString":"My profession is $profession"]
//this params map comes after arrival of request from client side and following code is inside the controller
params=["name":"name1","profession":"profession1"]
def paramsKeyMap=params.keySet()
paramsKeyMap.each{
bindings."$it"=params[it]
println it
}
println placeholderStrings.get("nameString") // this line gives error as groovy.lang.MissingPropertyException: No such property: name
Above code gives error but below code runs:
params=["name":"name1","profession":"profession1"]
def keyMap=params.keySet()
keyMap.each {
binding[it] =params[it]
println it // or even binding[it] = 'something'
}
//Now I am declaring it locally pls note this
def placeholderStrings=["nameString":"My name is $name","professionString":"My profession is $profession"]
println placeholderStrings.get("nameString") // this line gives error as groovy.lang.MissingPropertyException: No such property: name
As we can see the difference, that in the first script, the placeholderStrings were declared before the bindings, while in second, it was after the bindings. I want to do something similar to first situation because in my application, I need to evaluate the placeholder strings at runtime based on client requests.
placeholderStrings.get(keyFromParams)
.Now the issue is that when ever I call the placeholderStrings.get(keyFromParams)
, it tries to substitute the placeholders in the string and throws exception.
To fix the issue I tried to store the placeholderString values as single quoted strings like:
def placeholderStrings=["nameString":'My name is $name',"professionString":'My profession is $profession']
But then now I have no way to convert the values in above map to GString so that the placeholders can be replaced.So can anyone suggest what can be done?
Upvotes: 2
Views: 3721
Reputation: 50245
Using Expando.
def exp = new Expando()
exp.nameString = {"My name is $name"}
exp.professionString = {"My profession is $profession"}
exp.name = "Rahul"
exp.profession = "SoftwareEngineer"
assert exp.nameString() == 'My name is Rahul'
assert exp.professionString() == 'My profession is SoftwareEngineer'
exp.name = "Sachin"
exp.profession = "Cricket"
assert exp.nameString() == 'My name is Sachin'
assert exp.professionString() == 'My profession is Cricket'
EDIT
Without using Expando
def params = [name: 'Rahul', age: 25, profession: 'developer']
def stringMap = params.collectEntries([:]){k, v ->
def key = k + "String"
[(key), "My $k is $v"]
}
assert stringMap instanceof java.util.LinkedHashMap
assert stringMap == [nameString:"My name is Rahul", ageString:"My age is 25", professionString:"My profession is developer"]
assert stringMap.nameString == "My name is Rahul"
Upvotes: 2
Reputation: 123900
Lazy GStrings (e.g. "My name is ${-> name}"
) might solve the problem, but the whole approach of injecting substitutions into the script binding feels like a hack (and potential security hole) to me. You might be better off with a template engine. Groovy ships with SimpleTemplateEngine
and GStringTemplateEngine
, although I've been told that it's easy to run into memory leak issues with them (I don't know the details).
Upvotes: 4