2013-03-18 79 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