Adding properties from Java to groovy objects
I want to be able to add properties to an instance of a string object using the metaprogramming capabilities of groovy from Java
To do this from groovy is simple:
class GroovyClass { def getDynamicString() { def myString = "hello" myString.MetaClass.dynamicProperty = "there" return myString } }
This is my Spock test case:
def "should add dynamic property"() { GroovyClass groovyClass = new GroovyClass() when: def theString = groovyClass.getDynamicString() then: theString == "hello" theString.dynamicProperty == "there" }
But I want to do the same thing from Java and run it through the same tests As far as I know, groovy adds additional properties and methods (such as getmetaclass) to JDK classes like string, but I'm not sure how and when it does this I found the following solution to work, but initializing the groovy shell and writing the metaprogramming code as a string seems cumbersome
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; }
Is there any way to avoid using shell Do this in the case of evaluate – that is, by calling groovy library methods directly from Java?
Solution
So, in view of this groovy script:
def a = 'A String' Decorator.decorate( a,'foo','bar' ) assert a == 'A String' assert a.class == String assert a.foo == 'bar'
Then we can write the Java decorator class like this:
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 ) ; } }
Then, if we compile the Java class and run the groovy script, all assertions should pass