SlideShare a Scribd company logo
METAPROGRAMMING
OPTIONS WITH GROOVY
METAPROGRAMMING
OPTIONS WITH GROOVY
Iván López @ilopmarIván López @ilopmar@LondonGGUG@LondonGGUG
Hello!
I am Iván López
@ilopmar
http://greachconf.com@madridgug
▷ 1st
rule: You DO talk about the
London-GGUG
▷ 2nd
rule: If it's your first London-
GGUG you HAVE to talk
▷3rd
rule: You have to be awesome
(by David Dawson)
London-GGUG rules
Groovy is dynamic
▷ “Delay” to runtime some decisions
▷ Add properties/behaviours in
runtime
▷ Wide range of applicability
What is
metaprogramming?
“Metaprogramming is the writing
of computer programs that write
or manipulate other programs (or
themselves) as their data.
- Wikipedia
1.
Runtime
metaprogramming
Runtime metaprogramming
▷ Groovy provides this through Meta-
Object Protocol (MOP)
▷ Use MOP to:
– Invoke methods dynamically
– Synthesize classes and methods on
the fly
What is the Meta Object Protocol?
Groovy
Groovy
Java
Java
MOP
MetaClass
▷ MetaClass registry for each class
▷ Collection of methods/properties
▷ We can always modify the metaclass
MOP method
injection
MOP Method Injection
▷ Injecting methods at code-writing time
▷ We can “open” a class any time
▷ Different techniques:
– MetaClass
– Categories
– Extensions
– Mixins vs Traits
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)
// Execution
If you can see Chuck Norris, he can see you. If you can not see Chuck No
If 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
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)
// Execution
If you can see Chuck Norris, he can see you. If you can not see Chuck No
If 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
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)
// Execution
If you can see Chuck Norris, he can see you. If you can not see Chuck No
If 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
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)
// Execution
If you can see Chuck Norris, he can see you. If you can not see Chuck No
If 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
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)
// Execution
If you can see Chuck Norris, he can see you. If you can not see Chuck No
If 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
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)
// Execution
If you can see Chuck Norris, he can see you. If you can not see Chuck No
If 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
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
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
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
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
// Integer
assert '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'
// Boolean
assert false.toBoolean() == false
Boolean.metaClass.toBoolean = { !delegate }
assert false.toBoolean() == true
Overriding methods using MetaClass
// Integer
assert '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'
// Boolean
assert false.toBoolean() == false
Boolean.metaClass.toBoolean = { !delegate }
assert false.toBoolean() == true
Overriding methods using MetaClass
// Integer
assert '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'
// Boolean
assert false.toBoolean() == false
Boolean.metaClass.toBoolean = { !delegate }
assert false.toBoolean() == true
Overriding methods using MetaClass
// Integer
assert '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'
// Boolean
assert false.toBoolean() == false
Boolean.metaClass.toBoolean = { !delegate }
assert false.toBoolean() == true
Overriding methods using MetaClass
// Integer
assert '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'
// Boolean
assert false.toBoolean() == false
Boolean.metaClass.toBoolean = { !delegate }
assert false.toBoolean() == true
Overriding methods using MetaClass
// Integer
assert '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'
// Boolean
assert false.toBoolean() == false
Boolean.metaClass.toBoolean = { !delegate }
assert false.toBoolean() == true
Overriding methods using MetaClass
Categories
▷ MetaClass changes are “persistent”
▷ Change metaclass in confined code
▷ MOP modified only in the closure
Categories example
class 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
}
// Execution
Lorem
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)
Categories example
class 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
}
// Execution
Lorem
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)
Categories example
class 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
}
// Execution
Lorem
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)
Categories example
class 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
}
// Execution
Lorem
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)
Categories example (II)
import groovy.time.TimeCategory
use (TimeCategory) {
println (20.hours + 10.days.from.now)
// Fri Jul 17 20:00:00 CEST 2015
}
println TimeCategory.getHours(20).plus(TimeCategory.getDays(10).from.now)
// Fri Jul 17 20:00:00 CEST 2015
Categories example (II)
import groovy.time.TimeCategory
use (TimeCategory) {
println (20.hours + 10.days.from.now)
// Fri Jul 17 20:00:00 CEST 2015
}
println TimeCategory.getHours(20).plus(TimeCategory.getDays(10).from.now)
// Fri Jul 17 20:00:00 CEST 2015
Extension modules
▷ JAR file that provides extra methods
▷ Meta-information file
▷ Put jar in classpath to enhance classes
// src/main/groovy/londonggug/StringUtilsExtension.groovy
package londonggug
class StringUtilsExtension {
static String truncate(String self, Integer length, Boolean overflow = false) {
self.take(length) + (overflow ? '...' : '')
}
}
// 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.ExtensionModule
moduleName = string-utils-module
moduleVersion = 0.1
extensionClasses = londonggug.StringUtilsExtension
Extension modules example
package londonggug
import spock.lang.Specification
class StringUtilsExtensionSpec extends Specification {
void 'test trucate'() {
expect:
"Lorem" == "Lorem ipsum".truncate(5)
"Lorem..." == "Lorem ipsum".truncate(5, true)
}
}
Extension modules example
// src/main/groovy/londonggug/StringUtilsExtension.groovy
package londonggug
class 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.ExtensionModule
moduleName = string-utils-module
moduleVersion = 0.1
extensionClasses = londonggug.StringUtilsExtension
// Execute with:
// gradle build
// groovy -cp build/libs/string-
extensions-1.0.jar
ExtensionExample1.groovy
assert "Lorem..." == "Lorem ipsum".
truncate(5, true)
package londonggug
import spock.lang.Specification
class StringUtilsExtensionSpec extends Specification {
void 'test trucate'() {
expect:
"Lorem" == "Lorem ipsum".truncate(5)
"Lorem..." == "Lorem ipsum".truncate(5, true)
}
}
Extension modules example
// src/main/groovy/londonggug/StringUtilsExtension.groovy
package londonggug
class StringUtilsExtension {
static String truncate(String self, Integer length, Boolean overflow = false) {
self.take(length) + (overflow ? '...' : '')
}
}
// 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.ExtensionModule
moduleName = string-utils-module
moduleVersion = 0.1
extensionClasses = londonggug.StringUtilsExtension
package londonggug
import spock.lang.Specification
class StringUtilsExtensionSpec extends Specification {
void 'test trucate'() {
expect:
"Lorem" == "Lorem ipsum".truncate(5)
"Lorem..." == "Lorem ipsum".truncate(5, true)
}
}
Extension modules example
// src/main/groovy/londonggug/StringUtilsExtension.groovy
package londonggug
class StringUtilsExtension {
static String truncate(String self, Integer length, Boolean overflow = false) {
self.take(length) + (overflow ? '...' : '')
}
}
// 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.ExtensionModule
moduleName = string-utils-module
moduleVersion = 0.1
extensionClasses = londonggug.StringUtilsExtension
package londonggug
import spock.lang.Specification
class StringUtilsExtensionSpec extends Specification {
void 'test trucate'() {
expect:
"Lorem" == "Lorem ipsum".truncate(5)
"Lorem..." == "Lorem ipsum".truncate(5, true)
}
}
// src/main/groovy/londonggug/StringUtilsExtension.groovy
package londonggug
class StringUtilsExtension {
static String truncate(String self, Integer length, Boolean overflow = false) {
self.take(length) + (overflow ? '...' : '')
}
}
package londonggug
import spock.lang.Specification
class 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.ExtensionModule
moduleName = string-utils-module
moduleVersion = 0.1
extensionClasses = londonggug.StringUtilsExtension
Mixins
▷ “Bring in” or “mix in” implementations
from multiple classes
▷ Calls first routed to mixed-in class
▷ Last mixin wins
▷ Not easily un-done
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 SupermanPower
assert person.fly() == "Flying..."
assert !(person instanceof SupermanPower)
class SupermanPower {
String fly() {
"Flying..."
}
}
@Mixin([SpidermanPower])
class Person {}
def person = new Person()
assert person.spiderSense() == "Using spider-sense..."
assert !(person instanceof SpidermanPower)
Person.mixin SupermanPower
assert person.fly() == "Flying..."
assert !(person instanceof SupermanPower)
class SupermanPower {
String fly() {
"Flying..."
}
}
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 SupermanPower
assert person.fly() == "Flying..."
assert !(person instanceof SupermanPower)
class SupermanPower {
String fly() {
"Flying..."
}
}
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 SupermanPower
assert person.fly() == "Flying..."
assert !(person instanceof SupermanPower)
class SupermanPower {
String fly() {
"Flying..."
}
}
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 SupermanPower
assert person.fly() == "Flying..."
assert !(person instanceof SupermanPower)
class SpidermanPower {
String spiderSense() {
"Using spider-sense..."
}
}
Mixins example
class SupermanPower {
String fly() {
"Flying..."
}
}
@Mixin([SpidermanPower])
class Person {}
def person = new Person()
assert person.spiderSense() == "Using spider-sense..."
assert !(person instanceof SpidermanPower)
Person.mixin SupermanPower
assert person.fly() == "Flying..."
assert !(person instanceof SupermanPower)
class SpidermanPower {
String spiderSense() {
"Using spider-sense..."
}
}
Mixins example
class SupermanPower {
String fly() {
"Flying..."
}
}
“When we started fixing mixin bugs we didn't know
if they were a bug or a feature, so we removed
mixins and add traits.
- Jochen Theodorou
(Greach 2015 Opening Keynote)
Traits
▷ Groovy 2.3+
▷ Similar to Java 8 default methods
▷ Supported in JDK 6, 7 and 8
▷ Stateful
▷ Composition over inheritance
▷ Documentation
class Person implements SpidermanPower {}
def person = new Person()
assert person.spiderSense() == "Using spider-sense..."
assert person instanceof SpidermanPower
def person2 = person.withTraits SupermanPower
assert person2.fly() == "Flying..."
assert person2 instanceof SupermanPower
Traits example
trait SpidermanPower {
String spiderSense() {
"Using spider-sense..."
}
}
trait SupermanPower {
String fly() {
"Flying..."
}
}
class Person implements SpidermanPower {}
def person = new Person()
assert person.spiderSense() == "Using spider-sense..."
assert person instanceof SpidermanPower
def person2 = person.withTraits SupermanPower
assert person2.fly() == "Flying..."
assert person2 instanceof SupermanPower
Traits example
trait SpidermanPower {
String spiderSense() {
"Using spider-sense..."
}
}
trait SupermanPower {
String fly() {
"Flying..."
}
}
class Person implements SpidermanPower {}
def person = new Person()
assert person.spiderSense() == "Using spider-sense..."
assert person instanceof SpidermanPower
def person2 = person.withTraits SupermanPower
assert person2.fly() == "Flying..."
assert person2 instanceof SupermanPower
Traits example
trait SpidermanPower {
String spiderSense() {
"Using spider-sense..."
}
}
trait SupermanPower {
String fly() {
"Flying..."
}
}
class Person implements SpidermanPower {}
def person = new Person()
assert person.spiderSense() == "Using spider-sense..."
assert person instanceof SpidermanPower
def person2 = person.withTraits SupermanPower
assert person2.fly() == "Flying..."
assert person2 instanceof SupermanPower
Traits example
trait SpidermanPower {
String spiderSense() {
"Using spider-sense..."
}
}
trait SupermanPower {
String fly() {
"Flying..."
}
}
MOP method
synthesis
MOP Method Synthesis
▷ Dynamically figure out behaviour upon
invocation
▷ It may not exist until it's called/executed
▷ “Intercept, Cache, Invoke” pattern
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?"
}
}
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?"
}
}
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')
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')
MethodMissing example
▷ Requirements:
– Send notifications to users by different
channels
– +50 notifications
– Not all notifications by all channels
– Extensible and open to future
modifications
MethodMissing example
abstract 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}'"
}
}
MethodMissing example
abstract 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}'"
}
}
MethodMissing example
abstract 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}'"
}
}
MethodMissing example
abstract 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}'"
}
}
MethodMissing example
class 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)
}
}
MethodMissing example
class 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)
}
}
MethodMissing example
class 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(...)
MethodMissing example
class 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)
}
}
MethodMissing example
class 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)
}
}
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!")
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!")
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!")
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!")
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) {…}
}
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!")
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!")
MethodMissing example
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!")
// 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!'
2.
Why we should use
metaprogramming?
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
With great power
comes great
responsibility
Thanks!
Any questions?
@ilopmar
lopez.ivan@gmail.com
https://github.com/lmivan
Iván López

