Question

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
Was it helpful?

Solution

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".

OTHER TIPS

Please check/share the code you use for calling the getName() method as sometimes when asking for a property to a groovy object it uses the getProperty or getAttribute methods, and both of them call the getStaticMetaClass() method, which I think is what is actually happening to you.

What I mean is that instead of calling directly getName o a Person object it's actually callling the method getProperty(..., personObject, 'name', ...) which calls getStaticMetaClass().getProperty(..., personObject, 'name', ...).

You can also try to debug your code putting a breakpoint on the line you call method.getName() for example and look on the stacktrace how is the getName() method being called.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top