How can I intercept a call from Java to Groovy--or simulate this easily

mzWinneryj

New Member
I was hoping to use groovy's invokeMethod to do this, but it turns out that when you call from Java to Groovy, invokeMethod isn't called, but otherwise it would have worked perefectly.I have a case where I'm submitting a Groovy class to a Java class (Which I can't edit). The Groovy class is annotated and the Java class scans for the annotations and saves the annotated methods as listeners for it's events.When the event is issued I'd like to grab some information from the event object, use it to retrieve data and inject that data into the event handler in the script (Via annotated variables inside that method).The things I have control over--I instantiate the scripts, set a base class for them, and pass them to the other system to be registered. The scripts will be written by others--I have control over the script's design but my goal is simplicity.I could probably create an adapter class, but that seems quite difficult and fragile since I'd have to manually register all those methods instead of using the annotations like it does now--there are a lot of different events to listen to.I'm wondering if there are groovy tricks I'm not considering. I'm still pretty new to groovy meta-programming. Perhaps there is a way to create the adapter class automatically, or when I compile the scripts, replace the methods with forwarding methods that forward to my code before calling their real method--anything like that possible?Requested source code:Source code--well let's see, this process is spread across a few classes...This is how I set up the Groovy Class Loader with a ScriptBase\[code\]cconfig.setScriptBaseClass("tv.kress.bill.minecraft.ezplugin.ScriptBase");GroovyClassLoader gcl = new GroovyClassLoader(getClass().getClassLoader(), cconfig);\[/code\]Then I pass it to the Groovy Scripting Engine (I'm leaving out some stuff here)\[code\]gse = new GroovyScriptEngine(cpString, gcl);\[/code\]Then I instantiate the script\[code\]scriptClass = gse.loadScriptByName(file.getAbsolutePath());instance = (GroovyObject) scriptClass.newInstance();\[/code\]Then, if it's a "Listener" which is the marker interface that the "canned" java library uses to identify java classes it should scan for annotations, I pass it off to that class so that any annotated methods can be registered (Somewhere along the line "instance" became "script", same object though:\[code\] if (script instanceof Listener) pm.registerEvents((Listener) script, this);\[/code\]The interesting part of the script itself looks like this:\[code\]@EventHandlerpublic void userEvent(UserInteractEvent event) {\[/code\]What I'd like to add is the ability to, inside the userEvent, add an annotated local variable like this:\[code\] @Persist int persistedPerUserData // Or @PersistPerUser? or @Persist(User=true)?\[/code\]so that just before userEvent is called, I can intercept it. I'd grab the user name from the UserInteractionEvent, combine it with the script, variable and method name to get a unique signature like "MyScript:UserEvent:Bill:persistedPerUserData" and use that to retrieve an int I can place into persistedPerUserData.Later after the method returns grab the value from persistedPerUserData and store it back into "MyScript:UserEvent:Bill:persistedPerUserData" (Currently a hash but I expect to make it a database eventually).In this way, the script never has to consider the fact that it's dealing with different users, it just has to have a single set of variables and all the persistence just works.There are other events this will work for, but I believe they all extend the same event and that root event has the "user" field.EDIT: Just as another thing NOT to try, I tried to use the ProxyMetaClass/interceptor like this:\[code\]// Attempt (and fail) to intercept calls to an instance of clazzclass Slicer { public static Object slice(Class clazz) { Object instance; def proxy = ProxyMetaClass.getInstance(clazz); proxy.interceptor = new MyInterceptor(); proxy.use { instance = clazz.newInstance(); } return instance; } }\[/code\]With the same results, every call from a groovy class was instrumented fine, but no calls from Java were intercepted. Back to the drawing board. I guess this is why Aspects use bytecode manipulation.
 
Top