More Related Content

Similar to London-GGUG 2015 - Metaprogramming Options with Groovy

The Ring programming language version 1.7 book - Part 40 of 196
The Ring programming language version 1.7 book - Part 40 of 196The Ring programming language version 1.7 book - Part 40 of 196
The Ring programming language version 1.7 book - Part 40 of 196
Mahmoud Samir Fayed
 
openFrameworks 007 - utils
openFrameworks 007 - utilsopenFrameworks 007 - utils
openFrameworks 007 - utils
roxlu
 
Lec 8 03_sept [compatibility mode]
Lec 8 03_sept [compatibility mode]Lec 8 03_sept [compatibility mode]
Lec 8 03_sept [compatibility mode]Palak Sanghani
 
The Ring programming language version 1.2 book - Part 25 of 84
The Ring programming language version 1.2 book - Part 25 of 84The Ring programming language version 1.2 book - Part 25 of 84
The Ring programming language version 1.2 book - Part 25 of 84
Mahmoud Samir Fayed
 
The Ring programming language version 1.5.3 book - Part 36 of 184
The Ring programming language version 1.5.3 book - Part 36 of 184The Ring programming language version 1.5.3 book - Part 36 of 184
The Ring programming language version 1.5.3 book - Part 36 of 184
Mahmoud Samir Fayed
 
