Groovy Update: what's new in 1.8 and what's coming in 1.9
The Groovy Development team is releasing Groovy 1.8, and this session will cover the new features including improved support for advanced and readable Domain-Specific Languages thanks to Groovy 1.8's "Extended Command Expressions", new performance improvements in the area of integer arithmetics, built-in support for parsing and producing JSON payloads, new AST transformations and now GPars come already bundled.
Presentation on how to chat with PDF using ChatGPT code interpreter
Groovy update - S2GForum London 2011 - Guillaume Laforge
1. Groovy Update
What’s new in Groovy 1.8,
and what’s cooking in 1.9!
Guillaume Laforge
Groovy Project Manager
SpringSource / VMware
2. Guillaume Laforge
• Groovy Project Manager
• JSR-241 Spec Lead
• Head of Groovy Development
at SpringSource / VMWare
• Initiator of the Grails framework
• Creator of the Gaelyk toolkit
• 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
3. Guillaume Laforge
• Groovy Project Manager
• JSR-241 Spec Lead
• Head of Groovy Development
at SpringSource / VMWare
• Initiator of the Grails framework
• Creator of the Gaelyk toolkit
• 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
17. 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
6
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
6
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
• Less dots, less parens allow you to
– write more readable business rules
– in almost plain English sentences
• (or any language, of course)
6
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)
6
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)
• Let’s have a look at some examples
6
29. Command chains expressions
Before... we used to do...
take 2.pills, of: chloroquinine, after: 6.hours
Normal argument
9
30. Command chains expressions
Before... we used to do...
take 2.pills, of: chloroquinine, after: 6.hours
Normal argument Named arguments
9
31. 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)
9
45. Command chains expressions
// methods with multiple arguments (commas)
take coffee with sugar, milk and liquor
17
46. Command chains expressions
// methods with multiple arguments (commas)
take coffee with sugar, milk and liquor
// leverage named‐args as punctuation
17
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
17
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
17
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 {}
17
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
17
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
17
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
17
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
17
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
17
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
17
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
17
57. 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
17
58. 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
( ).
17
59. Runtime performance improvements
• Significant runtime improvements
for primitive int operations
– classical Fibonacci example x13 faster!
– almost as fast as Java
• Some direct method calls on this
• But there’s more to come!
– in particular for all the primitive types
18
60. GPars bundled
• GPars is bundled in the Groovy distribution
• GPars covers a wide range of parallel and concurrent
paradigms
– actors, fork/join, dataflow, agents, STM...
19
62. 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)
21
63. 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)
21
90. @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()
31
91. @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()
31
92. @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
32
93. 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?
33
94. 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
33
95. 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
33
96. 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
• Also see compilation customizers later on
33
97. @ThreadInterrupt
@ThreadInterrupt
import groovy.transform.ThreadInterrupt
while (true) {
// eat lots of CPU
}
34
98. @ThreadInterrupt
@ThreadInterrupt
import groovy.transform.ThreadInterrupt
while (true) {
{ if (Thread.currentThread.isInterrupted())
throw new InterruptedException() }
// eat lots of CPU
}
34
99. @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)
34
100. @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
– unit: for the time duration unit (TimeUnit.SECONDS)
35
101. @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...'
}
36
102. @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)
37
103. @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()
38
104. @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
39
105. @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
40
106. @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) }
}
41
107. @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) }
}
41
108. @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
}
}
42
109. @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
}
}
42
110. Miscelanous
• Compilation customizers
• Java 7 diamond operator
• Slashy and dollar slashy strings
• New GDK methods
• (G)String to Enum coercion
43
111. Compilation customizers
• Ability to apply some customization to the Groovy
compilation process
• Three available customizers
– ImportCustomizer
– SecureASTCustomizer
– ASTTransformationCustomizer
• But you can implement your own
44
113. 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()
""")
46
114. 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()
47
116. Secure AST customizer
...
// language tokens allowed
tokensWhitelist = [
PLUS, MINUS, MULTIPLY, DIVIDE, MOD, POWER, PLUS_PLUS,
MINUS_MINUS, COMPARE_EQUAL, COMPARE_NOT_EQUAL,
COMPARE_LESS_THAN, COMPARE_LESS_THAN_EQUAL,
COMPARE_GREATER_THAN, COMPARE_GREATER_THAN_EQUAL
]
// types allowed to be used (including primitive types)
constantTypesClassesWhiteList = [
Integer, Float, Long, Double, BigDecimal,
Integer.TYPE, Long.TYPE, Float.TYPE, Double.TYPE
]
// classes who are allowed to be receivers of method calls
receiversClassesWhiteList = [
Math, Integer, Float, Double, Long, BigDecimal ]
}
...
49
117. Secure AST customizer
• Ready to evaluate our arithmetic expressions!
...
def config = new CompilerConfiguration()
config.addCompilationCustomizers(imports, secure)
def shell = new GroovyShell(config)
shell.evaluate 'cos(PI/3)'
• But the following would have failed:
shell.evaluate 'System.exit(0)'
50
118. Slashy and dollar slashy strings
• Slashy strings are now multiline
– particularly handy for multi-line regexs
• Dollar slashy string notation introduced
– a multiline GString with different escaping rules
def (name, date) = ["Guillaume", "May, 17th"]
def dollarSlashy = $/
Hello $name, today we're ${date}
$ dollar‐sign
$$ dollar‐sign
backslash
/ slash
$/ slash
/$
51
138. (G)String to Enum coercion
enum Color {
red, green, blue
}
// coercion with as
def r = "red" as Color
53
139. (G)String to Enum coercion
enum Color {
red, green, blue
}
// coercion with as
def r = "red" as Color
// implicit coercion
Color b = "blue"
53
140. (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
53
142. Groovy 1.9 roadmap
• Java 7 alignements: Project Coin
– binary literals
– underscore in literals
– multicatch
• JDK 7: InvokeDynamic
• Towards a more modular Groovy
• Rewritten Antlr 3 grammar (GSoC)
• Eclipse compiler to replace
the joint compiler?
• What else? Your call!
55
143. Groovy 1.9 roadmap
• Java 7 alignements: Project Coin
– binary literals
– underscore in literals
– multicatch
• JDK 7: InvokeDynamic
• Towards a more modular Groovy
• Rewritten Antlr 3 grammar (GSoC)
• Eclipse compiler to replace
the joint compiler?
• What else? Your call!
55
144. Binary literals
• We had decimal, octal and hexadecimal notations
for number literals
• We can now use binary representations too
int x = 0b10101111
assert x == 175
byte aByte = 0b00100001
assert aByte == 33
int anInt = 0b1010000101000101
assert anInt == 41285
56
145. Underscore in literals
• We can now 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
57
146. Multicatch
• One block for multiple exception caught
– rather than duplicating the block
try {
/* ... */
} catch(IOException | NullPointerException e) {
/* one block to treat 2 exceptions */
}
58