Details
-
Type:
Bug
-
Status:
Open
-
Priority:
Major
-
Resolution: Unresolved
-
Affects Version/s: 1.6
-
Component/s: groovy-jdk
-
Labels:None
-
Environment:Ubuntu Linux, JDK 1.6, Eclipse 3.4
-
Number of attachments :
Description
The following code attempts to cache a method call within the methodMissing method, however in groovy 1.6, when the method is called for a second time the cached version is not being used. This code works fine in 1.5.7.
class PersonAgain
{
def work() { "working..." }
def plays = ['Tennis', 'VolleyBall', 'BasketBall']
def methodMissing(String name, args)
{
System.out.println "methodMissing called for $name"
def methodInList = plays.find {it == name.split('play')[1] }
if(methodInList)
{
def impl = { Object[] vargs ->
return "playing ${name.split('play')[1]}..."
}
PersonAgain.metaClass."$name" = impl
return impl(args)
}
else
{
throw new MissingMethodException(name, PersonAgain.class, args)
}
}
static { PersonAgain.metaClass }
}
jack = new PersonAgain()
println jack.playTennis()
println jack.playTennis()
Activity
Guillaume Laforge
made changes -
| Field | Original Value | New Value |
|---|---|---|
| Description |
The following code attempts to cache a method call within the methodMissing method, however in groovy 1.6, when the method is called for a second time the cached version is not being used. This code works fine in 1.5.7. class PersonAgain { def work() { "working..." } def plays = ['Tennis', 'VolleyBall', 'BasketBall'] def methodMissing(String name, args) { System.out.println "methodMissing called for $name" def methodInList = plays.find {it == name.split('play')[1] } if(methodInList) { def impl = { Object[] vargs -> return "playing ${name.split('play')[1]}..." } PersonAgain.metaClass."$name" = impl return impl(args) } else { throw new MissingMethodException(name, PersonAgain.class, args) } } static { PersonAgain.metaClass } } jack = new PersonAgain() println jack.playTennis() println jack.playTennis() |
The following code attempts to cache a method call within the methodMissing method, however in groovy 1.6, when the method is called for a second time the cached version is not being used. This code works fine in 1.5.7. {code} class PersonAgain { def work() { "working..." } def plays = ['Tennis', 'VolleyBall', 'BasketBall'] def methodMissing(String name, args) { System.out.println "methodMissing called for $name" def methodInList = plays.find {it == name.split('play')[1] } if(methodInList) { def impl = { Object[] vargs -> return "playing ${name.split('play')[1]}..." } PersonAgain.metaClass."$name" = impl return impl(args) } else { throw new MissingMethodException(name, PersonAgain.class, args) } } static { PersonAgain.metaClass } } jack = new PersonAgain() println jack.playTennis() println jack.playTennis() {code} |
Guillaume Laforge
made changes -
| Fix Version/s | 1.6.1 [ 14852 ] | |
| Fix Version/s | 1.7-beta-1 [ 14014 ] |
Guillaume Laforge
made changes -
| Fix Version/s | 1.6.1 [ 14852 ] | |
| Fix Version/s | 1.6.2 [ 15151 ] |
Guillaume Laforge
made changes -
| Fix Version/s | 1.6.2 [ 15151 ] | |
| Fix Version/s | 1.6.3 [ 15251 ] |
Guillaume Laforge
made changes -
| Fix Version/s | 1.6.3 [ 15251 ] |
Guillaume Laforge
made changes -
| Fix Version/s | 1.7-beta-x [ 15538 ] | |
| Fix Version/s | 1.7-beta-1 [ 14014 ] |
blackdrag blackdrag
made changes -
| Fix Version/s | 1.8.x [ 15750 ] | |
| Fix Version/s | 2.x [ 17013 ] | |
| Fix Version/s | 1.7.x [ 15538 ] |
My understanding is that the behavior you are seeing is correct. First time you invoke playTennis(), it adds playTennis() on the metaClass of PersonAgain class, but this change won't be visible on the instance that you have already created. Any more instances that you create after this point will see the playTennis() on the PersonAgain's metaClass.
If you want even instance "jack" to see the metaClass change that you have made, then you will have to set its metaClass to null
So, if you do:
class PersonAgain { def work() { "working..." } def plays = ['Tennis', 'VolleyBall', 'BasketBall'] def methodMissing(String name, args) { System.out.println "methodMissing called for $name" def methodInList = plays.find {it == name.split('play')[1] } if(methodInList) { def impl = { Object[] vargs -> return "playing ${name.split('play')[1]}..." } PersonAgain.metaClass."$name" = impl return impl(args) } else { throw new MissingMethodException(name, PersonAgain.class, args) } } static { PersonAgain.metaClass } } jack = new PersonAgain() println jack.playTennis() // call goes to methodMissing anotherJack = new PersonAgain() println anotherJack.playTennis() // call does not go to methodMissing, but to the closure that got mapped to method name playTennis jack.metaClass = null // refresh "jack"'s metaClass too. println jack.playTennis() // now it also does not go to methodMissing, but to the closure mapped