Introduction to Java Strings, By Kavita Ganesan
Introduction to Java Strings, By Kavita GanesanIntroduction to Java Strings, By Kavita Ganesan
Introduction to Java Strings, By Kavita Ganesan
Kavita Ganesan
 
Deep dumpster diving 2010
Deep dumpster diving 2010Deep dumpster diving 2010
Deep dumpster diving 2010RonnBlack
 
Chapter 2
Chapter 2Chapter 2
Rust concurrency tutorial 2015 12-02
Rust concurrency tutorial 2015 12-02Rust concurrency tutorial 2015 12-02
Rust concurrency tutorial 2015 12-02
nikomatsakis
 
2013 DevFest Vienna - Bad Tests, Good Tests
2013 DevFest Vienna - Bad Tests, Good Tests2013 DevFest Vienna - Bad Tests, Good Tests
2013 DevFest Vienna - Bad Tests, Good Tests
Tomek Kaczanowski
 
The Ring programming language version 1.6 book - Part 39 of 189
The Ring programming language version 1.6 book - Part 39 of 189The Ring programming language version 1.6 book - Part 39 of 189
The Ring programming language version 1.6 book - Part 39 of 189
Mahmoud Samir Fayed
 
Java for the Impatient, Java Constructors, Scope, Wrappers, Inheritance, and ...
Java for the Impatient, Java Constructors, Scope, Wrappers, Inheritance, and ...Java for the Impatient, Java Constructors, Scope, Wrappers, Inheritance, and ...
Java for the Impatient, Java Constructors, Scope, Wrappers, Inheritance, and ...
argsstring
 
The Ring programming language version 1.3 book - Part 27 of 88
The Ring programming language version 1.3 book - Part 27 of 88The Ring programming language version 1.3 book - Part 27 of 88
The Ring programming language version 1.3 book - Part 27 of 88
Mahmoud Samir Fayed
 
Core java oop
Core java oopCore java oop
Core java oop
Parth Shah
 

Similar to London-GGUG 2015 - Metaprogramming Options with Groovy (20)

The Ring programming language version 1.7 book - Part 40 of 196
The Ring programming language version 1.7 book - Part 40 of 196The Ring programming language version 1.7 book - Part 40 of 196
The Ring programming language version 1.7 book - Part 40 of 196
 
Reflection
ReflectionReflection
Reflection
 
Reflection
ReflectionReflection
Reflection
 
Reflection
ReflectionReflection
Reflection
 
Reflection
ReflectionReflection
Reflection
 
Reflection
ReflectionReflection
Reflection
 
Reflection
ReflectionReflection
Reflection
 
openFrameworks 007 - utils
openFrameworks 007 - utilsopenFrameworks 007 - utils
openFrameworks 007 - utils
 
Lec 8 03_sept [compatibility mode]
Lec 8 03_sept [compatibility mode]Lec 8 03_sept [compatibility mode]
Lec 8 03_sept [compatibility mode]
 
The Ring programming language version 1.2 book - Part 25 of 84
The Ring programming language version 1.2 book - Part 25 of 84The Ring programming language version 1.2 book - Part 25 of 84
The Ring programming language version 1.2 book - Part 25 of 84
 
The Ring programming language version 1.5.3 book - Part 36 of 184
The Ring programming language version 1.5.3 book - Part 36 of 184The Ring programming language version 1.5.3 book - Part 36 of 184
The Ring programming language version 1.5.3 book - Part 36 of 184
 
Introduction to Java Strings, By Kavita Ganesan
Introduction to Java Strings, By Kavita GanesanIntroduction to Java Strings, By Kavita Ganesan
Introduction to Java Strings, By Kavita Ganesan
 
Deep dumpster diving 2010
Deep dumpster diving 2010Deep dumpster diving 2010
Deep dumpster diving 2010
 
Chapter 2
Chapter 2Chapter 2
Chapter 2
 
Rust concurrency tutorial 2015 12-02
Rust concurrency tutorial 2015 12-02Rust concurrency tutorial 2015 12-02
Rust concurrency tutorial 2015 12-02
 
2013 DevFest Vienna - Bad Tests, Good Tests
2013 DevFest Vienna - Bad Tests, Good Tests2013 DevFest Vienna - Bad Tests, Good Tests
2013 DevFest Vienna - Bad Tests, Good Tests
 
The Ring programming language version 1.6 book - Part 39 of 189
The Ring programming language version 1.6 book - Part 39 of 189The Ring programming language version 1.6 book - Part 39 of 189
The Ring programming language version 1.6 book - Part 39 of 189
 
Java for the Impatient, Java Constructors, Scope, Wrappers, Inheritance, and ...
Java for the Impatient, Java Constructors, Scope, Wrappers, Inheritance, and ...Java for the Impatient, Java Constructors, Scope, Wrappers, Inheritance, and ...
Java for the Impatient, Java Constructors, Scope, Wrappers, Inheritance, and ...
 
The Ring programming language version 1.3 book - Part 27 of 88
The Ring programming language version 1.3 book - Part 27 of 88The Ring programming language version 1.3 book - Part 27 of 88
The Ring programming language version 1.3 book - Part 27 of 88
 
Core java oop
Core java oopCore java oop
Core java oop
 

More from Iván López Martín

SalmorejoTech 2024 - Spring Boot <3 Testcontainers
SalmorejoTech 2024 - Spring Boot <3 TestcontainersSalmorejoTech 2024 - Spring Boot <3 Testcontainers
SalmorejoTech 2024 - Spring Boot <3 Testcontainers
Iván López Martín
 
