2013-03-18 74 views
3

我希望能够使用Groovy的Java元编程功能将属性添加到String对象的实例。将属性添加到来自Java的Groovy对象

在Groovy做到这一点很简单:

class GroovyClass { 
    def getDynamicString() { 
     def myString = "hello" 
     myString.metaClass.dynamicProperty = "there" 
     return myString 
    } 
} 

这里是我的斯波克测试用例:

def "should add dynamic property"() { 
    GroovyClass groovyClass = new GroovyClass() 

    when: 
    def theString = groovyClass.getDynamicString() 
    then: 
    theString == "hello" 
    theString.dynamicProperty == "there" 
} 

不过,我想从Java做同样的事情,并通过运行同样的测试。据我所知,Groovy将额外的属性和方法(如getMetaClass)添加到像String这样的JDK类中,但我不确定它究竟如何或何时执行此操作。我发现以下解决方案可行,但初始化GroovyShell并将元编程代码编写为字符串似乎很麻烦。

public String getDynamicString() 
{ 
    String myString = "hello"; 
    GroovyShell shell = new GroovyShell(); 
    shell.setVariable("myString", myString); 
    shell.setVariable("theDynamicPropertyValue", "there"); 
    shell.evaluate("myString.metaClass.dynamicProperty = theDynamicPropertyValue"); 
    return myString; 
} 

有没有办法不使用shell.evaluate上面做 - 即通过从Java调用直接Groovy的库方法?

回答

7

因此,鉴于这种常规脚本:

def a = 'A String' 

Decorator.decorate(a, 'foo', 'bar') 

assert a  == 'A String' 
assert a.class == String 
assert a.foo == 'bar' 

然后,我们可以写我们的Java装饰类,像这样:

import org.codehaus.groovy.runtime.HandleMetaClass ; 
import org.codehaus.groovy.runtime.InvokerHelper ; 

public class Decorator { 
    public static void decorate(Object o, String name, Object value) { 
    HandleMetaClass hmc = new HandleMetaClass(InvokerHelper.getMetaClass(o), o) ; 
    hmc.setProperty(name, value) ; 
    } 
} 

然后,如果我们编译java类,并运行Groovy脚本,所有断言应该通过

+0

非常感谢,完美的作品!我不确定如何,但HandleMetaClass似乎是将Java对象视为Groovy对象的关键。 – 2013-03-18 14:07:49