Groovy - Как использовать метапрограммирование для добавления трассировки ко всем статическим методам класса? - PullRequest
0 голосов
/ 20 января 2011

Это то, что я имею до сих пор:

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, args)         
        println "Finished method $name"

        return result
    }
}

Это прекрасно работает большую часть времени. Тем не менее, иногда вызов getStaticMetaMethod вызывает исключение, когда не следует.

РЕДАКТИРОВАТЬ: исключение, которое он выдает:

 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)

1 Ответ

0 голосов
/ 28 сентября 2011

Вместо этого вы хотели сделать следующее?

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

Допустим, аргументы были [1,"abc",true].Это приведет к тому, что types будет [Integer,String,Boolean].

Использование оператора распространения (*) приводит к тому, что Groovy пытается вызвать метод с сигнатурой, такой как getStaticMetaMethod(String,Integer,String,Boolean).Вероятно, это не то, что вы намеревались.

Однако, поскольку нет метода этой подписи, Groovy возвращается к попытке преобразовать *type в соответствующий объект, подобный коллекции.В этом случае он имеет опцию Class[] или Object[], поскольку существуют методы getStaticMetaMethod(String,Class[]) и getStaticMetaMethod(String,Object[]).

Когда аргументы содержат только нулевое значение, Groovy не может выбирать междуприведение к Class[] или Object[], и, следовательно, исключение.Использование явного приведения (types as Class[]) проясняет ваше намерение в Groovy и устраняет неоднозначность.

Кстати, вы можете воспроизвести исключение с помощью исходного кода и:

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