CommitConf 2024 - Spring Boot <3 Testcontainers
CommitConf 2024 - Spring Boot <3 TestcontainersCommitConf 2024 - Spring Boot <3 Testcontainers
CommitConf 2024 - Spring Boot <3 Testcontainers
Iván López Martín
 
Voxxed Days CERN 2024 - Spring Boot <3 Testcontainers.pdf
Voxxed Days CERN 2024 - Spring Boot <3 Testcontainers.pdfVoxxed Days CERN 2024 - Spring Boot <3 Testcontainers.pdf
Voxxed Days CERN 2024 - Spring Boot <3 Testcontainers.pdf
Iván López Martín
 
VMware - Testcontainers y Spring Boot
VMware - Testcontainers y Spring BootVMware - Testcontainers y Spring Boot
VMware - Testcontainers y Spring Boot
Iván López Martín
 
Spring IO 2023 - Dynamic OpenAPIs with Spring Cloud Gateway
Spring IO 2023 - Dynamic OpenAPIs with Spring Cloud GatewaySpring IO 2023 - Dynamic OpenAPIs with Spring Cloud Gateway
Spring IO 2023 - Dynamic OpenAPIs with Spring Cloud Gateway
Iván López Martín
 
Codemotion Madrid 2023 - Testcontainers y Spring Boot
Codemotion Madrid 2023 - Testcontainers y Spring BootCodemotion Madrid 2023 - Testcontainers y Spring Boot
Codemotion Madrid 2023 - Testcontainers y Spring Boot
Iván López Martín
 
CommitConf 2023 - Spring Framework 6 y Spring Boot 3
CommitConf 2023 - Spring Framework 6 y Spring Boot 3CommitConf 2023 - Spring Framework 6 y Spring Boot 3
CommitConf 2023 - Spring Framework 6 y Spring Boot 3
Iván López Martín
 
Construyendo un API REST con Spring Boot y GraalVM
Construyendo un API REST con Spring Boot y GraalVMConstruyendo un API REST con Spring Boot y GraalVM
Construyendo un API REST con Spring Boot y GraalVM
Iván López Martín
 
jLove 2020 - Micronaut and graalvm: The power of AoT
jLove 2020 - Micronaut and graalvm: The power of AoTjLove 2020 - Micronaut and graalvm: The power of AoT
jLove 2020 - Micronaut and graalvm: The power of AoT
Iván López Martín
 
Codemotion Madrid 2020 - Serverless con Micronaut
Codemotion Madrid 2020 - Serverless con MicronautCodemotion Madrid 2020 - Serverless con Micronaut
Codemotion Madrid 2020 - Serverless con Micronaut
Iván López Martín
 
JConf Perú 2020 - ¡Micronaut en acción!
JConf Perú 2020 - ¡Micronaut en acción!JConf Perú 2020 - ¡Micronaut en acción!
JConf Perú 2020 - ¡Micronaut en acción!
Iván López Martín
 
JConf Perú 2020 - Micronaut + GraalVM = <3
JConf Perú 2020 - Micronaut + GraalVM = <3JConf Perú 2020 - Micronaut + GraalVM = <3
JConf Perú 2020 - Micronaut + GraalVM = <3
Iván López Martín
 
JConf México 2020 - Micronaut + GraalVM = <3
JConf México 2020 - Micronaut + GraalVM = <3JConf México 2020 - Micronaut + GraalVM = <3
JConf México 2020 - Micronaut + GraalVM = <3
Iván López Martín
 
Developing Micronaut Applications With IntelliJ IDEA
Developing Micronaut Applications With IntelliJ IDEADeveloping Micronaut Applications With IntelliJ IDEA
Developing Micronaut Applications With IntelliJ IDEA
Iván López Martín
 
CommitConf 2019 - Micronaut y GraalVm: La combinación perfecta
CommitConf 2019 - Micronaut y GraalVm: La combinación perfectaCommitConf 2019 - Micronaut y GraalVm: La combinación perfecta
CommitConf 2019 - Micronaut y GraalVm: La combinación perfecta
Iván López Martín
 
Codemotion Madrid 2019 - ¡GraalVM y Micronaut: compañeros perfectos!
Codemotion Madrid 2019 - ¡GraalVM y Micronaut: compañeros perfectos!Codemotion Madrid 2019 - ¡GraalVM y Micronaut: compañeros perfectos!
Codemotion Madrid 2019 - ¡GraalVM y Micronaut: compañeros perfectos!
Iván López Martín
 
Greach 2019 - Creating Micronaut Configurations
Greach 2019 - Creating Micronaut ConfigurationsGreach 2019 - Creating Micronaut Configurations
Greach 2019 - Creating Micronaut Configurations
Iván López Martín
 
VoxxedDays Bucharest 2019 - Alexa, nice to meet you
VoxxedDays Bucharest 2019 - Alexa, nice to meet youVoxxedDays Bucharest 2019 - Alexa, nice to meet you
VoxxedDays Bucharest 2019 - Alexa, nice to meet you
Iván López Martín
 
JavaDay Lviv 2019 - Micronaut in action!
JavaDay Lviv 2019 - Micronaut in action!JavaDay Lviv 2019 - Micronaut in action!
JavaDay Lviv 2019 - Micronaut in action!
Iván López Martín
 
CrossDvlup Madrid 2019 - Alexa, encantado de conocerte
CrossDvlup Madrid 2019 - Alexa, encantado de conocerteCrossDvlup Madrid 2019 - Alexa, encantado de conocerte
CrossDvlup Madrid 2019 - Alexa, encantado de conocerte
Iván López Martín
 

More from Iván López Martín (20)

SalmorejoTech 2024 - Spring Boot <3 Testcontainers
SalmorejoTech 2024 - Spring Boot <3 TestcontainersSalmorejoTech 2024 - Spring Boot <3 Testcontainers
SalmorejoTech 2024 - Spring Boot <3 Testcontainers
 
CommitConf 2024 - Spring Boot <3 Testcontainers
CommitConf 2024 - Spring Boot <3 TestcontainersCommitConf 2024 - Spring Boot <3 Testcontainers
CommitConf 2024 - Spring Boot <3 Testcontainers
 
Voxxed Days CERN 2024 - Spring Boot <3 Testcontainers.pdf
Voxxed Days CERN 2024 - Spring Boot <3 Testcontainers.pdfVoxxed Days CERN 2024 - Spring Boot <3 Testcontainers.pdf
Voxxed Days CERN 2024 - Spring Boot <3 Testcontainers.pdf
 
