I'm trying to inspect Groovy generated methods on some CGLib proxied Groovy class, from Java, to learn what the return and parameter types are for methods. Ex, consider this Groovy class:
class Person {
String name
}
Groovy generates getName()
and setName()
methods for the name property. getName()
presumably returns a String
and setName()
presumably takes a String
.
But when proxying this class via CGLib and intercepting invocations against the getName
using CGLib's MethodInterceptor, method.getName()
returns getMetaClass
and method.getReturnType()
returns groovy.lang.MetaClass
.
Is there a way to learn the actual method name and return type from inside a MethodInterceptor?
Edit: Here's the call stack when intercepting an invocation of Person.getName():
ExplicitMappingInterceptor.intercept(Object, Method, Object[], MethodProxy) line: 42
GroovyMMTester$A$$EnhancerByCGLIB$$915b5b4.getMetaClass() line: not available
CallSiteArray.createPogoSite(CallSite, Object, Object[]) line: 144
CallSiteArray.createCallSite(CallSite, Object, Object[]) line: 161
CallSiteArray.defaultCall(CallSite, Object, Object[]) line: 45
AbstractCallSite.call(Object, Object[]) line: 108
AbstractCallSite.call(Object) line: 112
GroovyMMTester$Map.configure() line: 18 <-- Person.getName() call is in here, but doesn't show
I think the problem you have is basically that you have the Java thinking of calling a method will call the method directly and be done with it. Well not even Java does that, but those things are hidden in the JVM. Groovy has not the luxury of modifying the JVM, so a set of methods might be called before the final method is called. Since this is an implementation detail the sequence may vary. And since Groovy is a language with runtime meta programming the target method you expect might not be called at all.
Anyway, to be able to call the method getName() in Groovy, the Groovy runtime first has to get the meta class of the Object the call is made on, which results in a call to getMetaClass(). If you intercept here, then you might never get to that method call you want.
The solution is actually easy... you just filter those helper methods. That would be any method starting with $ and any method starting with this$, as well as super$, and the getMetaClass method. Filtering means here you do not intercept, but simply continue the call by using Reflection. If you met one method that is not in that set, then you most probably have the target. in your example method.getName() will then return "getName".