Transcript
Page 1: Metaprogramming With The Groovy Runtime - Part 1 of 2

© 2013 SpringOne 2GX. All rights reserved. Do not distribute without permission.

Metaprogramming With The Groovy Runtime – Part 1 of 2

Jeff Scott Brown@jeffscottbrown

[email protected]

Page 2: Metaprogramming With The Groovy Runtime - Part 1 of 2

Metaprogramming● What Is It?

– behavior changes at runtime

– capabilities are introduced at runtime

– Wikipedia says...

“Metaprogramming is the writing of computer programs that write or manipulate other programs (or themselves)...”

Page 3: Metaprogramming With The Groovy Runtime - Part 1 of 2

Metaprogramming And Groovy● Groovy Lends Itself Well To Metaprogramming

– dynamic method dispatch

– method/property interception

– create methods at runtime

– JVM supports very dynamic behavior

● much cannot be easily tapped by Java the language

Page 4: Metaprogramming With The Groovy Runtime - Part 1 of 2

Expando

● Dynamically Expanding Objectdef myExpando = new Expando()

myExpando.favoriteLanguage = 'Groovy'

myExpando.addNumbers = { i, j -> i + j }

assert 'Groovy' == myExpando.favoriteLanguage

assert 100 == myExpando.addNumbers(60, 40)

assert myExpando.foo == null

Page 5: Metaprogramming With The Groovy Runtime - Part 1 of 2

Runtime Mappings

expando.favoriteLanguage = 'Groovy'// maps to...expando.setProperty('favoriteLanguage', 'Groovy')

expando.favoriteLanguage// maps to...expando.getProperty('favoriteLanguage')

expando.addNumbers(33, 66)// maps to...expando.invokeMethod('addNumbers', [33, 66] as Object[])

Page 6: Metaprogramming With The Groovy Runtime - Part 1 of 2

Our Own Expando

With Those 3 Simple Methods We Can Create Our Own Version Of Expando In 3 Minutes.

Let's Do That Now. Live Demo...

Page 7: Metaprogramming With The Groovy Runtime - Part 1 of 2

Closure Delegates● Closures May Be Assigned A “Delegate”● Closures Relay Method Calls To Their

Delegate● Useful For Creating DSLs And Builders● Same Closure May Be Executed In

Different Contexts With Different Delegates

Page 8: Metaprogramming With The Groovy Runtime - Part 1 of 2

Closure Delegatesdef myClosure = { append('First Line\n') append('Last Line\n')}// will fail because there is no 'append' methodmyClosure()

def buffer = new StringBuffer()def myClosure = { append('First Line\n') append('Last Line\n')}myClosure.delegate = buffer// will append to the StringBuffermyClosure()

Page 9: Metaprogramming With The Groovy Runtime - Part 1 of 2

Closure Delegates

class User {

String login String password String email Date age

static constraints = { login(length:5..15,blank:false,unique:true) password(length:5..15,blank:false) email(email:true,blank:false) age(min:new Date(),nullable:false) }}

Page 10: Metaprogramming With The Groovy Runtime - Part 1 of 2

MarkupBuilder

def mkp = new groovy.xml.MarkupBuilder()mkp.html { head { title('My MarkupBuilder Test') } body { h2('My Favorite Sites') ul { li('groovy.codehaus.org') li('grails.org') li('javajeff.blogspot.com') } }}

Remember that this is executable code. All of those tag names are method calls that are being intercepted by the builder.

Page 11: Metaprogramming With The Groovy Runtime - Part 1 of 2

MarkupBuilder

<html> <head> <title>My MarkupBuilder Test</title> </head> <body> <h2>My Favorite Sites</h2> <ul> <li>groovy.codehaus.org</li> <li>grails.org</li> <li>javajeff.blogspot.com</li> </ul> </body></html>

Page 12: Metaprogramming With The Groovy Runtime - Part 1 of 2

ExpandoMetaClass

String.metaClass.vowels = { delegate.findAll { it.toLowerCase().matches('[aeiou]') }}def message = 'Groovy Is A Great Language'println message.vowels()// ["o", "o", "I", "A", "e", "a", "a", "u", "a", "e"]

Page 13: Metaprogramming With The Groovy Runtime - Part 1 of 2

Thank You For Coming

Q & A