繁体   English   中英

如何拦截从Java到Groovy的呼叫-或轻松模拟

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM