Search code examples
groovy

How to use variable in Key Names in Groovy?


The trick in How to use a variable for the key part of a map is not working for the following.

How to make it work?

def x = [users:[[name:'Alice', age:30], [name:'Bob', age:25]], settings:[app:[name:'ExampleApp', version:'1.0.0']]]
println x

def userNameKey = "users[0].name"
def appVersionKey = "settings.app.version"

def firstUserName = x."(userNameKey)" // Accesses "users[0].name"
println "First user's name: ${firstUserName}"

def appVer = x."$appVersionKey" // Accesses "settings.app.version"
println "App version: ${appVer}"

BTW, for the curious mind, the above "solution" comes from Google Gemini --

enter image description here


Solution

  • unsafe but the easiest way to evaluate dynamic expression - Eval.me

    def x = [
          users:[
            [name:'Alice', age:30], 
            [name:'Bob', age:25]], 
          settings:[app:[name:'ExampleApp', version:'1.0.0']]
    ]
    
    def userNameKey = "ROOT.users[0].name"
    def appVersionKey = "ROOT.settings.app.version"
    
    def firstUserName = Eval.me("ROOT", x, userNameKey)
    println "First user's name: ${firstUserName}"
    
    def appVer = Eval.me("ROOT", x, appVersionKey)
    println "App version: ${appVer}"
    

    prints:

    First user's name: Alice
    App version: 1.0.0
    
    

    This option is unsafe because if evaluation expression provided by 3dr party - they could read/write almost anything from your system...


    option 2 - use jsonpath

    read more about jsonpath sysntax here: https://github.com/json-path/JsonPath

    @Grab(group='com.jayway.jsonpath', module='json-path', version='2.9.0')
    import com.jayway.jsonpath.JsonPath
    
    def x = [
          users:[
            [name:'Alice', age:30], 
            [name:'Bob', age:25]], 
          settings:[app:[name:'ExampleApp', version:'1.0.0']]
    ]
    
    def userNameKey = '$.users[0].name'
    def appVersionKey = '$.settings.app.version'
    
    def xJPath = JsonPath.parse(x)
    
    def firstUserName = xJPath.read(userNameKey)
    println "First user's name: ${firstUserName}"
    
    def appVer = xJPath.read(appVersionKey)
    println "App version: ${appVer}"