2. Guillaume Laforge
• Groovy Project Manager at VMware
• Initiator of the Grails framework
• Creator of the Gaelyk toolkit
• Co-author of Groovy in Action
• Speaking worldwide w/ a French accent
• Follow me on...
• My blog: http://glaforge.appspot.com
• Twitter: @glaforge
• Google+: http://gplus.to/glaforge
2 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
3. Guillaume Laforge
• Groovy Project Manager at VMware
• Initiator of the Grails framework
• Creator of the Gaelyk toolkit
• Co-author of Groovy in Action
• Speaking worldwide w/ a French accent
• Follow me on...
• My blog: http://glaforge.appspot.com
• Twitter: @glaforge
• Google+: http://gplus.to/glaforge
2 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
18. Command chains expressions
• A grammar improvement allowing you to
drop dots & parens when chaining method calls
– an extended version of top-level statements like println
7 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
19. Command chains expressions
• A grammar improvement allowing you to
drop dots & parens when chaining method calls
– an extended version of top-level statements like println
7 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
20. Command chains expressions
• A grammar improvement allowing you to
drop dots & parens when chaining method calls
– an extended version of top-level statements like println
• Less dots, less parens allow you to
– write more readable business rules
– in almost plain English sentences
• (or any language, of course)
7 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
21. Command chains expressions
• A grammar improvement allowing you to
drop dots & parens when chaining method calls
– an extended version of top-level statements like println
• Less dots, less parens allow you to
– write more readable business rules
– in almost plain English sentences
• (or any language, of course)
7 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
22. Command chains expressions
• A grammar improvement allowing you to
drop dots & parens when chaining method calls
– an extended version of top-level statements like println
• Less dots, less parens allow you to
– write more readable business rules
– in almost plain English sentences
• (or any language, of course)
• Let’s have a look at some examples
7 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
23. Command chains expressions
turn left then right
8 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
24. Command chains expressions
Alternation of
method names
turn left then right
8 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
25. Command chains expressions
Alternation of
method names
turn left then right
and parameters
(even named ones)
8 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
26. Command chains expressions
turn left then right
8 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
27. Command chains expressions
Equivalent to:
( ). ( )
turn left then right
8 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
29. Command chains expressions
Before... we used to do...
take 2.pills, of: chloroquinine, after: 6.hours
10 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
30. Command chains expressions
Before... we used to do...
take 2.pills, of: chloroquinine, after: 6.hours
Normal argument
10 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
31. Command chains expressions
Before... we used to do...
take 2.pills, of: chloroquinine, after: 6.hours
Normal argument Named arguments
10 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
32. Command chains expressions
Before... we used to do...
take 2.pills, of: chloroquinine, after: 6.hours
Normal argument Named arguments
Woud call:
def take(Map m, Quantity q)
10 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
33. Command chains expressions
Now, even less punctuation!
take 2.pills of chloroquinine after 6.hours
11 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
34. Command chains expressions
Now, even less punctuation!
( ). ( ). ( )
take 2.pills of chloroquinine after 6.hours
11 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
35. Command chains expressions
// environment initialization
Integer.metaClass.getPills { ‐> delegate }
Integer.metaClass.getHours { ‐> delegate }
// variable injection
def chloroquinine = /*...*/
{ }
// implementing the DSL logic
def take(n) {
[of: { drug ‐>
[after: { time ‐> /*...*/ }]
}]
}
// ‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐
take 2.pills of chloroquinine after 6.hours
12 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
36. Command chains expressions
take 2.pills of chloroquinine after 6.hours
13 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
37. Command chains expressions
take 2.pills of chloroquinine after 6.hours
... some dots remain ...
13 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
38. Command chains expressions
Yes, we can... get rid of them :-)
take 2 pills of chloroquinine after 6 hours
14 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
39. Command chains expressions
Yes, we can... get rid of them :-)
( ). ( ). ( ). ( )
take 2 pills of chloroquinine after 6 hours
14 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
40. Command chains expressions
// variable injection
def (of, after, hours) = /*...*/
// implementing the DSL logic
{ }
def take(n) {
[pills: { of ‐>
[chloroquinine: { after ‐>
['6': { time ‐> }]
}]
}]
}
// ‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐
take 2 pills of chloroquinine after 6 hours
15 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
43. Command chains expressions
// methods with multiple arguments (commas)
take coffee with sugar, milk and liquor
@glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge 16
44. Command chains expressions
// methods with multiple arguments (commas)
take coffee with sugar, milk and liquor
// leverage named‐args as punctuation
@glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge 16
45. Command chains expressions
// methods with multiple arguments (commas)
take coffee with sugar, milk and liquor
// leverage named‐args as punctuation
check that: margarita tastes good
@glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge 16
46. Command chains expressions
// methods with multiple arguments (commas)
take coffee with sugar, milk and liquor
// leverage named‐args as punctuation
check that: margarita tastes good
// closure parameters for new control structures
@glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge 16
47. Command chains expressions
// methods with multiple arguments (commas)
take coffee with sugar, milk and liquor
// leverage named‐args as punctuation
check that: margarita tastes good
// closure parameters for new control structures
given {} when {} then {}
@glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge 16
48. Command chains expressions
// methods with multiple arguments (commas)
take coffee with sugar, milk and liquor
// leverage named‐args as punctuation
check that: margarita tastes good
// closure parameters for new control structures
given {} when {} then {}
// zero‐arg methods require parens
@glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge 16
49. Command chains expressions
// methods with multiple arguments (commas)
take coffee with sugar, milk and liquor
// leverage named‐args as punctuation
check that: margarita tastes good
// closure parameters for new control structures
given {} when {} then {}
// zero‐arg methods require parens
select all unique() from names
@glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge 16
50. Command chains expressions
// methods with multiple arguments (commas)
take coffee with sugar, milk and liquor
// leverage named‐args as punctuation
check that: margarita tastes good
// closure parameters for new control structures
given {} when {} then {}
// zero‐arg methods require parens
select all unique() from names
// possible with an odd number of terms
@glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge 16
51. Command chains expressions
// methods with multiple arguments (commas)
take coffee with sugar, milk and liquor
// leverage named‐args as punctuation
check that: margarita tastes good
// closure parameters for new control structures
given {} when {} then {}
// zero‐arg methods require parens
select all unique() from names
// possible with an odd number of terms
take 3 cookies
@glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge 16
52. Command chains expressions
// methods with multiple arguments (commas)
take coffee with sugar, milk and liquor
( ). ( ). ( )
// leverage named‐args as punctuation
check that: margarita tastes good
// closure parameters for new control structures
given {} when {} then {}
// zero‐arg methods require parens
select all unique() from names
// possible with an odd number of terms
take 3 cookies
@glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge 16
53. Command chains expressions
// methods with multiple arguments (commas)
take coffee with sugar, milk and liquor
( ). ( ). ( )
// leverage named‐args as punctuation
check that: margarita tastes good
( ). ( )
// closure parameters for new control structures
given {} when {} then {}
// zero‐arg methods require parens
select all unique() from names
// possible with an odd number of terms
take 3 cookies
@glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge 16
54. Command chains expressions
// methods with multiple arguments (commas)
take coffee with sugar, milk and liquor
( ). ( ). ( )
// leverage named‐args as punctuation
check that: margarita tastes good
( ). ( )
// closure parameters for new control structures
given {} when {} then {}
( ). ( ). ( )
// zero‐arg methods require parens
select all unique() from names
// possible with an odd number of terms
take 3 cookies
@glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge 16
55. Command chains expressions
// methods with multiple arguments (commas)
take coffee with sugar, milk and liquor
( ). ( ). ( )
// leverage named‐args as punctuation
check that: margarita tastes good
( ). ( )
// closure parameters for new control structures
given {} when {} then {}
( ). ( ). ( )
// zero‐arg methods require parens
select all unique() from names
( ). . ( )
// possible with an odd number of terms
take 3 cookies
@glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge 16
56. Command chains expressions
// methods with multiple arguments (commas)
take coffee with sugar, milk and liquor
( ). ( ). ( )
// leverage named‐args as punctuation
check that: margarita tastes good
( ). ( )
// closure parameters for new control structures
given {} when {} then {}
( ). ( ). ( )
// zero‐arg methods require parens
select all unique() from names
( ). . ( )
// possible with an odd number of terms
take 3 cookies
( ).
@glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge 16
57. Runtime performance improvements
• Significant runtime improvements
for primitive type operations
– classical Fibonacci example x13 faster!
– almost as fast as Java
• Some direct method calls on this
17 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
58. GPars bundled
• GPars is bundled in the Groovy distribution
• GPars covers a wide range of parallel and concurrent
paradigms
– actors, fork/join, map/filter/reduce, dataflow, agents, STM
– parallel arrays, executors, and more...
• Don’t miss the following presentations on GPars
– Paul King — Thursday, 12:45 - 2:15PM
• Groovy & Concurrency with GPars
– Venkat Subramaniam — Friday, 8:30 - 10:00AM
18 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
60. Closure annotation parameters
@Retention(RetentionPolicy.RUNTIME)
@interface Invariant {
Class value() // a closure class
}
{ @Invariant({ number >= 0 })
class Distance {
float number
String unit
}
def d = new Distance(number: 10, unit: "meters")
def anno = Distance.getAnnotation(Invariant)
def check = anno.value().newInstance(d, d)
assert check(d)
20 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
61. Closure annotation parameters
@Retention(RetentionPolicy.RUNTIME)
@interface Invariant {
Class value() // a closure class
}
{ @Invariant({ number >= 0 })
class Distance {
float number an’s G
Cont racts
String unit P oor-m
}
def d = new Distance(number: 10, unit: "meters")
def anno = Distance.getAnnotation(Invariant)
def check = anno.value().newInstance(d, d)
assert check(d)
20 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
66. Closure memoization
def plus = { a, b ‐> sleep 1000; a + b }.memoize()
23 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
67. Closure memoization
def plus = { a, b ‐> sleep 1000; a + b }.memoize()
assert plus(1, 2) == 3 // after 1000ms
23 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
68. Closure memoization
def plus = { a, b ‐> sleep 1000; a + b }.memoize()
assert plus(1, 2) == 3 // after 1000ms
assert plus(1, 2) == 3 // return immediately
23 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
69. Closure memoization
def plus = { a, b ‐> sleep 1000; a + b }.memoize()
assert plus(1, 2) == 3 // after 1000ms
assert plus(1, 2) == 3 // return immediately
assert plus(2, 2) == 4 // after 1000ms
23 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
70. Closure memoization
def plus = { a, b ‐> sleep 1000; a + b }.memoize()
assert plus(1, 2) == 3 // after 1000ms
assert plus(1, 2) == 3 // return immediately
assert plus(2, 2) == 4 // after 1000ms
assert plus(2, 2) == 4 // return immediately
23 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
71. Closure memoization
def plus = { a, b ‐> sleep 1000; a + b }.memoize()
assert plus(1, 2) == 3 // after 1000ms
assert plus(1, 2) == 3 // return immediately
assert plus(2, 2) == 4 // after 1000ms
assert plus(2, 2) == 4 // return immediately
23 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
72. Closure memoization
def plus = { a, b ‐> sleep 1000; a + b }.memoize()
assert plus(1, 2) == 3 // after 1000ms
assert plus(1, 2) == 3 // return immediately
assert plus(2, 2) == 4 // after 1000ms
assert plus(2, 2) == 4 // return immediately
// at least 10 invocations cached
23 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
73. Closure memoization
def plus = { a, b ‐> sleep 1000; a + b }.memoize()
assert plus(1, 2) == 3 // after 1000ms
assert plus(1, 2) == 3 // return immediately
assert plus(2, 2) == 4 // after 1000ms
assert plus(2, 2) == 4 // return immediately
// at least 10 invocations cached
def plusAtLeast = { ... }.memoizeAtLeast(10)
23 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
74. Closure memoization
def plus = { a, b ‐> sleep 1000; a + b }.memoize()
assert plus(1, 2) == 3 // after 1000ms
assert plus(1, 2) == 3 // return immediately
assert plus(2, 2) == 4 // after 1000ms
assert plus(2, 2) == 4 // return immediately
// at least 10 invocations cached
def plusAtLeast = { ... }.memoizeAtLeast(10)
23 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
75. Closure memoization
def plus = { a, b ‐> sleep 1000; a + b }.memoize()
assert plus(1, 2) == 3 // after 1000ms
assert plus(1, 2) == 3 // return immediately
assert plus(2, 2) == 4 // after 1000ms
assert plus(2, 2) == 4 // return immediately
// at least 10 invocations cached
def plusAtLeast = { ... }.memoizeAtLeast(10)
// at most 10 invocations cached
23 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
76. Closure memoization
def plus = { a, b ‐> sleep 1000; a + b }.memoize()
assert plus(1, 2) == 3 // after 1000ms
assert plus(1, 2) == 3 // return immediately
assert plus(2, 2) == 4 // after 1000ms
assert plus(2, 2) == 4 // return immediately
// at least 10 invocations cached
def plusAtLeast = { ... }.memoizeAtLeast(10)
// at most 10 invocations cached
def plusAtMost = { ... }.memoizeAtMost(10)
23 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
77. Closure memoization
def plus = { a, b ‐> sleep 1000; a + b }.memoize()
assert plus(1, 2) == 3 // after 1000ms
assert plus(1, 2) == 3 // return immediately
assert plus(2, 2) == 4 // after 1000ms
assert plus(2, 2) == 4 // return immediately
// at least 10 invocations cached
def plusAtLeast = { ... }.memoizeAtLeast(10)
// at most 10 invocations cached
def plusAtMost = { ... }.memoizeAtMost(10)
// between 10 and 20 invocations cached
23 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
78. Closure memoization
def plus = { a, b ‐> sleep 1000; a + b }.memoize()
assert plus(1, 2) == 3 // after 1000ms
assert plus(1, 2) == 3 // return immediately
assert plus(2, 2) == 4 // after 1000ms
assert plus(2, 2) == 4 // return immediately
// at least 10 invocations cached
def plusAtLeast = { ... }.memoizeAtLeast(10)
// at most 10 invocations cached
def plusAtMost = { ... }.memoizeAtMost(10)
// between 10 and 20 invocations cached
def plusAtLeast = { ... }.memoizeBetween(10, 20)
23 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
88. @Log
• Four different loggers can be injected
– @Log, @Commons, @Log4j, @Slf4j
• Possible to implement your own strategy
import groovy.util.logging.*
@Log
class Car {
Car() {
log.info 'Car constructed'
}
}
def c = new Car()
30 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
89. @Log
• Four different loggers can be injected
– @Log, @Commons, @Log4j, @Slf4j
• Possible to implement your own strategy
import groovy.util.logging.*
@Log
class Car {
Guarded Car() {
w/ an if log.info 'Car constructed'
}
}
def c = new Car()
30 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
90. @Field
• Surprising scoping rules in scripts
– variables are local to the run() method
– variables aren’t visible in methods
• although visually the variable is in a surrounding scope
• @Field creates a field in the script class
@Field List awe = [1, 2, 3]
def awesum() { awe.sum() }
assert awesum() == 6
31 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
91. Controlling code execution
• Your application may run user’s code
– what if the code runs in infinite loops or for too long?
– what if the code consumes too many resources?
32 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
92. Controlling code execution
• Your application may run user’s code
– what if the code runs in infinite loops or for too long?
– what if the code consumes too many resources?
• 3 new transforms at your rescue
– @ThreadInterrupt: adds Thread#isInterrupted checks so your
executing thread stops when interrupted
– @TimedInterrupt: adds checks in method and closure bodies to
verify it’s run longer than expected
– @ConditionalInterrupt: adds checks with your own conditional
logic to break out from the user code
32 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
93. @ThreadInterrupt
@ThreadInterrupt
import groovy.transform.ThreadInterrupt
while (true) {
// eat lots of CPU
}
33
@glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
94. @ThreadInterrupt
@ThreadInterrupt
import groovy.transform.ThreadInterrupt
while (true) {
{ if (Thread.currentThread.isInterrupted())
throw new InterruptedException() }
// eat lots of CPU
}
33
@glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
95. @ThreadInterrupt
@ThreadInterrupt
import groovy.transform.ThreadInterrupt
while (true) {
{ if (Thread.currentThread.isInterrupted())
throw new InterruptedException() }
// eat lots of CPU
}
• Two optional annotation parameters available
– checkOnMethodStart (true by default)
– applyToAllClasses (true by default)
33
@glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
96. @TimedInterrupt
@TimedInterrupt(10)
import groovy.transform.TimedInterrupt
while (true) {
// eat lots of CPU
}
• InterruptedException thrown when checks indicate code
ran longer than desired
• Optional annotation parameters available
– same as @ThreadInterrupt
– value: for an amount of time duration
34 – unit: for the time duration unit (TimeUnit.SECONDS)
@glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
97. @ConditionalInterrupt
• Specify your own condition to be inserted
at the start of method and closure bodies
– check for available resources, number of times run, etc.
• Leverages closure annotation parameters from Groovy 1.8
@ConditionalInterrupt({ counter++ > 2 })
import groovy.transform.ConditionalInterrupt
import groovy.transform.Field
@Field int counter = 0
100.times {
println 'executing script method...'
}
35 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
98. @ToString
• Provides a default toString() method to your types
• Available annotation options
– includeNames, includeFields, includeSuper, excludes
import groovy.transform.ToString
@ToString
class Person {
String name
int age
}
println new Person(name: 'Pete', age: 15)
// => Person(Pete, 15)
36 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
99. @EqualsAndHashCode
• Provides default implementations for equals() and
hashCode() methods
import groovy.transform.EqualsAndHashCode
@EqualsAndHashCode
class Coord {
int x, y
}
def c1 = new Coord(x: 20, y: 5)
def c2 = new Coord(x: 20, y: 5)
assert c1 == c2
assert c1.hashCode() == c2.hashCode()
37 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
100. @TupleConstructor
• Provides a «classical» constructor with all properties
• Several annotation parameter options available
import groovy.transform.TupleConstructor
@TupleConstructor
class Person {
String name
int age
}
def m = new Person('Marion', 3)
assert m.name == 'Marion'
assert m.age == 3
38 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
101. @Canonical
• One annotation to rule them all!
– @Canonical mixes together
• @ToString
• @EqualsAndHashCode
• @TupleConstructor
• You can customize behavior by combining
@Canonical and one of the other annotations
39 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
102. @InheritConstructor
• Classes like Exception are painful when extended, as all
the base constructors should be replicated
class CustomException extends Exception {
CustomException() { super() }
CustomException(String msg) { super(msg) }
CustomException(String msg, Throwable t) { super(msg, t) }
CustomException(Throwable t) { super(t) }
}
40 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
103. @InheritConstructor
• Classes like Exception are painful when extended, as all
the base constructors should be replicated
import groovy.transform.*
@InheritConstructors
class CustomException extends Exception {
CustomException() { super() }
CustomException(String msg) { super(msg) }
CustomException(String msg, Throwable t) { super(msg, t) }
CustomException(Throwable t) { super(t) }
}
40 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
104. @WithReadLock, @WithWriteLock
import groovy.transform.*
class ResourceProvider {
private final Map<String, String> data = new HashMap<>()
@WithReadLock
String getResource(String key) {
return data.get(key)
}
@WithWriteLock
void refresh() {
//reload the resources into memory
}
}
41 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
105. @WithReadLock, @WithWriteLock
import groovy.transform.*
class ResourceProvider {
private final Map<String, String> data = new HashMap<>()
{ @WithReadLock
String getResource(String key) {
return data.get(key)
}
{ @WithWriteLock
void refresh() {
//reload the resources into memory
}
}
41 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
106. Miscelanous
• Compilation customizers
• Java 7 diamond operator
• Slashy and dollar slashy strings
• New GDK methods
• (G)String to Enum coercion
42 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
107. Compilation customizers
• Ability to apply some customization to the Groovy
compilation process
• Three available customizers
– ImportCustomizer
– SecureASTCustomizer
– ASTTransformationCustomizer
• But you can implement your own
43 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
108. Imports customizer
def configuration = new CompilerConfiguration()
def custo = new ImportCustomizer()
custo.addStaticStar(Math.name)
configuration.addCompilationCustomizers(custo)
def result = new GroovyShell(configuration)
.evaluate(" cos PI/3 ")
44 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
109. Applying an AST transformation
def configuration = new CompilerConfiguration()
configuration.addCompilationCustomizers(
new ASTTransformationCustomizer(Log))
new GroovyShell(configuration).evaluate("""
class Car {
Car() {
log.info 'Car constructed'
}
}
log.info 'Constructing a car'
def c = new Car()
""")
45 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
110. Secure AST customizer
Idea: Implement an «arithmetic shell»
Being able control what a user script is
allowed to do: only arithmetic expressions
• Let’s setup our environment
– some imports
– an import customizer to import java.lang.Math.*
– prepare a secure AST customizer
import org.codehaus.groovy.control.customizers.*
import org.codehaus.groovy.control.*
import static org.codehaus.groovy.syntax.Types.*
def imports = new ImportCustomizer().addStaticStars('java.lang.Math')
def secure = new SecureASTCustomizer()
46 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
133. (G)String to Enum coercion
enum Color {
52 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
134. (G)String to Enum coercion
enum Color {
red, green, blue
52 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
135. (G)String to Enum coercion
enum Color {
red, green, blue
}
52 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
136. (G)String to Enum coercion
enum Color {
red, green, blue
}
52 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
137. (G)String to Enum coercion
enum Color {
red, green, blue
}
// coercion with as
52 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
138. (G)String to Enum coercion
enum Color {
red, green, blue
}
// coercion with as
def r = "red" as Color
52 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
139. (G)String to Enum coercion
enum Color {
red, green, blue
}
// coercion with as
def r = "red" as Color
52 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
140. (G)String to Enum coercion
enum Color {
red, green, blue
}
// coercion with as
def r = "red" as Color
// implicit coercion
52 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
141. (G)String to Enum coercion
enum Color {
red, green, blue
}
// coercion with as
def r = "red" as Color
// implicit coercion
Color b = "blue"
52 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
142. (G)String to Enum coercion
enum Color {
red, green, blue
}
// coercion with as
def r = "red" as Color
// implicit coercion
Color b = "blue"
52 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
143. (G)String to Enum coercion
enum Color {
red, green, blue
}
// coercion with as
def r = "red" as Color
// implicit coercion
Color b = "blue"
// with GStrings too
52 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
144. (G)String to Enum coercion
enum Color {
red, green, blue
}
// coercion with as
def r = "red" as Color
// implicit coercion
Color b = "blue"
// with GStrings too
def g = "${'green'}" as Color
52 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
146. Launching remote scripts
• With the Groovy command, you can launch remote scripts
> groovy http://groovyconsole.appspot.com/raw/110001
• Be careful to what
you’re executing :-)
54 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
151. Binary literals
• We had decimal, octal and hexadecimal notations
for number literals
int x = 0b10101111
assert x == 175
byte aByte = 0b00100001
assert aByte == 33
int anInt = 0b1010000101000101
assert anInt == 41285
58 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
152. Underscore in literals
• Now we can also add underscores
in number literals for more readability
long creditCardNumber = 1234_5678_9012_3456L
long socialSecurityNumbers = 999_99_9999L
float monetaryAmount = 12_345_132.12
long hexBytes = 0xFF_EC_DE_5E
long hexWords = 0xFFEC_DE5E
long maxLong = 0x7fff_ffff_ffff_ffffL
long alsoMaxLong = 9_223_372_036_854_775_807L
long bytes = 0b11010010_01101001_10010100_10010010
59 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
153. Multicatch
• One block for multiple exception caught
– rather than duplicating the block
try {
/* ... */
} catch(IOException | NullPointerException e) {
/* one block to treat 2 exceptions */
}
60 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
154. InvokeDynamic
• Groovy 1.9 will support JDK 7ʼs invokeDynamic
– an «indy» branch started recently
– compiler will have a flag for compiling against JDK 7
• Benefits
– more runtime performance!
– in the long run, will allow us to get rid of code!
• call site caching, thanks to MethodHandles
• metaclass registry, thanks to ClassValues
• will let the JIT inline calls more easily
61 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
155. Groovy Modularity
• Groovy’s «all» JAR weighs in at 4MB
• Nobody needs everything
– Template engine, Ant scripting, Swing UI building...
• Provide a smaller core
– and several smaller JARs per feature
• Paul King covers Groovy modularisation
– Wednesday, 12:45-2:15PM
62 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
156. Static Type Checking
• Goal: make the Groovy compiler «grumpy»!
– and throw compilation errors (not at runtime)
• Not everybody needs dynamic features all the time
– think Java libraries scripting
• Grumpy should...
– tell you about your method or variable typos
– complain if you call methods that don’t exist
– shout on assignments of wrong types
– infer the types of your variables
– figure out GDK methods
63 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
157. A typo in your variable or method names
import groovy.transform.StaticTypes
void method() {}
@TypeChecked test() {
// Cannot find matching method metthhoood()
metthhoood()
def name = "Guillaume"
// variable naamme is undeclared
println naamme
}
64 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
158. A typo in your variable or method names
import groovy.transform.StaticTypes
void method() {}
@TypeChecked test() {
// Cannot find matching method metthhoood()
metthhoood()
def name = "Guillaume"
// variable naamme is undeclared Compilation
println naamme errors!
}
64 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
159. Complain on wrong assignments
// cannot assign value of type... to variable...
int x = new Object()
Set set = new Object()
def o = new Object()
int x = o
String[] strings = ['a','b','c']
int str = strings[0]
// cannot find matching method plus()
int i = 0
i += '1'
65 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
160. Complain on wrong assignments
// cannot assign value of type... to variable...
int x = new Object()
Set set = new Object() Compilation
errors!
def o = new Object()
int x = o
String[] strings = ['a','b','c']
int str = strings[0]
// cannot find matching method plus()
int i = 0
i += '1'
65 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
161. Complain on wrong return types
String method() { 'String' }
// cannot assign value of type String...
int x = method()
// checks if/else branch return values
int method() {
if (true) { 'String' }
else { 42 }
}
// works for switch/case & try/catch/finally
// transparent toString() implied
String greeting(String name) {
def sb = new StringBuilder()
sb << "Hi" << name
}
66 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
162. Complain on wrong return types
String method() { 'String' }
// cannot assign value of type String...
int x = method() Compilation
errors!
// checks if/else branch return values
int method() {
if (true) { 'String' }
else { 42 }
}
// works for switch/case & try/catch/finally
// transparent toString() implied
String greeting(String name) {
def sb = new StringBuilder()
sb << "Hi" << name
}
66 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
163. Type inference
@TypeChecked test() {
def name = " Guillaume "
// String type infered (even inside GString)
println "NAME = ${name.toUpperCase()}"
// Groovy GDK method support
// (GDK operator overloading too)
println name.trim()
int[] numbers = [1, 2, 3]
// Element n is an int
for (int n in numbers) {
println n
}
}
67 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
164. Staticly checked method & dynamic method
@TypeChecked
String greeting(String name) {
// call method with dynamic behavior
// but with proper signature
generateMarkup(name.toUpperCase())
}
// usual dynamic behavior
String generateMarkup(String name) {
def sw = new StringWriter()
new MarkupBuilder(sw).html {
body {
div name
}
}
sw.toString()
}
68 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
165. Bytecode viewer
• Groovy Console’s
bytecode viewer
from the AST
browser window
– select class
generation phase
– select a class node
69 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
166. Disable Global AST transformations
// witout a specific configuration, the AST builder works
def shell = new GroovyShell()
shell.evaluate(script) // passes
def config = new CompilerConfiguration()
config.disabledGlobalASTTransformations =
['org.codehaus.groovy.ast.builder.AstBuilderTransformation']
def script = '''
import org.codehaus.groovy.ast.builder.AstBuilder
new AstBuilder().buildFromCode { "Hello" }
'''
// now with the configuration in place,
// the AST builder transform is not applied
shell = new GroovyShell(config) // <‐‐ with the configuration
shouldFail {
shell.evaluate(script) // fails
}
70 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge
168. Thank you!
e
L aforg pment
aume vy Develo
Guill Groo m
Hea d of g mail.co
aforge@
mail: gl glaforge e
E @ o /glaforg
T witter : http://gplus.t
Go ogle+:
72 @glaforge — http://glaforge.appspot.com — http://gplus.to/glaforge