开发者

Groovy - How do I use metaprogramming to add tracing to all static methods of a class?

This is what I have so far:

static def traceMethods(Class clazz) {
    def mc = clazz.metaClass

    mc.static.invokeMethod = { String name, args ->
        List types = args.collect { it == null ? null : it.getClass() }
        MetaMethod metmeth = mc.getStaticMetaMethod(name, *types) //throws exception sometimes when it shouldnt

        println "Starting method $name"
        def result = metmeth.doMethodInvoke(delegate, ar开发者_C百科gs)         
        println "Finished method $name"

        return result
    }
}

This works perfectly most of the time. However, sometimes the call to getStaticMetaMethod throws an exception when it shouldn't.

EDIT: The exception it throws is:

 groovy.lang.GroovyRuntimeException: Ambiguous method overloading for method org.codehaus.groovy.runtime.HandleMetaClass#getStaticMetaMethod.|Cannot resolve which method to invoke for [class java.lang.String, null] due to overlapping prototypes between:|?[class java.lang.String, class [Ljava.lang.Object;]|?[class java.lang.String, class [Ljava.lang.Class;]
    at groovy.lang.MetaClassImpl.chooseMostSpecificParams(MetaClassImpl.java:2906)
    at groovy.lang.MetaClassImpl.chooseMethodInternal(MetaClassImpl.java:2859)
    at groovy.lang.MetaClassImpl.chooseMethod(MetaClassImpl.java:2800)
    at groovy.lang.MetaClassImpl.getMethodWithCachingInternal(MetaClassImpl.java:1181)
    at groovy.lang.MetaClassImpl.createPogoCallSite(MetaClassImpl.java:3022)


Did you mean to do the following instead?

MetaMethod metmeth = mc.getStaticMetaMethod(name, types as Class[])

Let's say args was [1,"abc",true]. That would result in types being [Integer,String,Boolean].

Using the spread operator (*) here causes Groovy to attempt to calls a method with a signature like getStaticMetaMethod(String,Integer,String,Boolean). That's probably not what you intended.

However, since there is no method of that signature, Groovy falls back to trying to cast *type into an appropriate collection-like object. In this case, it has the option of Class[] or Object[], since the methods getStaticMetaMethod(String,Class[]) and getStaticMetaMethod(String,Object[]) both exist.

When args contains only a null value, Groovy can't decide between casting to Class[] or Object[], and hence the exception. Using an explicit cast (types as Class[]) makes your intention clear to Groovy and removes the ambiguity.

By the way, you can reproduce the exception with your original code and:

class A {
    static def doX(String s) { }
}
traceMethods(A)
A.doX(null)
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