この質問は、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
ofという名前の関数を実行します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()
したがって/foo
、クロージャー内で実行する必要がある場合、groovy はデリゲート マップでmappings
指定されたキーを探します。/foo
したがって、 のget()
方法MyMap
が使用されます。この名前のキーが存在しない場合は、新しいキーが作成されます。キーの値は常に、マップをパラメーターとして受け取るクロージャーです。
スクリプトを実行すると、次のようになります。
/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]"
できます。
だから私の2番目の質問は、なぜこれは単純なものでは機能しないLinkedHashMap
が、MyLinkedHashMap
(何も変更しない)で機能するのですか?