rahulserver
rahulserver

Reputation: 11205

Storing GStrings in a variable and evaluate at runtime

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.

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

Answers (2)

dmahapatro
dmahapatro

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

Peter Niederwieser
Peter Niederwieser

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

Related Questions