VMware - Testcontainers y Spring Boot
VMware - Testcontainers y Spring BootVMware - Testcontainers y Spring Boot
VMware - Testcontainers y Spring Boot
 
Spring IO 2023 - Dynamic OpenAPIs with Spring Cloud Gateway
Spring IO 2023 - Dynamic OpenAPIs with Spring Cloud GatewaySpring IO 2023 - Dynamic OpenAPIs with Spring Cloud Gateway
Spring IO 2023 - Dynamic OpenAPIs with Spring Cloud Gateway
 
Codemotion Madrid 2023 - Testcontainers y Spring Boot
Codemotion Madrid 2023 - Testcontainers y Spring BootCodemotion Madrid 2023 - Testcontainers y Spring Boot
Codemotion Madrid 2023 - Testcontainers y Spring Boot
 
CommitConf 2023 - Spring Framework 6 y Spring Boot 3
CommitConf 2023 - Spring Framework 6 y Spring Boot 3CommitConf 2023 - Spring Framework 6 y Spring Boot 3
CommitConf 2023 - Spring Framework 6 y Spring Boot 3
 
Construyendo un API REST con Spring Boot y GraalVM
Construyendo un API REST con Spring Boot y GraalVMConstruyendo un API REST con Spring Boot y GraalVM
Construyendo un API REST con Spring Boot y GraalVM
 
jLove 2020 - Micronaut and graalvm: The power of AoT
jLove 2020 - Micronaut and graalvm: The power of AoTjLove 2020 - Micronaut and graalvm: The power of AoT
jLove 2020 - Micronaut and graalvm: The power of AoT
 
Codemotion Madrid 2020 - Serverless con Micronaut
Codemotion Madrid 2020 - Serverless con MicronautCodemotion Madrid 2020 - Serverless con Micronaut
Codemotion Madrid 2020 - Serverless con Micronaut
 
JConf Perú 2020 - ¡Micronaut en acción!
JConf Perú 2020 - ¡Micronaut en acción!JConf Perú 2020 - ¡Micronaut en acción!
JConf Perú 2020 - ¡Micronaut en acción!
 
JConf Perú 2020 - Micronaut + GraalVM = <3
JConf Perú 2020 - Micronaut + GraalVM = <3JConf Perú 2020 - Micronaut + GraalVM = <3
JConf Perú 2020 - Micronaut + GraalVM = <3
 
JConf México 2020 - Micronaut + GraalVM = <3
JConf México 2020 - Micronaut + GraalVM = <3JConf México 2020 - Micronaut + GraalVM = <3
JConf México 2020 - Micronaut + GraalVM = <3
 
Developing Micronaut Applications With IntelliJ IDEA
Developing Micronaut Applications With IntelliJ IDEADeveloping Micronaut Applications With IntelliJ IDEA
Developing Micronaut Applications With IntelliJ IDEA
 
CommitConf 2019 - Micronaut y GraalVm: La combinación perfecta
CommitConf 2019 - Micronaut y GraalVm: La combinación perfectaCommitConf 2019 - Micronaut y GraalVm: La combinación perfecta
CommitConf 2019 - Micronaut y GraalVm: La combinación perfecta
 
Codemotion Madrid 2019 - ¡GraalVM y Micronaut: compañeros perfectos!
Codemotion Madrid 2019 - ¡GraalVM y Micronaut: compañeros perfectos!Codemotion Madrid 2019 - ¡GraalVM y Micronaut: compañeros perfectos!
Codemotion Madrid 2019 - ¡GraalVM y Micronaut: compañeros perfectos!
 
Greach 2019 - Creating Micronaut Configurations
Greach 2019 - Creating Micronaut ConfigurationsGreach 2019 - Creating Micronaut Configurations
Greach 2019 - Creating Micronaut Configurations
 
VoxxedDays Bucharest 2019 - Alexa, nice to meet you
VoxxedDays Bucharest 2019 - Alexa, nice to meet youVoxxedDays Bucharest 2019 - Alexa, nice to meet you
VoxxedDays Bucharest 2019 - Alexa, nice to meet you
 
JavaDay Lviv 2019 - Micronaut in action!
JavaDay Lviv 2019 - Micronaut in action!JavaDay Lviv 2019 - Micronaut in action!
JavaDay Lviv 2019 - Micronaut in action!
 
CrossDvlup Madrid 2019 - Alexa, encantado de conocerte
CrossDvlup Madrid 2019 - Alexa, encantado de conocerteCrossDvlup Madrid 2019 - Alexa, encantado de conocerte
CrossDvlup Madrid 2019 - Alexa, encantado de conocerte
 

Recently uploaded

UiPath Test Automation using UiPath Test Suite series, part 6
UiPath Test Automation using UiPath Test Suite series, part 6UiPath Test Automation using UiPath Test Suite series, part 6
UiPath Test Automation using UiPath Test Suite series, part 6
DianaGray10
 
Alt. GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using ...
Alt. GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using ...Alt. GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using ...
Alt. GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using ...
James Anderson
 
Full-RAG: A modern architecture for hyper-personalization
Full-RAG: A modern architecture for hyper-personalizationFull-RAG: A modern architecture for hyper-personalization
Full-RAG: A modern architecture for hyper-personalization
Zilliz
 
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
James Anderson
 
Generative AI Deep Dive: Advancing from Proof of Concept to Production
Generative AI Deep Dive: Advancing from Proof of Concept to ProductionGenerative AI Deep Dive: Advancing from Proof of Concept to Production
Generative AI Deep Dive: Advancing from Proof of Concept to Production
Aggregage
 
Microsoft - Power Platform_G.Aspiotis.pdf
Microsoft - Power Platform_G.Aspiotis.pdfMicrosoft - Power Platform_G.Aspiotis.pdf
Microsoft - Power Platform_G.Aspiotis.pdf
Uni Systems S.M.S.A.
 
DevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA ConnectDevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA Connect
Kari Kakkonen
 
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdfObservability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Paige Cruz
 
UiPath Test Automation using UiPath Test Suite series, part 5
UiPath Test Automation using UiPath Test Suite series, part 5UiPath Test Automation using UiPath Test Suite series, part 5
UiPath Test Automation using UiPath Test Suite series, part 5
DianaGray10
 
Large Language Model (LLM) and it’s Geospatial Applications
Large Language Model (LLM) and it’s Geospatial ApplicationsLarge Language Model (LLM) and it’s Geospatial Applications
Large Language Model (LLM) and it’s Geospatial Applications
Rohit Gautam
 
