动态地将IntegerMetaClass添加到GroovyShell

时间:2014-10-23 10:34:38

标签: java groovy metaclass groovyshell groovyclassloader

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

原因是我不会因为潜在的“令人不安”而污染整个运行时间。 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上的某些操作,而不仅仅是解析&#39; MetaClass?其他地方?

UPDATE1:

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

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);
    }
}

UPDATE2:

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

gcl.parseClass电话

之后添加以下内容
Constructor<?> constructor = clazz.getConstructor(Class.class);
DelegatingMetaClass dmc = (DelegatingMetaClass) constructor.newInstance(Integer.class);
dmc.initialize();
InvokerHelper.getMetaRegistry().setMetaClass(Integer.class, dmc);

但是这个解决方案必须保持一种映射&#39;在MetaClass源和原始目标类之间支持超过Integer ...

1 个答案:

答案 0 :(得分:1)

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

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

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