首页 文章

如何拦截从Java到Groovy的调用 - 或者轻松地模拟它

提问于
浏览
2

我希望使用groovy的invokeMethod来做到这一点,但事实证明,当你从Java调用Groovy时,不会调用invokeMethod,但是否则它会完美地工作 .

我有一个案例,我将Groovy类提交给Java类(我无法编辑) . Groovy类被注释,Java类扫描注释并将注释的方法保存为它的事件的侦听器 .

当事件发出时,我想从事件对象中获取一些信息,用它来检索数据并将数据注入脚本中的事件处理程序(通过该方法中的注释变量) .

我控制的东西 - 我实例化脚本,为它们设置一个基类,并将它们传递给另一个要注册的系统 . 这些脚本将由其他人编写 - 我可以控制脚本的设计,但我的目标是简单 .

我可能会创建一个适配器类,但这似乎非常困难和脆弱,因为我必须手动注册所有这些方法而不是像现在这样使用注释 - 有很多不同的事件要听 .

我想知道是否有我不考虑的常规技巧 . 我还不熟悉常规的元编程 . 也许有一种方法可以自动创建适配器类,或者在编译脚本时,将这些方法替换为在调用真实方法之前转发到我的代码的转发方法 - 这样可能吗?

请求的源代码:

源代码 - 好吧,让我们看看,这个过程分散在几个类中......

这就是我使用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();

然后,如果它是一个“监听器”,它是“ jar 头”java库用于识别java类的标记接口,它应该扫描注释,我将它传递给该类,以便可以注册任何带注释的方法(在某处line“instance”成为“script”,同样的对象:

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”(目前是一个哈希,但我希望最终使它成为一个数据库) .

通过这种方式,脚本永远不必考虑它处理不同用户的事实,它只需要有一组变量,所有持久性都可以正常工作 .

还有其他事件可以使用,但我相信它们都扩展了同一个事件,并且root事件具有“user”字段 .

编辑:正如另一件事不尝试,我试图像这样使用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使用字节码操作的原因 .

1 回答

  • 0

    我真的没有找到答案,但我想出了一些我认为会起作用的东西 - 我想没有人提到它因为它是如此明显,但我仍然是“用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注释,所以我传入了一个模块可以用作数据容器的哈希,然后我在关闭返回后继续它 .

    还在寻找更好的答案......

相关问题