#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])
Другие варианты:
- Пользовательский метакласс, реализующий invokeMethod
- Реализация интерфейса Interceptor. Подробнее читайте в этом руководстве