confess vienna 2015 - metaprogramming with groovy
TRANSCRIPT
![Page 1: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/1.jpg)
METAPROGRAMMING WITH GROOVY
Iván López @ilopmar
![Page 2: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/2.jpg)
Hello!I am Iván López
@ilopmar
http://greachconf.com@madridgug
![Page 3: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/3.jpg)
Groovy is dynamic
▷ “Delay” to runtime some decisions
▷ Add properties/behaviours in runtime
▷ Wide range of applicability
![Page 4: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/4.jpg)
What is metaprogramming?
![Page 5: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/5.jpg)
“Metaprogramming is the writing of computer programs that write or manipulate other programs (or themselves) as their data.
- Wikipedia
![Page 6: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/6.jpg)
1.Runtime metaprogramming
![Page 7: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/7.jpg)
Runtime metaprogramming
▷ Groovy provides this through Meta-Object Protocol (MOP)
▷ Use MOP to:– Invoke methods dynamically– Synthesize classes and methods on
the fly
![Page 8: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/8.jpg)
What is the Meta Object Protocol?
Groovy
Groovy
Java
Java
MOP
![Page 9: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/9.jpg)
Intercepting methodsusing MOP
![Page 10: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/10.jpg)
public interface GroovyObject { Object invokeMethod(String name, Object args) Object getProperty(String propertyName) void setProperty(String propertyName, Object newValue) MetaClass getMetaClass() void setMetaClass(MetaClass metaClass)}
Groovy Interceptable
▷ GroovyObject interface
▷ Implement GroovyInterceptable to hook into the execution
![Page 11: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/11.jpg)
GroovyInterceptable exampleclass Person implements GroovyInterceptable {
String name Integer age
public Object getProperty(String propertyName) { println "Getting property '${propertyName}'" return this.@"${propertyName}" }
public void setProperty(String propertyName, Object newValue) { println "Setting property '${propertyName}' with value '${newValue}'" this.@"${propertyName}" = newValue }}
def person = new Person()person.name = "Iván"person.age = 35
println "Hello ${person.name}, you're ${person.age}"
// ExecutionSetting property 'name' with value 'Iván'Setting property 'age' with value '35'Getting property 'name'Getting property 'age'Hello Iván, you're 35
![Page 12: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/12.jpg)
GroovyInterceptable exampleclass Person implements GroovyInterceptable {
String name Integer age
public Object getProperty(String propertyName) { println "Getting property '${propertyName}'" return this.@"${propertyName}" }
public void setProperty(String propertyName, Object newValue) { println "Setting property '${propertyName}' with value '${newValue}'" this.@"${propertyName}" = newValue }}
def person = new Person()person.name = "Iván"person.age = 35
println "Hello ${person.name}, you're ${person.age}"
// ExecutionSetting property 'name' with value 'Iván'Setting property 'age' with value '35'Getting property 'name'Getting property 'age'Hello Iván, you're 35
![Page 13: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/13.jpg)
GroovyInterceptable exampleclass Person implements GroovyInterceptable {
String name Integer age
public Object getProperty(String propertyName) { println "Getting property '${propertyName}'" return this.@"${propertyName}" }
public void setProperty(String propertyName, Object newValue) { println "Setting property '${propertyName}' with value '${newValue}'" this.@"${propertyName}" = newValue }}
def person = new Person()person.name = "Iván"person.age = 35
println "Hello ${person.name}, you're ${person.age}"
// ExecutionSetting property 'name' with value 'Iván'Setting property 'age' with value '35'Getting property 'name'Getting property 'age'Hello Iván, you're 35
![Page 14: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/14.jpg)
GroovyInterceptable exampleclass Person implements GroovyInterceptable {
String name Integer age
public Object getProperty(String propertyName) { println "Getting property '${propertyName}'" return this.@"${propertyName}" }
public void setProperty(String propertyName, Object newValue) { println "Setting property '${propertyName}' with value '${newValue}'" this.@"${propertyName}" = newValue }}
def person = new Person()person.name = "Iván"person.age = 35
println "Hello ${person.name}, you're ${person.age}"
// ExecutionSetting property 'name' with value 'Iván'Setting property 'age' with value '35'Getting property 'name'Getting property 'age'Hello Iván, you're 35
![Page 15: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/15.jpg)
GroovyInterceptable exampleclass Person implements GroovyInterceptable {
String name Integer age
public Object getProperty(String propertyName) { println "Getting property '${propertyName}'" return this.@"${propertyName}" }
public void setProperty(String propertyName, Object newValue) { println "Setting property '${propertyName}' with value '${newValue}'" this.@"${propertyName}" = newValue }}
def person = new Person()person.name = "Iván"person.age = 35
println "Hello ${person.name}, you're ${person.age}"
// ExecutionSetting property 'name' with value 'Iván'Setting property 'age' with value '35'Getting property 'name'Getting property 'age'Hello Iván, you're 35
![Page 16: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/16.jpg)
class Hello implements GroovyInterceptable {
public Object invokeMethod(String methodName, Object args) { System.out.println "Invoking method '${methodName}' with args '${args}'"
def method = metaClass.getMetaMethod(methodName, args) method?.invoke(this, args) }
void sayHi(String name) { System.out.println "Hello ${name}" }}
def hello = new Hello()hello.sayHi("ConFess Vienna!")hello.anotherMethod()
GroovyInterceptable example (II)
// ExecutionInvoking method 'sayHi' with args '[ConFess Vienna!]'Hello ConFess Vienna!Invoking method 'anotherMethod' with args '[]'
![Page 17: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/17.jpg)
class Hello implements GroovyInterceptable {
public Object invokeMethod(String methodName, Object args) { System.out.println "Invoking method '${methodName}' with args '${args}'"
def method = metaClass.getMetaMethod(methodName, args) method?.invoke(this, args) }
void sayHi(String name) { System.out.println "Hello ${name}" }}
def hello = new Hello()hello.sayHi("ConFess Vienna!")hello.anotherMethod()
GroovyInterceptable example (II)
// ExecutionInvoking method 'sayHi' with args '[ConFess Vienna!]'Hello ConFess Vienna!Invoking method 'anotherMethod' with args '[]'
![Page 18: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/18.jpg)
class Hello implements GroovyInterceptable {
public Object invokeMethod(String methodName, Object args) { System.out.println "Invoking method '${methodName}' with args '${args}'"
def method = metaClass.getMetaMethod(methodName, args) method?.invoke(this, args) }
void sayHi(String name) { System.out.println "Hello ${name}" }}
def hello = new Hello()hello.sayHi("ConFess Vienna!")hello.anotherMethod()
GroovyInterceptable example (II)
// ExecutionInvoking method 'sayHi' with args '[ConFess Vienna!]'Hello ConFess Vienna!Invoking method 'anotherMethod' with args '[]'
![Page 19: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/19.jpg)
class Hello implements GroovyInterceptable {
public Object invokeMethod(String methodName, Object args) { System.out.println "Invoking method '${methodName}' with args '${args}'"
def method = metaClass.getMetaMethod(methodName, args) method?.invoke(this, args) }
void sayHi(String name) { System.out.println "Hello ${name}" }}
def hello = new Hello()hello.sayHi("ConFess Vienna!")hello.anotherMethod()
GroovyInterceptable example (II)
// ExecutionInvoking method 'sayHi' with args '[ConFess Vienna!]'Hello ConFess Vienna!Invoking method 'anotherMethod' with args '[]'
![Page 20: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/20.jpg)
MetaClass▷ MetaClass registry for each class
▷ Collection of methods/properties
▷ We can always modify the metaclass
▷ Intercept methods implementing invokeMethod on metaclass
![Page 21: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/21.jpg)
class Hello { void sayHi(String name) { println "Hello ${name}" }}
Hello.metaClass.invokeMethod = { String methodName, args -> println "Invoking method '${methodName}' with args '${args}'"
def method = Hello.metaClass.getMetaMethod(methodName, args) method?.invoke(delegate, args)}
def hello = new Hello()
hello.sayHi("ConFess Vienna!")hello.anotherMethod()
// ExecutionInvoking method 'sayHi' with args '[ConFess Vienna!]'Hello ConFess Vienna!Invoking method 'anotherMethod' with args '[]'
MetaClass example
![Page 22: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/22.jpg)
class Hello { void sayHi(String name) { println "Hello ${name}" }}
Hello.metaClass.invokeMethod = { String methodName, args -> println "Invoking method '${methodName}' with args '${args}'"
def method = Hello.metaClass.getMetaMethod(methodName, args) method?.invoke(delegate, args)}
def hello = new Hello()
hello.sayHi("ConFess Vienna!")hello.anotherMethod()
// ExecutionInvoking method 'sayHi' with args '[ConFess Vienna!]'Hello ConFess Vienna!Invoking method 'anotherMethod' with args '[]'
MetaClass example
![Page 23: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/23.jpg)
class Hello { void sayHi(String name) { println "Hello ${name}" }}
Hello.metaClass.invokeMethod = { String methodName, args -> println "Invoking method '${methodName}' with args '${args}'"
def method = Hello.metaClass.getMetaMethod(methodName, args) method?.invoke(delegate, args)}
def hello = new Hello()
hello.sayHi("ConFess Vienna!")hello.anotherMethod()
// ExecutionInvoking method 'sayHi' with args '[ConFess Vienna!]'Hello ConFess Vienna!Invoking method 'anotherMethod' with args '[]'
MetaClass example
![Page 24: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/24.jpg)
class Hello { void sayHi(String name) { println "Hello ${name}" }}
Hello.metaClass.invokeMethod = { String methodName, args -> println "Invoking method '${methodName}' with args '${args}'"
def method = Hello.metaClass.getMetaMethod(methodName, args) method?.invoke(delegate, args)}
def hello = new Hello()
hello.sayHi("ConFess Vienna!")hello.anotherMethod()
// ExecutionInvoking method 'sayHi' with args '[ConFess Vienna!]'Hello ConFess Vienna!Invoking method 'anotherMethod' with args '[]'
MetaClass example
![Page 25: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/25.jpg)
class Hello { void sayHi(String name) { println "Hello ${name}" }}
Hello.metaClass.invokeMethod = { String methodName, args -> println "Invoking method '${methodName}' with args '${args}'"
def method = Hello.metaClass.getMetaMethod(methodName, args) method?.invoke(delegate, args)}
def hello = new Hello()
hello.sayHi("ConFess Vienna!")hello.anotherMethod()
// ExecutionInvoking method 'sayHi' with args '[ConFess Vienna!]'Hello ConFess Vienna!Invoking method 'anotherMethod' with args '[]'
MetaClass example
![Page 26: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/26.jpg)
MOP method injection
![Page 27: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/27.jpg)
MOP Method Injection▷ Injecting methods at code-writing time
▷ We can “open” a class any time
▷ Different techniques:– MetaClass– Categories– Extensions– Mixins vs Traits
![Page 28: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/28.jpg)
class StringUtils { static String truncate(String text, Integer length, Boolean overflow = false) { text.take(length) + (overflow ? '...' : '') }}
String chuckIpsum = "If you can see Chuck Norris, he can see you.\If you can not see Chuck Norris you may be only seconds away from death"
println StringUtils.truncate(chuckIpsum, 72)println StringUtils.truncate(chuckIpsum, 72, true)
// ExecutionIf you can see Chuck Norris, he can see you. If you can not see Chuck NoIf you can see Chuck Norris, he can see you. If you can not see Chuck No...
String.metaClass.truncate = { Integer length, Boolean overflow = false -> delegate.take(length) + (overflow ? '...' : '')}
assert chuckIpsum.truncate(72, true) == StringUtils.truncate(chuckIpsum, 72, true)
Adding methods using MetaClass
![Page 29: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/29.jpg)
class StringUtils { static String truncate(String text, Integer length, Boolean overflow = false) { text.take(length) + (overflow ? '...' : '') }}
String chuckIpsum = "If you can see Chuck Norris, he can see you.\If you can not see Chuck Norris you may be only seconds away from death"
println StringUtils.truncate(chuckIpsum, 72)println StringUtils.truncate(chuckIpsum, 72, true)
// ExecutionIf you can see Chuck Norris, he can see you. If you can not see Chuck NoIf you can see Chuck Norris, he can see you. If you can not see Chuck No...
String.metaClass.truncate = { Integer length, Boolean overflow = false -> delegate.take(length) + (overflow ? '...' : '')}
assert chuckIpsum.truncate(72, true) == StringUtils.truncate(chuckIpsum, 72, true)
Adding methods using MetaClass
![Page 30: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/30.jpg)
class StringUtils { static String truncate(String text, Integer length, Boolean overflow = false) { text.take(length) + (overflow ? '...' : '') }}
String chuckIpsum = "If you can see Chuck Norris, he can see you.\If you can not see Chuck Norris you may be only seconds away from death"
println StringUtils.truncate(chuckIpsum, 72)println StringUtils.truncate(chuckIpsum, 72, true)
// ExecutionIf you can see Chuck Norris, he can see you. If you can not see Chuck NoIf you can see Chuck Norris, he can see you. If you can not see Chuck No...
String.metaClass.truncate = { Integer length, Boolean overflow = false -> delegate.take(length) + (overflow ? '...' : '')}
assert chuckIpsum.truncate(72, true) == StringUtils.truncate(chuckIpsum, 72, true)
Adding methods using MetaClass
![Page 31: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/31.jpg)
class StringUtils { static String truncate(String text, Integer length, Boolean overflow = false) { text.take(length) + (overflow ? '...' : '') }}
String chuckIpsum = "If you can see Chuck Norris, he can see you.\If you can not see Chuck Norris you may be only seconds away from death"
println StringUtils.truncate(chuckIpsum, 72)println StringUtils.truncate(chuckIpsum, 72, true)
// ExecutionIf you can see Chuck Norris, he can see you. If you can not see Chuck NoIf you can see Chuck Norris, he can see you. If you can not see Chuck No...
String.metaClass.truncate = { Integer length, Boolean overflow = false -> delegate.take(length) + (overflow ? '...' : '')}
assert chuckIpsum.truncate(72, true) == StringUtils.truncate(chuckIpsum, 72, true)
Adding methods using MetaClass
![Page 32: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/32.jpg)
class StringUtils { static String truncate(String text, Integer length, Boolean overflow = false) { text.take(length) + (overflow ? '...' : '') }}
String chuckIpsum = "If you can see Chuck Norris, he can see you.\If you can not see Chuck Norris you may be only seconds away from death"
println StringUtils.truncate(chuckIpsum, 72)println StringUtils.truncate(chuckIpsum, 72, true)
// ExecutionIf you can see Chuck Norris, he can see you. If you can not see Chuck NoIf you can see Chuck Norris, he can see you. If you can not see Chuck No...
String.metaClass.truncate = { Integer length, Boolean overflow = false -> delegate.take(length) + (overflow ? '...' : '')}
assert chuckIpsum.truncate(72, true) == StringUtils.truncate(chuckIpsum, 72, true)
Adding methods using MetaClass
![Page 33: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/33.jpg)
class StringUtils { static String truncate(String text, Integer length, Boolean overflow = false) { text.take(length) + (overflow ? '...' : '') }}
String chuckIpsum = "If you can see Chuck Norris, he can see you.\If you can not see Chuck Norris you may be only seconds away from death"
println StringUtils.truncate(chuckIpsum, 72)println StringUtils.truncate(chuckIpsum, 72, true)
// ExecutionIf you can see Chuck Norris, he can see you. If you can not see Chuck NoIf you can see Chuck Norris, he can see you. If you can not see Chuck No...
String.metaClass.truncate = { Integer length, Boolean overflow = false -> delegate.take(length) + (overflow ? '...' : '')}
assert chuckIpsum.truncate(72, true) == StringUtils.truncate(chuckIpsum, 72, true)
Adding methods using MetaClass
![Page 34: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/34.jpg)
class Utils {}
def utilsInstance = new Utils()
Utils.metaClass.version = "3.0"utilsInstance.metaClass.released = true
assert utilsInstance.version == "3.0"assert utilsInstance.released == true
Adding properties using MetaClass
![Page 35: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/35.jpg)
Adding properties using MetaClass
class Utils {}
def utilsInstance = new Utils()
Utils.metaClass.version = "3.0"utilsInstance.metaClass.released = true
assert utilsInstance.version == "3.0"assert utilsInstance.released == true
![Page 36: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/36.jpg)
class Utils {}
def utilsInstance = new Utils()
Utils.metaClass.version = "3.0"utilsInstance.metaClass.released = true
assert utilsInstance.version == "3.0"assert utilsInstance.released == true
Adding properties using MetaClass
![Page 37: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/37.jpg)
class Utils {}
def utilsInstance = new Utils()
Utils.metaClass.version = "3.0"utilsInstance.metaClass.released = true
assert utilsInstance.version == "3.0"assert utilsInstance.released == true
Adding properties using MetaClass
![Page 38: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/38.jpg)
// Integerassert '42' == 42.toString()
Integer.metaClass.toString = { delegate == 42 ? 'The answer to life, the universe and everything' : String.valueOf(delegate)}
assert 42.toString() == 'The answer to life, the universe and everything'assert 100.toString() == '100'
// Booleanassert false.toBoolean() == false
Boolean.metaClass.toBoolean = { !delegate }assert false.toBoolean() == true
Overriding methods using MetaClass
![Page 39: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/39.jpg)
// Integerassert '42' == 42.toString()
Integer.metaClass.toString = { delegate == 42 ? 'The answer to life, the universe and everything' : String.valueOf(delegate)}
assert 42.toString() == 'The answer to life, the universe and everything'assert 100.toString() == '100'
// Booleanassert false.toBoolean() == false
Boolean.metaClass.toBoolean = { !delegate }assert false.toBoolean() == true
Overriding methods using MetaClass
![Page 40: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/40.jpg)
// Integerassert '42' == 42.toString()
Integer.metaClass.toString = { delegate == 42 ? 'The answer to life, the universe and everything' : String.valueOf(delegate)}
assert 42.toString() == 'The answer to life, the universe and everything'assert 100.toString() == '100'
// Booleanassert false.toBoolean() == false
Boolean.metaClass.toBoolean = { !delegate }assert false.toBoolean() == true
Overriding methods using MetaClass
![Page 41: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/41.jpg)
// Integerassert '42' == 42.toString()
Integer.metaClass.toString = { delegate == 42 ? 'The answer to life, the universe and everything' : String.valueOf(delegate)}
assert 42.toString() == 'The answer to life, the universe and everything'assert 100.toString() == '100'
// Booleanassert false.toBoolean() == false
Boolean.metaClass.toBoolean = { !delegate }assert false.toBoolean() == true
Overriding methods using MetaClass
![Page 42: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/42.jpg)
// Integerassert '42' == 42.toString()
Integer.metaClass.toString = { delegate == 42 ? 'The answer to life, the universe and everything' : String.valueOf(delegate)}
assert 42.toString() == 'The answer to life, the universe and everything'assert 100.toString() == '100'
// Booleanassert false.toBoolean() == false
Boolean.metaClass.toBoolean = { !delegate }assert false.toBoolean() == true
Overriding methods using MetaClass
![Page 43: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/43.jpg)
// Integerassert '42' == 42.toString()
Integer.metaClass.toString = { delegate == 42 ? 'The answer to life, the universe and everything' : String.valueOf(delegate)}
assert 42.toString() == 'The answer to life, the universe and everything'assert 100.toString() == '100'
// Booleanassert false.toBoolean() == false
Boolean.metaClass.toBoolean = { !delegate }assert false.toBoolean() == true
Overriding methods using MetaClass
![Page 44: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/44.jpg)
Categories
▷ MetaClass changes are “persistent”
▷ Change metaclass in confined code
▷ MOP modified only in the closure
![Page 45: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/45.jpg)
Categories exampleclass StringUtils { static String truncate(String text, Integer length, Boolean overflow = false) { text.take(length) + (overflow ? '...' : '') }}
use (StringUtils) { println "Lorem ipsum".truncate(5)}
try { println "Lorem ipsum".truncate(5)} catch (MissingMethodException mme) { println mme}
// ExecutionLorem
groovy.lang.MissingMethodException: No signature of method: java.lang.String.truncate() is applicable for argument types: (java.lang.Integer) values: [5]Possible solutions: concat(java.lang.String), take(int)
![Page 46: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/46.jpg)
Categories exampleclass StringUtils { static String truncate(String text, Integer length, Boolean overflow = false) { text.take(length) + (overflow ? '...' : '') }}
use (StringUtils) { println "Lorem ipsum".truncate(5)}
try { println "Lorem ipsum".truncate(5)} catch (MissingMethodException mme) { println mme}
// ExecutionLorem
groovy.lang.MissingMethodException: No signature of method: java.lang.String.truncate() is applicable for argument types: (java.lang.Integer) values: [5]Possible solutions: concat(java.lang.String), take(int)
![Page 47: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/47.jpg)
Categories exampleclass StringUtils { static String truncate(String text, Integer length, Boolean overflow = false) { text.take(length) + (overflow ? '...' : '') }}
use (StringUtils) { println "Lorem ipsum".truncate(5)}
try { println "Lorem ipsum".truncate(5)} catch (MissingMethodException mme) { println mme}
// ExecutionLorem
groovy.lang.MissingMethodException: No signature of method: java.lang.String.truncate() is applicable for argument types: (java.lang.Integer) values: [5]Possible solutions: concat(java.lang.String), take(int)
![Page 48: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/48.jpg)
Categories exampleclass StringUtils { static String truncate(String text, Integer length, Boolean overflow = false) { text.take(length) + (overflow ? '...' : '') }}
use (StringUtils) { println "Lorem ipsum".truncate(5)}
try { println "Lorem ipsum".truncate(5)} catch (MissingMethodException mme) { println mme}
// ExecutionLorem
groovy.lang.MissingMethodException: No signature of method: java.lang.String.truncate() is applicable for argument types: (java.lang.Integer) values: [5]Possible solutions: concat(java.lang.String), take(int)
![Page 49: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/49.jpg)
class FileBinaryCategory { def static leftShift(File file, URL url) { def input def output
try { input = url.openStream() output = new BufferedOutputStream(new FileOutputStream(file))
output << input } finally { input?.close() output?.close() } }}
Categories example (II)
![Page 50: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/50.jpg)
class FileBinaryCategory { def static leftShift(File file, URL url) { def input def output
try { input = url.openStream() output = new BufferedOutputStream(new FileOutputStream(file))
output << input } finally { input?.close() output?.close() } }}
Categories example (II)
![Page 51: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/51.jpg)
class FileBinaryCategory { def static leftShift(File file, URL url) { def input def output
try { input = url.openStream() output = new BufferedOutputStream(new FileOutputStream(file))
output << input } finally { input?.close() output?.close() } }}
Categories example (II)
File tmpFile = File.createTempFile('tmp_', '')
use (FileBinaryCategory) { tmpFile << "http://groovy.codehaus.org/images/groovy-logo-medium.png".toURL()}
println tmpFile
// Execution/tmp/tmp_7428855173238452155
![Page 52: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/52.jpg)
class FileBinaryCategory { def static leftShift(File file, URL url) { def input def output
try { input = url.openStream() output = new BufferedOutputStream(new FileOutputStream(file))
output << input } finally { input?.close() output?.close() } }}
Categories example (II)
File tmpFile = File.createTempFile('tmp_', '')
use (FileBinaryCategory) { tmpFile << "http://groovy.codehaus.org/images/groovy-logo-medium.png".toURL()}
println tmpFile
// Execution/tmp/tmp_7428855173238452155
![Page 53: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/53.jpg)
class FileBinaryCategory { def static leftShift(File file, URL url) { def input def output
try { input = url.openStream() output = new BufferedOutputStream(new FileOutputStream(file))
output << input } finally { input?.close() output?.close() } }}
Categories example (II)
File tmpFile = File.createTempFile('tmp_', '')
use (FileBinaryCategory) { tmpFile << "http://groovy.codehaus.org/images/groovy-logo-medium.png".toURL()}
println tmpFile
// Execution/tmp/tmp_7428855173238452155
![Page 54: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/54.jpg)
class FileBinaryCategory { def static leftShift(File file, URL url) { def input def output
try { input = url.openStream() output = new BufferedOutputStream(new FileOutputStream(file))
output << input } finally { input?.close() output?.close() } }}
Categories example (II)
File tmpFile = File.createTempFile('tmp_', '')
use (FileBinaryCategory) { tmpFile << "http://groovy.codehaus.org/images/groovy-logo-medium.png".toURL()}
println tmpFile
// Execution/tmp/tmp_7428855173238452155
![Page 55: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/55.jpg)
Extension modules
▷ JAR file that provides extra methods
▷ Meta-information file
▷ Put jar in classpath to enhance classes
![Page 56: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/56.jpg)
// src/main/groovy/confess2015/StringUtilsExtension.groovypackage confess2015class StringUtilsExtension { static String truncate(String self, Integer length, Boolean overflow = false) { self.take(length) + (overflow ? '...' : '') }}
package confess2015import spock.lang.Specificationclass StringUtilsExtensionSpec extends Specification { void 'test trucate'() { expect: "Lorem" == "Lorem ipsum".truncate(5) "Lorem..." == "Lorem ipsum".truncate(5, true) }}
// Execute with:// gradle build// groovy -cp build/libs/string-extensions-1.0.jar ExtensionExample1.groovy
assert "Lorem..." == "Lorem ipsum". truncate(5, true)
# src/main/resources/META-INF/services/org.codehaus.groovy.runtime.ExtensionModulemoduleName = string-utils-modulemoduleVersion = 0.1extensionClasses = confess2015.StringUtilsExtension
Extension modules example
![Page 57: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/57.jpg)
Extension modules example// src/main/groovy/confess2015/StringUtilsExtension.groovypackage confess2015class StringUtilsExtension { static String truncate(String self, Integer length, Boolean overflow = false) { self.take(length) + (overflow ? '...' : '') }}
# src/main/resources/META-INF/services/org.codehaus.groovy.runtime.ExtensionModulemoduleName = string-utils-modulemoduleVersion = 0.1extensionClasses = confess2015.StringUtilsExtension
package confess2015import spock.lang.Specificationclass StringUtilsExtensionSpec extends Specification { void 'test trucate'() { expect: "Lorem" == "Lorem ipsum".truncate(5) "Lorem..." == "Lorem ipsum".truncate(5, true) }}
// Execute with:// gradle build// groovy -cp build/libs/string-extensions-1.0.jar ExtensionExample1.groovy
assert "Lorem..." == "Lorem ipsum". truncate(5, true)
![Page 58: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/58.jpg)
Extension modules example// src/main/groovy/confess2015/StringUtilsExtension.groovypackage confess2015class StringUtilsExtension { static String truncate(String self, Integer length, Boolean overflow = false) { self.take(length) + (overflow ? '...' : '') }}
package confess2015import spock.lang.Specificationclass StringUtilsExtensionSpec extends Specification { void 'test trucate'() { expect: "Lorem" == "Lorem ipsum".truncate(5) "Lorem..." == "Lorem ipsum".truncate(5, true) }}
// Execute with:// gradle build// groovy -cp build/libs/string-extensions-1.0.jar ExtensionExample1.groovy
assert "Lorem..." == "Lorem ipsum". truncate(5, true)
# src/main/resources/META-INF/services/org.codehaus.groovy.runtime.ExtensionModulemoduleName = string-utils-modulemoduleVersion = 0.1extensionClasses = confess2015.StringUtilsExtension
![Page 59: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/59.jpg)
Extension modules example// src/main/groovy/confess2015/StringUtilsExtension.groovypackage confess2015class StringUtilsExtension { static String truncate(String self, Integer length, Boolean overflow = false) { self.take(length) + (overflow ? '...' : '') }}
package confess2015import spock.lang.Specificationclass StringUtilsExtensionSpec extends Specification { void 'test trucate'() { expect: "Lorem" == "Lorem ipsum".truncate(5) "Lorem..." == "Lorem ipsum".truncate(5, true) }}
// Execute with:// gradle build// groovy -cp build/libs/string-extensions-1.0.jar ExtensionExample1.groovy
assert "Lorem..." == "Lorem ipsum". truncate(5, true)
# src/main/resources/META-INF/services/org.codehaus.groovy.runtime.ExtensionModulemoduleName = string-utils-modulemoduleVersion = 0.1extensionClasses = confess2015.StringUtilsExtension
![Page 60: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/60.jpg)
// src/main/groovy/confess2015/StringUtilsExtension.groovypackage confess2015class StringUtilsExtension { static String truncate(String self, Integer length, Boolean overflow = false) { self.take(length) + (overflow ? '...' : '') }}
package confess2015import spock.lang.Specificationclass StringUtilsExtensionSpec extends Specification { void 'test trucate'() { expect: "Lorem" == "Lorem ipsum".truncate(5) "Lorem..." == "Lorem ipsum".truncate(5, true) }}
// Execute with:// gradle build// groovy -cp build/libs/string-extensions-1.0.jar ExtensionExample1.groovy
assert "Lorem..." == "Lorem ipsum". truncate(5, true)
Extension modules example
# src/main/resources/META-INF/services/org.codehaus.groovy.runtime.ExtensionModulemoduleName = string-utils-modulemoduleVersion = 0.1extensionClasses = confess2015.StringUtilsExtension
![Page 61: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/61.jpg)
Mixins
▷ “Bring in” or “mix in” implementations from multiple classes
▷ Calls first routed to mixed-in class
▷ Last mixin wins
▷ Not easily un-done
![Page 62: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/62.jpg)
class SpidermanPower { String spiderSense() { "Using spider-sense..." }}
Mixins example
@Mixin([SpidermanPower])class Person {}
def person = new Person()assert person.spiderSense() == "Using spider-sense..."assert !(person instanceof SpidermanPower)
Person.mixin SupermanPowerassert person.fly() == "Flying..."assert !(person instanceof SupermanPower)
class SupermanPower { String fly() { "Flying..." }}
![Page 63: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/63.jpg)
@Mixin([SpidermanPower])class Person {}
def person = new Person()assert person.spiderSense() == "Using spider-sense..."assert !(person instanceof SpidermanPower)
Person.mixin SupermanPowerassert person.fly() == "Flying..."assert !(person instanceof SupermanPower)
class SupermanPower { String fly() { "Flying..." }}
class SpidermanPower { String spiderSense() { "Using spider-sense..." }}
Mixins example
![Page 64: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/64.jpg)
@Mixin([SpidermanPower])class Person {}
def person = new Person()assert person.spiderSense() == "Using spider-sense..."assert !(person instanceof SpidermanPower)
Person.mixin SupermanPowerassert person.fly() == "Flying..."assert !(person instanceof SupermanPower)
class SupermanPower { String fly() { "Flying..." }}
class SpidermanPower { String spiderSense() { "Using spider-sense..." }}
Mixins example
![Page 65: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/65.jpg)
@Mixin([SpidermanPower])class Person {}
def person = new Person()assert person.spiderSense() == "Using spider-sense..."assert !(person instanceof SpidermanPower)
Person.mixin SupermanPowerassert person.fly() == "Flying..."assert !(person instanceof SupermanPower)
class SupermanPower { String fly() { "Flying..." }}
class SpidermanPower { String spiderSense() { "Using spider-sense..." }}
Mixins example
![Page 66: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/66.jpg)
@Mixin([SpidermanPower])class Person {}
def person = new Person()assert person.spiderSense() == "Using spider-sense..."assert !(person instanceof SpidermanPower)
Person.mixin SupermanPowerassert person.fly() == "Flying..."assert !(person instanceof SupermanPower)
class SpidermanPower { String spiderSense() { "Using spider-sense..." }}
Mixins exampleclass SupermanPower { String fly() { "Flying..." }}
![Page 67: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/67.jpg)
@Mixin([SpidermanPower])class Person {}
def person = new Person()assert person.spiderSense() == "Using spider-sense..."assert !(person instanceof SpidermanPower)
Person.mixin SupermanPowerassert person.fly() == "Flying..."assert !(person instanceof SupermanPower)
class SpidermanPower { String spiderSense() { "Using spider-sense..." }}
Mixins exampleclass SupermanPower { String fly() { "Flying..." }}
![Page 68: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/68.jpg)
Traits▷ Groovy 2.3+
▷ Similar to Java 8 default methods
▷ Supported in JDK 6, 7 and 8
▷ Stateful
▷ Composition over inheritance
▷ Documentation
![Page 69: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/69.jpg)
class Person implements SpidermanPower {}
def person = new Person()assert person.spiderSense() == "Using spider-sense..."assert person instanceof SpidermanPower
def person2 = person.withTraits SupermanPowerassert person2.fly() == "Flying..."assert person2 instanceof SupermanPower
Traits exampletrait SpidermanPower { String spiderSense() { "Using spider-sense..." }}
trait SupermanPower { String fly() { "Flying..." }}
![Page 70: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/70.jpg)
class Person implements SpidermanPower {}
def person = new Person()assert person.spiderSense() == "Using spider-sense..."assert person instanceof SpidermanPower
def person2 = person.withTraits SupermanPowerassert person2.fly() == "Flying..."assert person2 instanceof SupermanPower
Traits exampletrait SpidermanPower { String spiderSense() { "Using spider-sense..." }}
trait SupermanPower { String fly() { "Flying..." }}
![Page 71: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/71.jpg)
class Person implements SpidermanPower {}
def person = new Person()assert person.spiderSense() == "Using spider-sense..."assert person instanceof SpidermanPower
def person2 = person.withTraits SupermanPowerassert person2.fly() == "Flying..."assert person2 instanceof SupermanPower
Traits exampletrait SpidermanPower { String spiderSense() { "Using spider-sense..." }}
trait SupermanPower { String fly() { "Flying..." }}
![Page 72: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/72.jpg)
class Person implements SpidermanPower {}
def person = new Person()assert person.spiderSense() == "Using spider-sense..."assert person instanceof SpidermanPower
def person2 = person.withTraits SupermanPowerassert person2.fly() == "Flying..."assert person2 instanceof SupermanPower
Traits exampletrait SpidermanPower { String spiderSense() { "Using spider-sense..." }}
trait SupermanPower { String fly() { "Flying..." }}
![Page 73: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/73.jpg)
MOP method synthesis
![Page 74: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/74.jpg)
MOP Method Synthesis
▷ Dynamically figure out behaviour upon invocation
▷ It may not exist until it's called/executed
▷ “Intercept, Cache, Invoke” pattern
![Page 75: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/75.jpg)
def p = new Person(name: 'Iván', age: 34)
assert p.respondsTo('sayHi')assert p.respondsTo('sayHiTo', String)assert !p.respondsTo('goodbye')
assert p.hasProperty('name')assert !p.hasProperty('country')
Check for methods and properties
class Person { String name Integer age
String sayHi() { "Hi, my name is ${name} and I'm ${age}" }
String sayHiTo(String name) { "Hi ${name}, how are you?" }}
![Page 76: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/76.jpg)
def p = new Person(name: 'Iván', age: 35)
assert p.respondsTo('sayHi')assert p.respondsTo('sayHiTo', String)assert !p.respondsTo('goodbye')
assert p.hasProperty('age')assert !p.hasProperty('country')
Check for methods and properties
class Person { String name Integer age
String sayHi() { "Hi, my name is ${name} and I'm ${age}" }
String sayHiTo(String name) { "Hi ${name}, how are you?" }}
![Page 77: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/77.jpg)
Check for methods and properties
class Person { String name Integer age
String sayHi() { "Hi, my name is ${name} and I'm ${age}" }
String sayHiTo(String name) { "Hi ${name}, how are you?" }}
def p = new Person(name: 'Iván', age: 35)
assert p.respondsTo('sayHi')assert p.respondsTo('sayHiTo', String)assert !p.respondsTo('goodbye')
assert p.hasProperty('age')assert !p.hasProperty('country')
![Page 78: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/78.jpg)
Check for methods and properties
class Person { String name Integer age
String sayHi() { "Hi, my name is ${name} and I'm ${age}" }
String sayHiTo(String name) { "Hi ${name}, how are you?" }}
def p = new Person(name: 'Iván', age: 35)
assert p.respondsTo('sayHi')assert p.respondsTo('sayHiTo', String)assert !p.respondsTo('goodbye')
assert p.hasProperty('age')assert !p.hasProperty('country')
![Page 79: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/79.jpg)
MethodMissing example
▷ Requirements:– Send notifications to users by different
channels– +50 notifications– Not all notifications by all channels– Extensible and open to future
modifications
![Page 80: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/80.jpg)
MethodMissing exampleabstract class Channel { void sendNewFollower(String username, String follower) { } void sendNewMessage(String username, String msg) { } ...}
class EmailChannel extends Channel { void sendNewFollower(String username, String follower) { println "Sending email notification to '${username}' for new follower '${follower}'" } void sendNewMessage(String username, String msg) { println "Sending email notification to '${username}' for new message '${msg}'" }}
class MobilePushChannel extends Channel { void sendNewFollower(String username, String follower) { println "Sending mobile push notification to '${username}' for new follower '${follower}'" }}
![Page 81: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/81.jpg)
MethodMissing exampleabstract class Channel { void sendNewFollower(String username, String follower) { } void sendNewMessage(String username, String msg) { } ...}
class EmailChannel extends Channel { void sendNewFollower(String username, String follower) { println "Sending email notification to '${username}' for new follower '${follower}'" } void sendNewMessage(String username, String msg) { println "Sending email notification to '${username}' for new message '${msg}'" }}
class MobilePushChannel extends Channel { void sendNewFollower(String username, String follower) { println "Sending mobile push notification to '${username}' for new follower '${follower}'" }}
![Page 82: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/82.jpg)
MethodMissing exampleabstract class Channel { void sendNewFollower(String username, String follower) { } void sendNewMessage(String username, String msg) { } ...}
class EmailChannel extends Channel { void sendNewFollower(String username, String follower) { println "Sending email notification to '${username}' for new follower '${follower}'" } void sendNewMessage(String username, String msg) { println "Sending email notification to '${username}' for new message '${msg}'" }}
class MobilePushChannel extends Channel { void sendNewFollower(String username, String follower) { println "Sending mobile push notification to '${username}' for new follower '${follower}'" }}
![Page 83: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/83.jpg)
MethodMissing exampleclass NotificationService {
List channels = []
def methodMissing(String name, args) { System.out.println "...methodMissing called for ${name} with args ${args}"
// Generate the implementation def implementation = { Object[] methodArgs -> channels.each { channel -> def metaMethod = channel.metaClass.getMetaMethod(name, methodArgs) return metaMethod.invoke(channel, methodArgs) } } // Cache the implementation in the metaClass NotificationService instance = this instance.metaClass."$name" = implementation
// Execute it! implementation(args) }}
![Page 84: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/84.jpg)
MethodMissing exampleclass NotificationService {
List channels = []
def methodMissing(String name, args) { System.out.println "...methodMissing called for ${name} with args ${args}"
// Generate the implementation def implementation = { Object[] methodArgs -> channels.each { channel -> def metaMethod = channel.metaClass.getMetaMethod(name, methodArgs) return metaMethod.invoke(channel, methodArgs) } } // Cache the implementation in the metaClass NotificationService instance = this instance.metaClass."$name" = implementation
// Execute it! implementation(args) }}
![Page 85: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/85.jpg)
MethodMissing exampleclass NotificationService {
List channels = []
def methodMissing(String name, args) { System.out.println "...methodMissing called for ${name} with args ${args}"
// Generate the implementation def implementation = { Object[] methodArgs -> channels.each { channel -> def metaMethod = channel.metaClass.getMetaMethod(name, methodArgs) return metaMethod.invoke(channel, methodArgs) } } // Cache the implementation in the metaClass NotificationService instance = this instance.metaClass."$name" = implementation
// Execute it! implementation(args) }}
notificationService.sendNewFollower(...)notificationService.sendNewMessage(...)
![Page 86: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/86.jpg)
MethodMissing exampleclass NotificationService {
List channels = []
def methodMissing(String name, args) { System.out.println "...methodMissing called for ${name} with args ${args}"
// Generate the implementation def implementation = { Object[] methodArgs -> channels.each { channel -> def metaMethod = channel.metaClass.getMetaMethod(name, methodArgs) return metaMethod.invoke(channel, methodArgs) } } // Cache the implementation in the metaClass NotificationService instance = this instance.metaClass."$name" = implementation
// Execute it! implementation(args) }}
![Page 87: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/87.jpg)
MethodMissing exampleclass NotificationService {
List channels = []
def methodMissing(String name, args) { System.out.println "...methodMissing called for ${name} with args ${args}"
// Generate the implementation def implementation = { Object[] methodArgs -> channels.each { channel -> def metaMethod = channel.metaClass.getMetaMethod(name, methodArgs) return metaMethod.invoke(channel, methodArgs) } } // Cache the implementation in the metaClass NotificationService instance = this instance.metaClass."$name" = implementation
// Execute it! implementation(args) }}
![Page 88: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/88.jpg)
MethodMissing example
// Execution...methodMissing called for sendNewFollower with args [John, Peter]Sending email notification to 'John' for new follower 'Peter'Sending mobile push notification to 'John' for new follower 'Peter'
Sending email notification to 'Mary' for new follower 'Steve'Sending mobile push notification to 'Mary' for new follower 'Steve'
...methodMissing called for sendNewMessage with args [Iván, Hello!]Sending email notification to 'Iván' for new message 'Hello!'
def notificationService = new NotificationService( channels: [new EmailChannel(), new MobilePushChannel()])
assert !notificationService.respondsTo('sendNewFollower', String, String)notificationService.sendNewFollower("John", "Peter")assert notificationService.respondsTo('sendNewFollower', String, String)
notificationService.sendNewFollower("Mary", "Steve")
notificationService.sendNewMessage("Iván", "Hello!")
![Page 89: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/89.jpg)
MethodMissing example
// Execution...methodMissing called for sendNewFollower with args [John, Peter]Sending email notification to 'John' for new follower 'Peter'Sending mobile push notification to 'John' for new follower 'Peter'
Sending email notification to 'Mary' for new follower 'Steve'Sending mobile push notification to 'Mary' for new follower 'Steve'
...methodMissing called for sendNewMessage with args [Iván, Hello!]Sending email notification to 'Iván' for new message 'Hello!'
def notificationService = new NotificationService( channels: [new EmailChannel(), new MobilePushChannel()])
assert !notificationService.respondsTo('sendNewFollower', String, String)notificationService.sendNewFollower("John", "Peter")assert notificationService.respondsTo('sendNewFollower', String, String)
notificationService.sendNewFollower("Mary", "Steve")
notificationService.sendNewMessage("Iván", "Hello!")
![Page 90: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/90.jpg)
MethodMissing example
// Execution...methodMissing called for sendNewFollower with args [John, Peter]Sending email notification to 'John' for new follower 'Peter'Sending mobile push notification to 'John' for new follower 'Peter'
Sending email notification to 'Mary' for new follower 'Steve'Sending mobile push notification to 'Mary' for new follower 'Steve'
...methodMissing called for sendNewMessage with args [Iván, Hello!]Sending email notification to 'Iván' for new message 'Hello!'
def notificationService = new NotificationService( channels: [new EmailChannel(), new MobilePushChannel()])
assert !notificationService.respondsTo('sendNewFollower', String, String)notificationService.sendNewFollower("John", "Peter")assert notificationService.respondsTo('sendNewFollower', String, String)
notificationService.sendNewFollower("Mary", "Steve")
notificationService.sendNewMessage("Iván", "Hello!")
![Page 91: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/91.jpg)
MethodMissing example
// Execution...methodMissing called for sendNewFollower with args [John, Peter]Sending email notification to 'John' for new follower 'Peter'Sending mobile push notification to 'John' for new follower 'Peter'
Sending email notification to 'Mary' for new follower 'Steve'Sending mobile push notification to 'Mary' for new follower 'Steve'
...methodMissing called for sendNewMessage with args [Iván, Hello!]Sending email notification to 'Iván' for new message 'Hello!'
def notificationService = new NotificationService( channels: [new EmailChannel(), new MobilePushChannel()])
assert !notificationService.respondsTo('sendNewFollower', String, String)notificationService.sendNewFollower("John", "Peter")assert notificationService.respondsTo('sendNewFollower', String, String)
notificationService.sendNewFollower("Mary", "Steve")
notificationService.sendNewMessage("Iván", "Hello!")
![Page 92: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/92.jpg)
MethodMissing example
// Execution...methodMissing called for sendNewFollower with args [John, Peter]Sending email notification to 'John' for new follower 'Peter'Sending mobile push notification to 'John' for new follower 'Peter'
Sending email notification to 'Mary' for new follower 'Steve'Sending mobile push notification to 'Mary' for new follower 'Steve'
...methodMissing called for sendNewMessage with args [Iván, Hello!]Sending email notification to 'Iván' for new message 'Hello!'
def notificationService = new NotificationService( channels: [new EmailChannel(), new MobilePushChannel()])
assert !notificationService.respondsTo('sendNewFollower', String, String)notificationService.sendNewFollower("John", "Peter")assert notificationService.respondsTo('sendNewFollower', String, String)
notificationService.sendNewFollower("Mary", "Steve")
notificationService.sendNewMessage("Iván", "Hello!")class EmailChannel extends Channel { void sendNewFollower(String username, String follower) {…} void sendNewMessage(String username, String msg) {…}}
class MobilePushChannel extends Channel { void sendNewFollower(String username, String follower) {…}}
![Page 93: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/93.jpg)
MethodMissing example
// Execution...methodMissing called for sendNewFollower with args [John, Peter]Sending email notification to 'John' for new follower 'Peter'Sending mobile push notification to 'John' for new follower 'Peter'
Sending email notification to 'Mary' for new follower 'Steve'Sending mobile push notification to 'Mary' for new follower 'Steve'
...methodMissing called for sendNewMessage with args [Iván, Hello!]Sending email notification to 'Iván' for new message 'Hello!'
def notificationService = new NotificationService( channels: [new EmailChannel(), new MobilePushChannel()])
assert !notificationService.respondsTo('sendNewFollower', String, String)notificationService.sendNewFollower("John", "Peter")assert notificationService.respondsTo('sendNewFollower', String, String)
notificationService.sendNewFollower("Mary", "Steve")
notificationService.sendNewMessage("Iván", "Hello!")
![Page 94: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/94.jpg)
MethodMissing example
// Execution...methodMissing called for sendNewFollower with args [John, Peter]Sending email notification to 'John' for new follower 'Peter'Sending mobile push notification to 'John' for new follower 'Peter'
Sending email notification to 'Mary' for new follower 'Steve'Sending mobile push notification to 'Mary' for new follower 'Steve'
...methodMissing called for sendNewMessage with args [Iván, Hello!]Sending email notification to 'Iván' for new message 'Hello!'
def notificationService = new NotificationService( channels: [new EmailChannel(), new MobilePushChannel()])
assert !notificationService.respondsTo('sendNewFollower', String, String)notificationService.sendNewFollower("John", "Peter")assert notificationService.respondsTo('sendNewFollower', String, String)
notificationService.sendNewFollower("Mary", "Steve")
notificationService.sendNewMessage("Iván", "Hello!")
![Page 95: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/95.jpg)
MethodMissing exampledef notificationService = new NotificationService( channels: [new EmailChannel(), new MobilePushChannel()])
assert !notificationService.respondsTo('sendNewFollower', String, String)notificationService.sendNewFollower("John", "Peter")assert notificationService.respondsTo('sendNewFollower', String, String)
notificationService.sendNewFollower("Mary", "Steve")
notificationService.sendNewMessage("Iván", "Hello!")
// Execution...methodMissing called for sendNewFollower with args [John, Peter]Sending email notification to 'John' for new follower 'Peter'Sending mobile push notification to 'John' for new follower 'Peter'
Sending email notification to 'Mary' for new follower 'Steve'Sending mobile push notification to 'Mary' for new follower 'Steve'
...methodMissing called for sendNewMessage with args [Iván, Hello!]Sending email notification to 'Iván' for new message 'Hello!'
![Page 96: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/96.jpg)
2.Compile-time metaprogramming
![Page 97: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/97.jpg)
Compile-time metaprogramming
▷ Advance feature
▷ Analyze/modify program structure at compile time
▷ Cross-cutting features
▷ Write code that generates bytecode
![Page 98: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/98.jpg)
AST and compilation
▷ AST: Abstract Syntax Tree
▷ AST modified during compilation
▷ Hook into the phases
▷ Initialization, Parsing, Conversion, Semantic analysis, Canonicalization, Instruction selection, Class generation, Output, Finalization
![Page 99: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/99.jpg)
Global ASTtransformations
![Page 100: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/100.jpg)
Global AST Transformations
▷ No annotation
▷ Meta-information file
▷ Applied to all code during compilation
▷ Any compilation phase
▷ Grails uses intensively in GORM
![Page 101: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/101.jpg)
Local ASTtransformations
![Page 102: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/102.jpg)
Local AST Transformations
▷ Annotate code
▷ No meta-information file
▷ Easy to debug
![Page 103: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/103.jpg)
Steps to create local AST
Interface AST Enjoy!
![Page 104: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/104.jpg)
Local AST example
package confess2015
import ...
@Retention(RetentionPolicy.SOURCE)@Target([ElementType.TYPE])@GroovyASTTransformationClass("confess2015.VersionASTTransformation")@interface Version { String value()}
class VersionedClass { public static final String VERSION = "1.0"}
import confess2015.Version
@Version('1.0')class VersionedClass {}
![Page 105: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/105.jpg)
Local AST example
class VersionedClass { public static final String VERSION = "1.0"}
package confess2015
import ...
@Retention(RetentionPolicy.SOURCE)@Target([ElementType.TYPE])@GroovyASTTransformationClass("confess2015.VersionASTTransformation")@interface Version { String value()}
import confess2015.Version
@Version('1.0')class VersionedClass {}
![Page 106: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/106.jpg)
Local AST example
class VersionedClass { public static final String VERSION = "1.0"}
package confess2015
import ...
@Retention(RetentionPolicy.SOURCE)@Target([ElementType.TYPE])@GroovyASTTransformationClass("confess2015.VersionASTTransformation")@interface Version { String value()}
import confess2015.Version
@Version('1.0')class VersionedClass {}
![Page 107: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/107.jpg)
Local AST example@GroovyASTTransformation(phase = CompilePhase.SEMANTIC_ANALYSIS)class VersionASTTransformation extends AbstractASTTransformation {
@Override public void visit(final ASTNode[] nodes, final SourceUnit source) { if (nodes.length != 2) { return }
if (nodes[0] instanceof AnnotationNode && nodes[1] instanceof ClassNode) { def annotation = nodes[0] def version = annotation.getMember('value')
if (version instanceof ConstantExpression) { nodes[1].addField('VERSION', ACC_PUBLIC | ACC_STATIC | ACC_FINAL, ClassHelper.STRING_TYPE, version) } else { source.addError(new SyntaxException("Invalid value for annotation", annotation.lineNumber, annotation.columnNumber)) } } }}
![Page 108: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/108.jpg)
Local AST example@GroovyASTTransformation(phase = CompilePhase.SEMANTIC_ANALYSIS)class VersionASTTransformation extends AbstractASTTransformation {
@Override public void visit(final ASTNode[] nodes, final SourceUnit source) { if (nodes.length != 2) { return }
if (nodes[0] instanceof AnnotationNode && nodes[1] instanceof ClassNode) { def annotation = nodes[0] def version = annotation.getMember('value')
if (version instanceof ConstantExpression) { nodes[1].addField('VERSION', ACC_PUBLIC | ACC_STATIC | ACC_FINAL, ClassHelper.STRING_TYPE, version) } else { source.addError(new SyntaxException("Invalid value for annotation", annotation.lineNumber, annotation.columnNumber)) } } }}
![Page 109: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/109.jpg)
Local AST example// Execute with:// gradle build// groovy -cp build/libs/add-version-1.0.jar LocalASTExample.groovy
import confess.Version
@Version('1.0')class VersionedClass {}
println VersionedClass.VERSION
// Execution1.0
![Page 110: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/110.jpg)
Local AST example// Execute with:// gradle build// groovy -cp build/libs/add-version-1.0.jar LocalASTExample.groovy
import confess.Version
@Version('1.0')class VersionedClass {}
println VersionedClass.VERSION
// Execution1.0
![Page 111: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/111.jpg)
Local AST example// Execute with:// gradle build// groovy -cp build/libs/add-version-1.0.jar LocalASTExample.groovy
import confess.Version
@Version('1.0')class VersionedClass {}
println VersionedClass.VERSION
// Execution1.0
![Page 112: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/112.jpg)
3.Why we should usemetaprogramming?
![Page 113: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/113.jpg)
Let’s review some concepts
Metaprogramming out-of-the box
Easy and very powerful
Write better code
Add behaviour easily
Take advantage of this power
Because Groovy, it's groovy
![Page 114: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/114.jpg)
With great powercomes great responsibility
![Page 115: ConFess Vienna 2015 - Metaprogramming with Groovy](https://reader034.vdocuments.site/reader034/viewer/2022042607/55a686a51a28abe7088b46eb/html5/thumbnails/115.jpg)
Thanks!Any questions?
@ilopmar
https://github.com/lmivan
Iván López
http://kcy.me/208wq