GraphSummit Singapore | The Art of the Possible with Graph - Q2 2024
GraphSummit Singapore | The Art of the  Possible with Graph - Q2 2024GraphSummit Singapore | The Art of the  Possible with Graph - Q2 2024
GraphSummit Singapore | The Art of the Possible with Graph - Q2 2024
Neo4j
 
zkStudyClub - Reef: Fast Succinct Non-Interactive Zero-Knowledge Regex Proofs
zkStudyClub - Reef: Fast Succinct Non-Interactive Zero-Knowledge Regex ProofszkStudyClub - Reef: Fast Succinct Non-Interactive Zero-Knowledge Regex Proofs
zkStudyClub - Reef: Fast Succinct Non-Interactive Zero-Knowledge Regex Proofs
Alex Pruden
 
Monitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR EventsMonitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR Events
Ana-Maria Mihalceanu
 
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
DanBrown980551
 
Goodbye Windows 11: Make Way for Nitrux Linux 3.5.0!
Goodbye Windows 11: Make Way for Nitrux Linux 3.5.0!Goodbye Windows 11: Make Way for Nitrux Linux 3.5.0!
Goodbye Windows 11: Make Way for Nitrux Linux 3.5.0!
SOFTTECHHUB
 
A tale of scale & speed: How the US Navy is enabling software delivery from l...
A tale of scale & speed: How the US Navy is enabling software delivery from l...A tale of scale & speed: How the US Navy is enabling software delivery from l...
A tale of scale & speed: How the US Navy is enabling software delivery from l...
sonjaschweigert1
 
Removing Uninteresting Bytes in Software Fuzzing
Removing Uninteresting Bytes in Software FuzzingRemoving Uninteresting Bytes in Software Fuzzing
Removing Uninteresting Bytes in Software Fuzzing
Aftab Hussain
 
RESUME BUILDER APPLICATION Project for students
RESUME BUILDER APPLICATION Project for studentsRESUME BUILDER APPLICATION Project for students
RESUME BUILDER APPLICATION Project for students
KAMESHS29
 
Mind map of terminologies used in context of Generative AI
Mind map of terminologies used in context of Generative AIMind map of terminologies used in context of Generative AI
Mind map of terminologies used in context of Generative AI
Kumud Singh
 
Essentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FMEEssentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FME
Safe Software
 

Recently uploaded (20)

UiPath Test Automation using UiPath Test Suite series, part 6
UiPath Test Automation using UiPath Test Suite series, part 6UiPath Test Automation using UiPath Test Suite series, part 6
UiPath Test Automation using UiPath Test Suite series, part 6
 
Alt. GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using ...
Alt. GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using ...Alt. GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using ...
Alt. GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using ...
 
Full-RAG: A modern architecture for hyper-personalization
Full-RAG: A modern architecture for hyper-personalizationFull-RAG: A modern architecture for hyper-personalization
Full-RAG: A modern architecture for hyper-personalization
 
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
 
Generative AI Deep Dive: Advancing from Proof of Concept to Production
Generative AI Deep Dive: Advancing from Proof of Concept to ProductionGenerative AI Deep Dive: Advancing from Proof of Concept to Production
Generative AI Deep Dive: Advancing from Proof of Concept to Production
 
Microsoft - Power Platform_G.Aspiotis.pdf
Microsoft - Power Platform_G.Aspiotis.pdfMicrosoft - Power Platform_G.Aspiotis.pdf
Microsoft - Power Platform_G.Aspiotis.pdf
 
DevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA ConnectDevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA Connect
 
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdfObservability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
 
UiPath Test Automation using UiPath Test Suite series, part 5
UiPath Test Automation using UiPath Test Suite series, part 5UiPath Test Automation using UiPath Test Suite series, part 5
UiPath Test Automation using UiPath Test Suite series, part 5
 
Large Language Model (LLM) and it’s Geospatial Applications
Large Language Model (LLM) and it’s Geospatial ApplicationsLarge Language Model (LLM) and it’s Geospatial Applications
Large Language Model (LLM) and it’s Geospatial Applications
 
GraphSummit Singapore | The Art of the Possible with Graph - Q2 2024
GraphSummit Singapore | The Art of the  Possible with Graph - Q2 2024GraphSummit Singapore | The Art of the  Possible with Graph - Q2 2024
GraphSummit Singapore | The Art of the Possible with Graph - Q2 2024
 
zkStudyClub - Reef: Fast Succinct Non-Interactive Zero-Knowledge Regex Proofs
zkStudyClub - Reef: Fast Succinct Non-Interactive Zero-Knowledge Regex ProofszkStudyClub - Reef: Fast Succinct Non-Interactive Zero-Knowledge Regex Proofs
zkStudyClub - Reef: Fast Succinct Non-Interactive Zero-Knowledge Regex Proofs
 
Monitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR EventsMonitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR Events
 
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
 
Goodbye Windows 11: Make Way for Nitrux Linux 3.5.0!
Goodbye Windows 11: Make Way for Nitrux Linux 3.5.0!Goodbye Windows 11: Make Way for Nitrux Linux 3.5.0!
Goodbye Windows 11: Make Way for Nitrux Linux 3.5.0!
 
A tale of scale & speed: How the US Navy is enabling software delivery from l...
A tale of scale & speed: How the US Navy is enabling software delivery from l...A tale of scale & speed: How the US Navy is enabling software delivery from l...
A tale of scale & speed: How the US Navy is enabling software delivery from l...
 
Removing Uninteresting Bytes in Software Fuzzing
Removing Uninteresting Bytes in Software FuzzingRemoving Uninteresting Bytes in Software Fuzzing
Removing Uninteresting Bytes in Software Fuzzing
 
RESUME BUILDER APPLICATION Project for students
RESUME BUILDER APPLICATION Project for studentsRESUME BUILDER APPLICATION Project for students
RESUME BUILDER APPLICATION Project for students
 
Mind map of terminologies used in context of Generative AI
Mind map of terminologies used in context of Generative AIMind map of terminologies used in context of Generative AI
Mind map of terminologies used in context of Generative AI
 
Essentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FMEEssentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FME
 

