在 groovy 中动态执行代码

Posted

技术标签:

【中文标题】在 groovy 中动态执行代码【英文标题】:executing code dynamically in groovy 【发布时间】:2014-11-21 13:07:58 【问题描述】:

我正在尝试在 groovy 中动态运行代码。我有someNode[0],这是变量var1中的值

然后我像这样添加双引号

var2 = "\""+var1+"\""

然后我尝试运行它

request.abc."$var2"=Value

我看到here 可以在属性和方法上执行此类操作。但是上面的代码不起作用。给我错误

An error occurred [Cannot set property '"someNode[0]"' on null object], see error log for details

感谢任何帮助。谢谢。

编辑 这是我的请求的sn-p


   "app":
      "bundle":"531323947",
      "cat":[
         "IAB1",
         "IAB9",
         "IAB9-30",
         "entertainment",
         "games"
      ],
      "id":"agltb3B1Yi1pbmNyDAsSA0FwcBitsL4UDA",
      .
      .

我要操作的字段是cat[0],即IAB1(我只是在上面写的代码中使用了abcsomeNode[0],但实际上它们是appcat[0]

另外,在运行上述代码之前,我使用jsonslurper 解析了请求

感谢您的帮助

【问题讨论】:

怎么样 var2 = var1 request.abc."$var2"=Value @vahid 感谢您的回复。我试图跑var2 = var1request.abc."$var2"=Value,但它给了我同样的错误An error occurred [Cannot set property 'someNode[0]' on null object], see error log for details 通常 [0] 告诉 groovy 返回任何数组的第一个元素 - 它可能与此有关 - 有没有办法在你设置好值后删除它并添加它? 你能告诉我们你的要求吗? @vahid 是对的,虽然您可以通过字符串访问,但对于数组来说可能并不容易。您上面的代码可能已经失败,因为“请求”中没有“abc”。 @cfrick 我编辑了问题以显示请求。谢谢 【参考方案1】:

一种方法是通过Eval

def request =[
"app":[
    "bundle":"531323947",
    "cat":[
            "IAB1",
            "IAB9",
            "IAB9-30",
            "entertainment",
            "games"
    ],
]
]

assert request.app.cat[0]=='IAB1'
def var = 'request.app.cat[0]'
Eval.me('request', request, "$var = 'new value'")
assert request.app.cat[0]=='new value'

【讨论】:

您应该非常小心地为Eval 提供用户内容!如果这是通过一些带有用户内容的网络界面提供的,我宁愿使用解析器。 我尝试了上述解决方案,但收到此错误 An error occurred [startup failed:Script1.groovy: 1:[parsed_MessageBody.app.cat[0]] is a constant expression, but it should be a variable expression at line: 1 column: 33. File: Script1.groovy @ line 1, column 33. 'parsed_MessageBody.app.cat[0]' = 'Value'^1 error], see error log for details 。不知道发生了什么。有什么想法吗? @user1207289 'parsed_MessageBody.app.cat[0]' = 'Value' 看起来不对。它应该是parsed_MessageBody.app.cat[0] = 'Value'(第一个字符串上没有引号) 感谢您的指出,我会尝试更改并发布结果。 现在工作正常。非常感谢,尽管我仍然需要找出 Eval.me('request', request, "$var = 'new value'") 在做什么。我知道eval,但要了解您在 eval 中传递的第一个参数。第二和第三我有点理解。【参考方案2】:

您正在访问/更新地图和列表中的值。 request.app 节点将是一个地图,request.app.cat 节点将是一个列表。可以通过多种不同的方式获取和设置地图中的值:

    直接使用put & get 方法。 使用括号[]。 使用缺少的属性作为映射键(即您使用它的方式)。

对于您想要实现的目标,即从变量键访问值,使用方法 1 或 2 比方法 3 更容易,而方法 3 在 GString 中带有变量。

使用括号的示例:

import groovy.json.JsonBuilder
import groovy.json.JsonSlurper

def request = new JsonSlurper().parseText '''
        "app":
            "bundle":"531323947",
            "cat":[
                "IAB1",
                "IAB9",
                "IAB9-30",
                "entertainment",
                "games"
            ],
            "id":"agltb3B1Yi1pbmNyDAsSA0FwcBitsL4UDA"
        
    '''

def level0 = 'app'
def level1 = 'cat'

def node = request[level0][level1]

assert request instanceof Map
assert node instanceof List
assert node[0] == 'IAB1'

node[0] = 'new value'
assert node[0] == 'new value'

println new JsonBuilder(request).toPrettyString()

输出:


    "app": 
        "cat": [
            "new value",
            "IAB9",
            "IAB9-30",
            "entertainment",
            "games"
        ],
        "id": "agltb3B1Yi1pbmNyDAsSA0FwcBitsL4UDA",
        "bundle": "531323947"
    

【讨论】:

在我的情况下,我实现这一点的唯一问题是cat[0] 在一个变量中。在我看来,再次解析 cat[0] 的开销很大。我不能像 def level1 = 'cat'node[0] = 'new value' 这样的硬编码。但在我看来,对于任何其他情况来说,这都是一个好方法。我会接受以下答案,因为它非常适合我的代码。我会提高你的答案,因为我从中吸取了教训。再次感谢您的意见。

以上是关于在 groovy 中动态执行代码的主要内容,如果未能解决你的问题,请参考以下文章

GroovyMOP 元对象协议与元编程 ( 使用 Groovy 元编程进行函数拦截 | 动态拦截函数 | 动态获取 MetaClass 中的方法 | evaluate 方法执行Groovy脚本 )

Groovy:在调用任何方法之前和之后透明地执行代码

Groovy07_Groovy动态语言

Groovy07_Groovy动态语言

GroovyGroovy 脚本调用 ( Groovy 类中调用 Groovy 脚本 | 创建 GroovyShell 对象并执行 Groovy 脚本 | 完整代码示例 )

springboot 中使用groovy脚本的各种方式