[英]How can I intercept a method call to a library class in Java or Android?
[英]How can I intercept a call from Java to Groovy--or simulate this easily
我希望使用groovy的invokeMethod来执行此操作,但事实证明,当您从Java调用Groovy时,不会调用invokeMethod,否则它将完全正常工作。
我遇到了将Groovy类提交到Java类的情况(我无法编辑)。 Groovy类被注释,Java类扫描注释,并将带注释的方法保存为事件的侦听器。
发出事件时,我想从事件对象中获取一些信息,使用它来检索数据并将该数据注入脚本中的事件处理程序中(通过该方法内部的带注释的变量)。
我可以控制的事情-我实例化了脚本,为它们设置了一个基类,然后将它们传递给另一个要注册的系统。 脚本将由其他人编写-我可以控制脚本的设计,但我的目标是简单。
我可能可以创建一个适配器类,但是这看起来非常困难且脆弱,因为我必须手动注册所有这些方法,而不是像现在那样使用批注-有很多不同的事件需要听。
我想知道是否有一些我没有考虑的怪异技巧。 我对groovy元编程还很陌生。 也许有一种方法可以自动创建适配器类,或者当我编译脚本时,在调用其真实方法之前,将这些方法替换为转发给我的代码的转发方法-诸如此类吗?
请求的源代码:
源代码-好吧,让我们看看,这个过程分布在几个类中...
这就是我用ScriptBase设置Groovy类加载器的方法
cconfig.setScriptBaseClass("tv.kress.bill.minecraft.ezplugin.ScriptBase");
GroovyClassLoader gcl = new GroovyClassLoader(getClass().getClassLoader(), cconfig);
然后,将其传递给Groovy脚本引擎(我在这里省略了一些东西)
gse = new GroovyScriptEngine(cpString, gcl);
然后我实例化脚本
scriptClass = gse.loadScriptByName(file.getAbsolutePath());
instance = (GroovyObject) scriptClass.newInstance();
然后,如果它是“罐头” java库用来标识应扫描注释的java类的标记器接口的“侦听器”,则将其传递给该类,以便可以注册任何带注释的方法(沿着行“实例”变为“脚本”,但同一个对象:
if (script instanceof Listener)
pm.registerEvents((Listener) script, this);
脚本本身有趣的部分如下所示:
@EventHandler
public void userEvent(UserInteractEvent event) {
我想添加的功能是,可以在userEvent中添加这样的带注释的局部变量:
@Persist int persistedPerUserData // Or @PersistPerUser? or @Persist(User=true)?
因此在调用userEvent之前,我可以对其进行拦截。 我从UserInteractionEvent中获取用户名,并将其与脚本,变量和方法名结合使用,以获取诸如“ MyScript:UserEvent:Bill:persistedPerUserData”之类的唯一签名,并使用该签名来检索可以放入persistedPerUserData中的int。
该方法返回后,稍后从persistedPerUserData中获取值,并将其存储回“ MyScript:UserEvent:Bill:persistedPerUserData”(当前为哈希值,但我希望最终使其成为数据库)。
这样,脚本不必考虑与不同用户打交道的事实,只需要具有一组变量即可,并且所有持久性都可以正常工作。
还有其他事件可以使用,但我相信它们都扩展相同的事件,并且该根事件具有“用户”字段。
编辑:就像另一件事不要尝试,我试图使用ProxyMetaClass / interceptor这样的:
// Attempt (and fail) to intercept calls to an instance of clazz
class 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;
}
}
具有相同的结果,对来自Groovy类的每个调用进行了很好的检测,但没有拦截来自Java的调用。 回到绘图板。 我猜这就是Aspects使用字节码操作的原因。
我确实还没有找到答案,但是我想出了一些我认为可以解决的问题-我想没有人提到它,因为它是如此明显,但是我仍然在“用Java思考”而不是时髦。
好的,我希望脚本实现看起来像这样:
@EventHandler
public void userEvent(UserInteractEvent event) {
@Persist int persisteData
// At this point persistedData contains data different depending on which user was passed in
...
我认为如果我使用闭包,我想我可以做些接近的事情:
@EventHandler
public void userEvent(UserInteractEvent event) {
persistScope(event.user) {
@Persist int persistedPerUserData // Or @PersistPerUser? or @Persist(User=true)?
...
这样在persistScope中,我可以扫描闭包中的@Persist批注并执行我的操作。 这可能不完全有效,因为直到关闭开始才创建int,但是只要我从groovy调用groovy,我就可以使用问题中提到的方法来解决该问题。 要么,要么我将使用持久化的用户数据“散列”一个哈希。
它有点笨拙,但是我认为它可以工作,而且我喜欢它更加明确的事实(事实上,在我只是假设传入的“事件”具有.getUser()方法之前,现在我可以确定持久性到我想要的任何东西)。
我将尝试实现这一点,并花几天时间,看看是否有人在接受之前回答了我提出的原始问题。
编辑:我不满意此解决方案。 由于变量是在该范围内声明的,因此我不能使用@Persist批注,因此我传入了一个散列,该散列可将该模块用作数据容器,然后在闭包返回后将其保留。
仍在寻找更好的答案...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.