Groovy闭包:Grails url映射的定义如何工作

时间:2012-12-25 12:28:44

标签: grails reflection groovy closures

请注意,此问题并非直接与Grails中的url映射有关。它是关于如何定义url映射的方式。

在查看UrlMappings.groovy时,我们会看到类似的内容:

class UrlMappings {     
    static mappings = {         
        "/foo" (controller: "foo", action: "myaction")
        "/bar" (controller: "bar", action: "myaction")
        "404" (controller: 'error')
    }
}

括号表示有一个函数/方法调用。从我的理解行

"/foo" (controller: "foo", action: "myaction")

执行/foo的名为UrlMappings的函数。如果UrlMappings不包含名为/foo的函数,则会查看闭包委托。

我的问题是你可以在mappings = { .. }内使用的字符串不受限制。您可以添加任何您想要的定义。例如:

"!%&/()" (controller: "foo")

因此必须采用某种动态方式来定义这些功能。我想不出在UrlMappings类中定义这些函数的解决方案。所以我尝试使用闭包委托来提出解决方案。

使用简单的groovy脚本,我尝试了以下哪种方式对我很好:

def mappings = {
    "/foo" (controller: "foo", action: "myaction")
    "/bar" (controller: "bar", action: "myaction")
    "404" (controller: 'error')
    "!%&/()" (controller: "foo")
}

class MyMap extends LinkedHashMap {
    @Override
    public Object get(Object key) {
        if (!this.containsKey(key)) {
            this.put(key, { Map map -> println "$key called: $map" })
        }
        return super.get(key);
    }
}

mappings.delegate = new MyMap()
mappings()

因此,当/foomappings闭包内执行时,groovy会在我的委托贴图中查找名为/foo的键。因此,使用get() MyMap方法。如果不存在具有此名称的密钥,则将创建一个新密钥。键的值始终是一个闭包,它将map作为参数。

执行脚本时我得到:

/foo called: [controller:foo, action:myaction]
/bar called: [controller:bar, action:myaction]
404 called: [controller:error]
!%&/() called: [controller:foo]

所以它奏效了。但是我不知道这是否是grails使用的方式。也许有一个更简单的解决方案?

所以我的第一个问题是:还有另一种(可能更容易)的方法吗? / Grails如何解决这些函数调用?

当我作为代表尝试使用地图时,出现了另一个问题。

让我们来看看:

def closure = {
    "foo" (arg: "foo")
}

closure.delegate = ["foo": { Map map -> println "called: $map" }]
closure() // error

我希望这段代码可以打印字符串called: [arg:foo]。但是我明白了:

  

groovy.lang.MissingMethodException:没有方法签名:Test.foo()适用于参数类型:(java.util.LinkedHashMap)值:[[arg:foo]]

然后我尝试了以下结果(如预期的那样)在相同的例外中:

def delegate = new LinkedHashMap()
delegate["foo"] = { Map map -> println "called: $map" }
closure.delegate = delegate 
closure() // error

但是,如果我这样做:

class MyLinkedHashMap extends LinkedHashMap { }
def delegate = new MyLinkedHashMap()
delegate["foo"] = { Map map -> println "called: $map" }
closure.delegate = delegate 
closure() // prints "called: [arg:foo]"

有效。

所以我的第二个问题是:为什么这不适用于简单的LinkedHashMap,但适用于MyLinkedHashMap(不会修改任何内容)?

1 个答案:

答案 0 :(得分:2)

你读过关于methodMissing的内容吗?

示例如下:http://groovy.codehaus.org/Using+methodMissing+and+propertyMissing

另一个:http://blog.vladimirvivien.com/2008/02/25/creating-a-simple-builder-with-groovys-methodmissing/

grails通过将此闭包列表传递给this builder来覆盖invokeMethod来完成工作,as explained here