Groovy 2.3および2.4におけるTraitの差異
Groovy SSHの開発で気づいたのですが、Groovy 2.3と2.4でTraitの挙動が微妙に異なるようです。
2.3から2.4に上げたところ、Traitのメソッドに書いたクロージャをdelegate指定で実行してもdelegateのプロパティやメソッドが解決できない問題が発生しました。例えば、以下のコードの実行結果は2.3と2.4で異なります。
// クロージャをdelegate指定で実行する class U { static <T> T callWithDelegate(Closure<T> closure, Object delegate) { def cloned = closure.clone() as Closure<T> cloned.resolveStrategy = Closure.DELEGATE_FIRST cloned.delegate = delegate cloned.call() } } class A { final a = 100 } trait X { def x() { U.callWithDelegate({ -> println a }, new A()) } } class Y implements X { def y() { x() } } new Y().y()
Groovy 2.3.10では期待通りの値が返されます。
100
Groovy 2.4.4ではMissingPropertyExceptionが発生し、delegateのプロパティが解決できないことが分かります。
Caught: groovy.lang.MissingPropertyException: No such property: a for class: Y groovy.lang.MissingPropertyException: No such property: a for class: Y at X$Trait$Helper$_x_closure1.doCall(script.groovy:13) at U.callWithDelegate(script.groovy:6) at U$callWithDelegate.call(Unknown Source) at X$Trait$Helper.x(script.groovy:13) at X$Trait$Helper$x.call(Unknown Source) at Y.x(script.groovy) at Y.y(script.groovy:17) at Y$y.call(Unknown Source) at script.run(script.groovy:20)
2.4.4のバグなのか2.4系の仕様なのか分かりませんが、Traitを利用している部分はテストを書いて挙動を確認できるようにしておいた方がよさそうです。
ちなみに、2.4で改善されたものもありました。クラスに @Slf4j を付けても、2.3では log
プロパティにアクセスできませんでしたが、2.4からはアクセスできるようになっています。