London-GGUG 2015 - Metaprogramming Options with Groovy

  • 1. METAPROGRAMMING OPTIONS WITH GROOVY METAPROGRAMMING OPTIONS WITH GROOVY Iván López @ilopmarIván López @ilopmar@LondonGGUG@LondonGGUG
  • 2. Hello! I am Iván López @ilopmar http://greachconf.com@madridgug
  • 3. ▷ 1st rule: You DO talk about the London-GGUG ▷ 2nd rule: If it's your first London- GGUG you HAVE to talk ▷3rd rule: You have to be awesome (by David Dawson) London-GGUG rules
  • 4. Groovy is dynamic ▷ “Delay” to runtime some decisions ▷ Add properties/behaviours in runtime ▷ Wide range of applicability
  • 6. “Metaprogramming is the writing of computer programs that write or manipulate other programs (or themselves) as their data. - Wikipedia
  • 8. Runtime metaprogramming ▷ Groovy provides this through Meta- Object Protocol (MOP) ▷ Use MOP to: – Invoke methods dynamically – Synthesize classes and methods on the fly
  • 9. What is the Meta Object Protocol? Groovy Groovy Java Java MOP
  • 10. MetaClass ▷ MetaClass registry for each class ▷ Collection of methods/properties ▷ We can always modify the metaclass
  • 12. MOP Method Injection ▷ Injecting methods at code-writing time ▷ We can “open” a class any time ▷ Different techniques: – MetaClass – Categories – Extensions – Mixins vs Traits
  • 13. 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) // Execution If you can see Chuck Norris, he can see you. If you can not see Chuck No If 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
  • 14. 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) // Execution If you can see Chuck Norris, he can see you. If you can not see Chuck No If 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
  • 15. 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) // Execution If you can see Chuck Norris, he can see you. If you can not see Chuck No If 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
  • 16. 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) // Execution If you can see Chuck Norris, he can see you. If you can not see Chuck No If 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
  • 17. 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) // Execution If you can see Chuck Norris, he can see you. If you can not see Chuck No If 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
  • 18. 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) // Execution If you can see Chuck Norris, he can see you. If you can not see Chuck No If 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
  • 19. 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
  • 20. 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
  • 21. 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
  • 22. 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
  • 23. // Integer assert '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' // Boolean assert false.toBoolean() == false Boolean.metaClass.toBoolean = { !delegate } assert false.toBoolean() == true Overriding methods using MetaClass
  • 24. // Integer assert '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' // Boolean assert false.toBoolean() == false Boolean.metaClass.toBoolean = { !delegate } assert false.toBoolean() == true Overriding methods using MetaClass
  • 25. // Integer assert '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' // Boolean assert false.toBoolean() == false Boolean.metaClass.toBoolean = { !delegate } assert false.toBoolean() == true Overriding methods using MetaClass
  • 26. // Integer assert '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' // Boolean assert false.toBoolean() == false Boolean.metaClass.toBoolean = { !delegate } assert false.toBoolean() == true Overriding methods using MetaClass
  • 27. // Integer assert '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' // Boolean assert false.toBoolean() == false Boolean.metaClass.toBoolean = { !delegate } assert false.toBoolean() == true Overriding methods using MetaClass
  • 28. // Integer assert '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' // Boolean assert false.toBoolean() == false Boolean.metaClass.toBoolean = { !delegate } assert false.toBoolean() == true Overriding methods using MetaClass
  • 29. Categories ▷ MetaClass changes are “persistent” ▷ Change metaclass in confined code ▷ MOP modified only in the closure
  • 30. Categories example class 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 } // Execution Lorem 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)
  • 31. Categories example class 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 } // Execution Lorem 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)
  • 32. Categories example class 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 } // Execution Lorem 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)
  • 33. Categories example class 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 } // Execution Lorem 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)
  • 34. Categories example (II) import groovy.time.TimeCategory use (TimeCategory) { println (20.hours + 10.days.from.now) // Fri Jul 17 20:00:00 CEST 2015 } println TimeCategory.getHours(20).plus(TimeCategory.getDays(10).from.now) // Fri Jul 17 20:00:00 CEST 2015
  • 35. Categories example (II) import groovy.time.TimeCategory use (TimeCategory) { println (20.hours + 10.days.from.now) // Fri Jul 17 20:00:00 CEST 2015 } println TimeCategory.getHours(20).plus(TimeCategory.getDays(10).from.now) // Fri Jul 17 20:00:00 CEST 2015
  • 36. Extension modules ▷ JAR file that provides extra methods ▷ Meta-information file ▷ Put jar in classpath to enhance classes
  • 37. // src/main/groovy/londonggug/StringUtilsExtension.groovy package londonggug class StringUtilsExtension { static String truncate(String self, Integer length, Boolean overflow = false) { self.take(length) + (overflow ? '...' : '') } } // 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.ExtensionModule moduleName = string-utils-module moduleVersion = 0.1 extensionClasses = londonggug.StringUtilsExtension Extension modules example package londonggug import spock.lang.Specification class StringUtilsExtensionSpec extends Specification { void 'test trucate'() { expect: "Lorem" == "Lorem ipsum".truncate(5) "Lorem..." == "Lorem ipsum".truncate(5, true) } }
  • 38. Extension modules example // src/main/groovy/londonggug/StringUtilsExtension.groovy package londonggug class 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.ExtensionModule moduleName = string-utils-module moduleVersion = 0.1 extensionClasses = londonggug.StringUtilsExtension // Execute with: // gradle build // groovy -cp build/libs/string- extensions-1.0.jar ExtensionExample1.groovy assert "Lorem..." == "Lorem ipsum". truncate(5, true) package londonggug import spock.lang.Specification class StringUtilsExtensionSpec extends Specification { void 'test trucate'() { expect: "Lorem" == "Lorem ipsum".truncate(5) "Lorem..." == "Lorem ipsum".truncate(5, true) } }
  • 39. Extension modules example // src/main/groovy/londonggug/StringUtilsExtension.groovy package londonggug class StringUtilsExtension { static String truncate(String self, Integer length, Boolean overflow = false) { self.take(length) + (overflow ? '...' : '') } } // 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.ExtensionModule moduleName = string-utils-module moduleVersion = 0.1 extensionClasses = londonggug.StringUtilsExtension package londonggug import spock.lang.Specification class StringUtilsExtensionSpec extends Specification { void 'test trucate'() { expect: "Lorem" == "Lorem ipsum".truncate(5) "Lorem..." == "Lorem ipsum".truncate(5, true) } }
  • 40. Extension modules example // src/main/groovy/londonggug/StringUtilsExtension.groovy package londonggug class StringUtilsExtension { static String truncate(String self, Integer length, Boolean overflow = false) { self.take(length) + (overflow ? '...' : '') } } // 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.ExtensionModule moduleName = string-utils-module moduleVersion = 0.1 extensionClasses = londonggug.StringUtilsExtension package londonggug import spock.lang.Specification class StringUtilsExtensionSpec extends Specification { void 'test trucate'() { expect: "Lorem" == "Lorem ipsum".truncate(5) "Lorem..." == "Lorem ipsum".truncate(5, true) } }
  • 41. // src/main/groovy/londonggug/StringUtilsExtension.groovy package londonggug class StringUtilsExtension { static String truncate(String self, Integer length, Boolean overflow = false) { self.take(length) + (overflow ? '...' : '') } } package londonggug import spock.lang.Specification class 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.ExtensionModule moduleName = string-utils-module moduleVersion = 0.1 extensionClasses = londonggug.StringUtilsExtension
  • 42. Mixins ▷ “Bring in” or “mix in” implementations from multiple classes ▷ Calls first routed to mixed-in class ▷ Last mixin wins ▷ Not easily un-done
  • 43. 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 SupermanPower assert person.fly() == "Flying..." assert !(person instanceof SupermanPower) class SupermanPower { String fly() { "Flying..." } }
  • 44. @Mixin([SpidermanPower]) class Person {} def person = new Person() assert person.spiderSense() == "Using spider-sense..." assert !(person instanceof SpidermanPower) Person.mixin SupermanPower assert person.fly() == "Flying..." assert !(person instanceof SupermanPower) class SupermanPower { String fly() { "Flying..." } } class SpidermanPower { String spiderSense() { "Using spider-sense..." } } Mixins example
  • 45. @Mixin([SpidermanPower]) class Person {} def person = new Person() assert person.spiderSense() == "Using spider-sense..." assert !(person instanceof SpidermanPower) Person.mixin SupermanPower assert person.fly() == "Flying..." assert !(person instanceof SupermanPower) class SupermanPower { String fly() { "Flying..." } } class SpidermanPower { String spiderSense() { "Using spider-sense..." } } Mixins example
  • 46. @Mixin([SpidermanPower]) class Person {} def person = new Person() assert person.spiderSense() == "Using spider-sense..." assert !(person instanceof SpidermanPower) Person.mixin SupermanPower assert person.fly() == "Flying..." assert !(person instanceof SupermanPower) class SupermanPower { String fly() { "Flying..." } } class SpidermanPower { String spiderSense() { "Using spider-sense..." } } Mixins example
  • 47. @Mixin([SpidermanPower]) class Person {} def person = new Person() assert person.spiderSense() == "Using spider-sense..." assert !(person instanceof SpidermanPower) Person.mixin SupermanPower assert person.fly() == "Flying..." assert !(person instanceof SupermanPower) class SpidermanPower { String spiderSense() { "Using spider-sense..." } } Mixins example class SupermanPower { String fly() { "Flying..." } }
  • 48. @Mixin([SpidermanPower]) class Person {} def person = new Person() assert person.spiderSense() == "Using spider-sense..." assert !(person instanceof SpidermanPower) Person.mixin SupermanPower assert person.fly() == "Flying..." assert !(person instanceof SupermanPower) class SpidermanPower { String spiderSense() { "Using spider-sense..." } } Mixins example class SupermanPower { String fly() { "Flying..." } }
  • 49. “When we started fixing mixin bugs we didn't know if they were a bug or a feature, so we removed mixins and add traits. - Jochen Theodorou (Greach 2015 Opening Keynote)
  • 50. Traits ▷ Groovy 2.3+ ▷ Similar to Java 8 default methods ▷ Supported in JDK 6, 7 and 8 ▷ Stateful ▷ Composition over inheritance ▷ Documentation
  • 51. class Person implements SpidermanPower {} def person = new Person() assert person.spiderSense() == "Using spider-sense..." assert person instanceof SpidermanPower def person2 = person.withTraits SupermanPower assert person2.fly() == "Flying..." assert person2 instanceof SupermanPower Traits example trait SpidermanPower { String spiderSense() { "Using spider-sense..." } } trait SupermanPower { String fly() { "Flying..." } }
  • 52. class Person implements SpidermanPower {} def person = new Person() assert person.spiderSense() == "Using spider-sense..." assert person instanceof SpidermanPower def person2 = person.withTraits SupermanPower assert person2.fly() == "Flying..." assert person2 instanceof SupermanPower Traits example trait SpidermanPower { String spiderSense() { "Using spider-sense..." } } trait SupermanPower { String fly() { "Flying..." } }
  • 53. class Person implements SpidermanPower {} def person = new Person() assert person.spiderSense() == "Using spider-sense..." assert person instanceof SpidermanPower def person2 = person.withTraits SupermanPower assert person2.fly() == "Flying..." assert person2 instanceof SupermanPower Traits example trait SpidermanPower { String spiderSense() { "Using spider-sense..." } } trait SupermanPower { String fly() { "Flying..." } }
  • 54. class Person implements SpidermanPower {} def person = new Person() assert person.spiderSense() == "Using spider-sense..." assert person instanceof SpidermanPower def person2 = person.withTraits SupermanPower assert person2.fly() == "Flying..." assert person2 instanceof SupermanPower Traits example trait SpidermanPower { String spiderSense() { "Using spider-sense..." } } trait SupermanPower { String fly() { "Flying..." } }
  • 56. MOP Method Synthesis ▷ Dynamically figure out behaviour upon invocation ▷ It may not exist until it's called/executed ▷ “Intercept, Cache, Invoke” pattern
  • 57. 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?" } }
  • 58. 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?" } }
  • 59. 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')
  • 60. 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')
  • 61. MethodMissing example ▷ Requirements: – Send notifications to users by different channels – +50 notifications – Not all notifications by all channels – Extensible and open to future modifications
  • 62. MethodMissing example abstract 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}'" } }
  • 63. MethodMissing example abstract 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}'" } }
  • 64. MethodMissing example abstract 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}'" } }
  • 65. MethodMissing example abstract 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}'" } }
  • 66. MethodMissing example class 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) } }
  • 67. MethodMissing example class 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) } }
  • 68. MethodMissing example class 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(...)
  • 69. MethodMissing example class 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) } }
  • 70. MethodMissing example class 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) } }
  • 71. 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!")
  • 72. 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!")
  • 73. 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!")
  • 74. 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!")
  • 75. 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) {…} }
  • 76. 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!")
  • 77. 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!")
  • 78. MethodMissing example 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!") // 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!'
  • 79. 2. Why we should use metaprogramming?
  • 80. 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
  • 81. With great power comes great responsibility