将 IntegerMetaClass 动态添加到 GroovyShell

Posted

技术标签:

【中文标题】将 IntegerMetaClass 动态添加到 GroovyShell【英文标题】:Adding IntegerMetaClass to GroovyShell dynamically 【发布时间】:2014-12-19 00:16:41 【问题描述】:

我想仅在给定的 GroovyShell 上下文中使用自定义 IntegerMetaClass

原因是不要让我的潜在“令人不安”IntegerMetaClass 污染整个运行时。

当我将 IntegerMetaClass.java 实现放入魔术包 groovy.runtime.metaclass.java.lang 时,它就像一个魅力。但是,当我尝试手动将其添加到中间 GroovyClassLoader 时,它停止工作。

// Pseudo-code without try catch, etc
// Within my eval factory
GroovyClassLoader gcl = new GroovyClassLoader(getClass().getClassLoader());
URL url = getClass().getClassLoader().getResource("groovy/runtime/metaclass/java/lang/IntegerMetaClass.groovy"); // I rename it to .groovy file
GroovyCodeSource gcs = new GroovyCodeSource(url);
Class<?> clazz = gcl.parseClass(gcs);
// clazz is not null here and equals to what I expect:
//   Class<groovy.runtime.metaclass.java.lang.IntegerMetaClass>

// Now trying to use it in a groovy shell
GroovyShell gs = new GroovyShell(gcl);
gs.evaluate("10.minutes"); // Where .minutes is part of my IntegerMetaClass
// Fail with an NoSuchProperty exception

我在GroovyClassLoader 上错过的不仅仅是“解析” MetaClass 吗?还有其他地方吗?

更新1:

如上所述,当我将 IntegerMetaClass.minutes 直接放在我的 java 源类路径中时,查找正在工作。

package groovy.runtime.metaclass.java.lang;

import groovy.lang.DelegatingMetaClass;
import groovy.lang.MetaClass;

public class IntegerMetaClass extends DelegatingMetaClass 
    public IntegerMetaClass(Class<Integer> delegate) 
        super(delegate);
    

    public IntegerMetaClass(MetaClass delegate) 
        super(delegate);
    

    @Override
    public Object getProperty(Object object, String property) 
        if ("minutes".equals(property)) 
            Integer q = (Integer) object;
            return new Minutes(q);
        
        return super.getProperty(object, property);
    

更新2:

一个可能但不令人满意的解决方案:

gcl.parseClass 调用之后添加以下内容

Constructor<?> constructor = clazz.getConstructor(Class.class);
DelegatingMetaClass dmc = (DelegatingMetaClass) constructor.newInstance(Integer.class);
dmc.initialize();
InvokerHelper.getMetaRegistry().setMetaClass(Integer.class, dmc);

但是这个解决方案必须在 MetaClass 源和原始目标类之间保持一种“映射”,以支持更多 Integer ...

【问题讨论】:

你能发布你的IntegerMetaClass来源吗? 相关:***.com/questions/25974525/scope-of-groovys-metaclass 问题是我不希望编写评估的 groovy 脚本的用户在使用它们之前担心“元配置”类。 【参考方案1】:

您可以使用GroovyShell 类加载器加载类:

    GroovyShell gs = new GroovyShell()
    gs.loader.loadClass('groovy.runtime.metaclass.java.lang.IntegerMetaClass')
    gs.evaluate("10.minutes")

注意:当IntegerMetaClass 是一个 groovy 文件时,我得到了一个 java.lang.IncompatibleClassChangeError,但当它是 java 时没有问题。这可能与我的环境设置有关

【讨论】:

以上是关于将 IntegerMetaClass 动态添加到 GroovyShell的主要内容,如果未能解决你的问题,请参考以下文章

将成员动态添加到动态对象

将 Telerik Datepicker 添加到动态添加的表单字段

如何将自动完成添加到动态添加的输入字段?自动完成功能不适用于动态添加的输入字段

将提示文本动态添加到滑块

将图像动态添加到画布

如何动态地将组件作为子组件添加到指令中?