2. Guillaume Laforge
• Groovy Project Manager
• JSR-241 Spec Lead
• Head of Groovy Development
at SpringSource / VMWare
• Initiator of the Grails framework
• Co-author of Groovy in Action
• Speaker: JavaOne, QCon, JavaZone, Sun TechDays, Devoxx, The
Spring Experience, SpringOne, JAX, Dynamic Language World, IJTC,
and more...
2
lundi 22 mars 2010
3. Groovy in a few words
! Groovy is a dynamic language for the JVM
• with a Meta Object Protocol
• compiles directly to bytecode
• provides seamless Java interoperability
! Groovy was created in 2003, is hosted at Codehaus, and is under the
Apache license
! Relaxed grammar deriving from Java 5
• annotations, generics, static imports, enums, varargs...
• borrowed good ideas from Ruby, Python, Smalltalk
• flat learning curve for Java developers
3
lundi 22 mars 2010
6. Developer producing LOLCODE
HAI
CAN HAS STDIO?
I HAS A VAR
IM IN YR LOOP
UP VAR!!1
VISIBLE VAR
IZ VAR BIGGER THAN 10? KTHXBYE
IM OUTTA YR LOOP
KTHXBYE
lundi 22 mars 2010
10. DSL: a potential solution?
!Use a more expressive language
than a general purpose one
!Share a common metaphore of understanding
between developers and subject matter experts
!Have domain experts help with the design
of the business logic of an application
!Avoid cluttering business code with
too much boilerplate technical code
!Cleanly separate business logic from application code
!Let business rules have their own lifecycle
10
lundi 22 mars 2010
25. Real-life Groovy examples
! Anti-malaria drug resistance simulation
! Human Resources employee skills representation
! Insurance policies risk calculation engine
! Loan acceptance rules engine for a financial platform
! Mathematica-like lingua for nuclear safety simulations
! Market data feeds evolution scenarios
! and more...
21
lundi 22 mars 2010
26. Three levels of techniques
Flexible & Meta-
malleable syntax programming AST
transformations
• scripts • POGO
• optional typing • categories • AST traversal
• native syntax • builders • local transformations
constructs • custom MetaClass • global transformations
• parens / semi • ExpandoMetaClass • hooks into Antlr
ommission
• named arguments
• BigDecimal
• operator overloading
• closures
22
lundi 22 mars 2010
27. A flexible & malleable syntax
! No need to write full-blown classes, use scripts
! Optional typing (def)
• in scripts, you can even omit the def keyword
! Native syntax constructs
! Parentheses & semi-colons are optional
! Named arguments
! BigDecimal by default for decimal numbers
! Closures for custom control structures
! Operator overloading
23
lundi 22 mars 2010
28. Scripts vs classes
! Hide all the boilerplate technical code
• an end-user doesn’t need to know about classes
public class Rule {
) {
public static void main(String[] args
System.out.println(“Hello”);
}
}
println “Hello”
24
lundi 22 mars 2010
29. Optional typing
! No need to bother with types or even generics
• unless you want to!
! Imagine an interest rate lookup table method returning some
generified type:
Rate <LoanType, Duration, BigDecimal>[]
lookupTable() { ... }
def table = lookupTable()
! No need to repeat the horrible generics type info!
25
lundi 22 mars 2010
30. Native syntax constructs
! Lists
[Monday, Tuesday, Wednesday]
! Maps
[CA: ‘California’, TX: ‘Texas’]
! Ranges
• You can create your own custom ranges
def bizDays = Monday..Friday
def allowedAge = 18..65
26
lundi 22 mars 2010
31. Optional parens & semis
! Make statements and expressions
look more like natural languages
move(left);
move left
27
lundi 22 mars 2010
32. Named arguments
! In Groovy you can mix named and unnamed arguments for method
parameters
• named params are actually put in a map parameter
• plus optional parens & semis
take 1.pill,
of: Chloroquinine,
after: 6.hours
! Corresponds to a method signature like:
def t ake(Map m, MedicineQuantity mq)
28
lundi 22 mars 2010
33. BigDecimal by default
! Main reason why financial institutions often decide to use Groovy for
their business rules!
• Although these days rounding issues are overrated!
! Java vs Groovy for a simple interpolation equation
BigDecimal uMinusv = c.subtract(a);
BigDecimal vMinusl = b.subtract(c);
BigDecimal uMinusl = a.subtract(b);
return e.multiply(uMinusv)
.add(d.multiply(vMinusl))
_HALF_UP);
.divide(uMinusl, 10, BigDecimal.ROUND
(d * (b - c) + e * (c - a)) / (a - b)
29
lundi 22 mars 2010
34. Custom control structures,
thanks to closures
! When closures are last, they can be put “out” of the parentheses
surrounding parameters
unless (a ccount.balance > 100.euros,
{ account.debit 100.euros })
unless (a ccount.balance > 100.euros) {
account.debit 100.euros
}
! Signature
de f unless(boolean b, Closure c)
30
lundi 22 mars 2010
35. Operator overloading
a + b a.plus(b)
• Currency amounts
a - b a.minus(b) 15.euros + 10.dollars
a * b a.multiply(b)
a / b a.divide(b) • Distance handling
a % b a.modulo(b)
a ** b a.power(b) 10.kilometers - 10.meters
a | b a.or(b)
a & b a.and(b)
• Workflow, concurrency
a ^ b a.xor(b) taskA | taskB & taskC
a[b] a.getAt(b)
a << b a.leftShift(b) • Credit an account
a >> b a.rightShift(b)
+a a.unaryPlus() account << 10.dollars
-a a.unaryMinus() account += 10.dollars
~a a.bitwiseNegate()
account.credit 10.dollars
31
lundi 22 mars 2010
36. The MOP
(Meta-Object Protocol)
lundi 22 mars 2010
37. Groovy’s MOP
! All the accesses to methods, properties, constructors, operators, etc.
can be intercepted thanks to the MOP
! While Java’s behavior is hard-wired at compile-time in the class
! Groovy’s runtime behavior is adaptable at runtime through the
metaclass
! Different hooks for changing the runtime behavior
• GroovyObject, custom MetaClass implementation, categories, ExpandoMetaClass
33
lundi 22 mars 2010
38. GroovyObject
! All instances of classes created in Groovy implement the
GroovyObject interface:
get/setProperty(String name)
invokeMeth od(String name, Object[] params)
propertyMissing(String name)
methodMissing( String name, Object[] params)
get/setMetaClass(MetaClass mc)
! A GO can have “pretended” methods and properties
34
lundi 22 mars 2010
39. MetaClass
! The core of Groovy’s MOP system
invokeConstructor()
invokeMe thod() and invokeStaticMethod()
invokeMissingMethod()
getProperty() and setProperty()
ge tAttribute() and setAttribute()
respondsTo() and hasProperty()
! MetaClasses can change the behavior of existing third-party classes
— even from the JDK
35
lundi 22 mars 2010
40. ExpandoMetaClass
! A DSL for MetaClasses!
MoneyAmount.meta Class.constructor = { ... }
Numb er.metaClass.getDollars = { ... }
Di stance.metaClass.toMeters = { ... }
Distance .metaClass.static.create = { ... }
! To avoid repetition of Type.metaClass, you can pass a closure to
metaClass { ... }
! The delegate variable in closure represents the current instance,
and it the default parameter
36
lundi 22 mars 2010
42. A builder for HR
softskills {
ideas {
capture 2
formulate 3
}
...
}
knowhow {
languages {
java 4
groovy 5
}
...
}
38
lundi 22 mars 2010
43. A builder for HR
softskills {
ideas {
capture 2
formulate 3
}
...
}
knowhow {
languages {
java 4
groovy 5
}
...
}
38
lundi 22 mars 2010
44. Builders
! Builders are...
• a mechanism for creating any tree-structered graph
• the realization of the GoF builder pattern at the syntax level in Groovy
• simply a clever use of chained method invocation, closures, parentheses omission, and use
of the GroovyObject methods
! Existing builders
• XML, Object graph, Swing, Ant, JMX, and more...
39
lundi 22 mars 2010
45. The clever trick
! GroovyObject#invokeMethod() is used to catch all non-existing
method calls in the context of the builder
! The nesting of closures visually shows the level of nesting / depth in
the tree
! builder.m1(attr1:1, attr2:2, { builder.m2(..., {...}) }
becomes equivalent to
builder.m1(attr1:1, attr2:2) { m2(...) {...} }
thanks to parens omission
40
lundi 22 mars 2010
46. Adding properties to numbers
! Three possible approaches
• create a Category
• a category is a kind of decorator for default MCs
• create a custom MetaClass
• a full-blown MC class to implement and to set on the POGO instance
• use ExpandoMetaClass
• friendlier DSL approach but with a catch
41
lundi 22 mars 2010
47. With a Category
class DistanceCategory {
static Di stance getMeters(Integer self) {
new Distance(self, Unit.METERS)
}
}
use(DistanceCategory) {
100.meters
}
! Interesting scope: thread-bound & lexical
! Have to surround with “use”
• but there are ways to hide it
42
lundi 22 mars 2010
48. With an ExpandoMetaClass
Number.metaClass.getMeters = {->
new Distance(delegate, Unit.METERS)
}
100.meters
! Works for the class hierarchy for POJOs, and a flag exists to make it
work for POGOs too
! But the catch is it’s really a global change, so beware EMC
enhancements collisions
43
lundi 22 mars 2010
50. Compile-time metaprogramming
! With metaprogramming, Groovy’s able to modify the behaviour of
programs... at runtime
! Groovy 1.6 introduced AST Transformations
• AST: Abstract Syntax Tree
• Ability to change what’s being compiled at compile-time!
• No runtime impact!
• Lets you change the semantics of your programs!
• Nice way of implementing patterns and removing boiler-plate technical code
! Two kinds of transformations: global and local
45
lundi 22 mars 2010
51. AST Transformations
! Two kinds of transformations
• Global transformations
• applicable to all compilation units
• Local transformations
• applicable to marked program elements
• using specific marker annotations
46
lundi 22 mars 2010
52. AST Transformations
in Groovy 1.6
! Several (local) transformations finds their way
• @Singleton — okay, not really a pattern :-)
• @Immutable, @Lazy, @Delegate
•@Newify
• @Category and @Mixin
•@PackageScope
• Swing’s @Bindable and @Vetoable
• Grape’s @Grab
! Let’s have a look at some of them
47
lundi 22 mars 2010
53. The @Singleton anti-pattern
!The evil Java singleton
public class Evil { ;
public st atic final Evil instance = new Evil()
privavte Evil() {}
; }
Evil getInstance() { return instance
}
!In Groovy now:
@Singleton class Evil {}
!A lazy version also:
@Singleton(lazy = true) class Evil {}
48
lundi 22 mars 2010
54. @Immutable
! To properly implement immutable classes
• No mutators (state musn’t change)
• Private final fields
• Defensive copying of mutable components
• Proper equals() / hashCode() / toString() for comparisons, or for keys in maps,
etc.
@Immutable class Coordinates {
Double lat, lng
}
def c1 = new Coordinates(lat: 48.8, lng: 2.5)
def c2 = new Coordinates(48.8, 2.5)
assert c1 == c2
49
lundi 22 mars 2010
55. @Lazy, not just for lazy dudes!
! When you need to lazily evaluate or instantiate complex data
structures for class fields, mark them with the @Lazy annotation
class Dude {
@Lazy pets = retrieveFromSlowDB()
}
! Groovy will handle the boiler-plate code for you!
50
lundi 22 mars 2010
56. @Delegate
Not just for managers!
!You can delegate to fields of your class
•Think multiple inheritance
class Employee {
def doTheWork() { "done" }
}
class Manager {
ee()
@Delegate Employee slave = new Employ
}
def god = new Manager()
assert god.doTheWork() == "done"
!Damn manager will get all the praise...
51
lundi 22 mars 2010
57. Global transformations
! Implement ASTTransformation
! Annotate the transfo specifying a compilation phase
ERSION)
@GroovyASTTr ansformation(phase=CompilePhase.CONV
public class MyTransformation
implements ASTTransformation {
Unit unit)
publ ic void visit(ASTNode[] nodes, Source
{ ... }
}
! For discovery, create the file META-INF/services/
org.codehaus.groovy.transform.ASTTransformation
! Add the fully qualified name of the class in that file
52
lundi 22 mars 2010
58. Local transformations
! Same approach as Globale transformations
! But you don’t need the META-INF file
! Instead create an annotation to specify on which element the
transformation should apply
@Ret ention(RetentionPolicy.SOURCE)
@Target([ElementType.METHOD])
@GroovyASTTransformationClass(
["fqn.MyTransformation"])
publ ic @interface WithLogging {...}
53
lundi 22 mars 2010
59. Example: the Spock framework
! Changing the semantics of the original code
! But keeping a valid Groovy syntax
@Speck
class HelloSpock {
() {
def "can you figure out what I'm up to?"
expect:
name.size() == size
where:
name << ["Kirk", "Spock", "Scotty"]
size << [4, 5, 6]
}
}
! Check out http://www.spockframework.org
54
lundi 22 mars 2010
60. Various integration mechanisms
! Java 6’s javax.script.* APIs (aka JSR-223)
! Spring’s language namespace
! Groovy’s own mechanisms
! But a key idea is to externalize those DSL programs
• DSL programs can have their own lifecycle
• no need to redeploy an application because of a rule change
• business people won’t see the technical code
55
lundi 22 mars 2010
61. Java 6’s javax.script.* API
! Groovy 1.6 provides its own implementation of the javax.script.* API
ScriptEngineManager mgr =
new ScriptEngineManager();
ScriptEngine engine =
mgr.getEngineByName(“Groovy”);
String result =
(String)engine.eval(“2+3”);
56
lundi 22 mars 2010
62. Spring’s lang namespace
! POGOs (Plain Old Groovy Objects) can be pre-compiled as any
POJO and used interchangeably with POJOs in a Spring application
! But Groovy scripts & classes can be loaded at runtime through the
<lang:groovy/> namespace and tag
! Reloadable on change
! Customizable through a custom MetaClass
<lang:groovy id="events" ovy"
script-s ource="classpath:dsl/eventsChart.gro
customizer-ref="eventsMetaClass" />
57
lundi 22 mars 2010
63. Groovy’s own mechanisms
! Eval
• for evaluating simple expressions
! GroovyShell
• for more complex scripts and DSLs
! GroovyClassLoader
• the most powerful mechanism
58
lundi 22 mars 2010
65. GroovyShell
! A Binding provides a context of execution
• can implement lazy evaluation if needed
! A base script class can be specified
def binding = new Binding()
binding.mass = 22.3
binding.velocity = 10.6
def shell = new GroovyShell(binding)
shell. evaluate(“mass * velocity ** 2 / 2”)
60
lundi 22 mars 2010
66. GroovyClassLoader
! Most powerful mechanism
• could also visit or change the AST
• scripts & classes can be loaded from elsewhere
• more control on compilation
GroovyClassLoader gcl =
new GroovyClassLoader();
Class clazz = gcl.parseClass(
new File(“f.groovy”));
GroovyObject instance =
(GroovyObject)clazz.newInstance();
instance.setMetaClass(customMC);
61
lundi 22 mars 2010
67. Externalize business rules
! Although Groovy DSLs can be embedded in normal Groovy classes,
you should externalize them
! Store them elsewhere
• in a database, an XML file, etc.
! Benefits
• Business rules are not entangled
in technical application code
• Business rules can have their own lifecycle, without requiring application
redeployments
62
lundi 22 mars 2010
76. Various levels
of sandboxing
! Groovy supports the usual
Java Security Managers
! Use metaprogramming tricks to prevent calling / instanciating certain
classes
! Create a special GroovyClassLoader AST code visitor to filter only the
nodes of the AST you want to keep
• ArithmeticShell in Groovy’s samples
71
lundi 22 mars 2010
77. Test, test, test!
! Don’t just test for nominal cases
• Explicitely test for errors!
! Ensure end-users get meaninful error messages
72
lundi 22 mars 2010