Есть ли способ перехватывать все вызовы методов в Groovy?

#groovy

#groovy

Вопрос:

Мне нужно перехватывать вызовы методов в предопределенных классах Java. Например, допустим, мне нужно перехватить метод разделения класса String, как мне это сделать?

Я попробовал это, которое работает, но я не хочу, чтобы конечный пользователь изменял свой код, обертывая свои вызовы с помощью прокси-блока.

Есть ли какой-либо способ добиться этого с помощью Groovy?

Ответ №1:

Если то, что вы хотите сделать, это перехватить вызов определенного метода, вы можете сделать что-то вроде этого…

 // intercept calls to the split method on java.lang.String
String.metaClass.split = { String arg ->
    // do whatever you want to do
}
  

Если то, что вы хотите сделать, это перехватить вызов определенного метода и выполнить некоторые действия в дополнение к вызову оригинала (например, обернуть реальный метод какой-то вашей собственной логикой), вы можете сделать что-то вроде этого:

 // get a reference to the original method...
def originalSplit = String.metaClass.getMetaMethod('split', [String] as Class[])

// now add your own version of the method to the meta class...
String.metaClass.split = { String arg ->
    // do something before invoking the original...

    // invoke the original...
    def result = originalSplit.invoke(delegate, arg)

    // do something after invoking the original...

    // return the result of invoking the original
    result
}
  

Я надеюсь, что это поможет.

Комментарии:

1. Обратите внимание, что все это будет применяться только к вызовам split метода из Groovy. Вы не сможете перехватывать вызовы split метода, которые поступают с Java или любого другого языка.

Ответ №2:

вы хотите использовать MetaClass для этого см. Документ

 ExpandoMetaClass.enableGlobally()
//call 'enableGlobally' method before adding to supplied class
String.metaClass.split = { regex -> 
  println "calling split from $delegate with $regex"
  delegate.split regex, 22
}
  

Комментарии:

1. Для чего «22»?

2. следовало бы написать 42 🙂

Ответ №3:

Чтобы перехватывать все вызовы методов в классе, переопределите Groovy invokeMethod . Пример:

 class Test {}
 
Test.metaClass.foo = {"foo() called"}
Test.metaClass.static.bar = {"bar() called"}

Test.metaClass.invokeMethod = { name, args ->
    handleInterception(name, args, delegate, false)
}

Test.metaClass.static.invokeMethod = { name, args ->
    handleInterception(name, args, delegate, true)
}
 
def handleInterception(name, args, delegate, isStatic) {
    def effDelegate = isStatic ? delegate : delegate.class
    
    println ">> Entering ${delegate.class.name}.$name() with args: $args"
    
    def metaMethod = effDelegate.metaClass.getMetaMethod(name, args)
    if (!metaMethod) {
        println "-- Method not found: $name($args)"
        return
    }
 
    try {
        def result = metaMethod.invoke(delegate, args)
        println "<< Leaving ${delegate.class.name}.$name() with result: $result"
        return result
    } catch (ex) {
        println "-- Exception occurred in $name: $ex.message"
        throw ex
    }
}
 
new Test().foo("1", 2)
Test.bar(2)
new Test().onTheFly(3)
  

Код взят из поста Рошана Даврани на groovyconsole.appspot.com .

Вывод:

 >> Entering Test.foo() with args: [1, 2]
-- Method not found: foo([1, 2])
>> Entering java.lang.Class.bar() with args: [2]
<< Leaving java.lang.Class.bar() with result: bar() called
>> Entering Test.onTheFly() with args: [3]
-- Method not found: onTheFly([3])
  

Другие варианты: