groovy in 2014 and beyond
DESCRIPTION
With 3 million downloads in a year, Groovy still clearly leads the pack of alternative languages on the JVM, but it's not resting on its laurels. The latest Groovy 2.3 release is pack full of useful new features and performance improvements. In particular, Groovy now supports the concept of "traits" for elegantly composing behaviors. Its JSON support is now the most performant among all the JSON libraries available to date. Groovy 2.3 introduces a new markup-based template engine, new code transformations, and much more.TRANSCRIPT
© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission.
Groovy, in 2014 and beyondGuillaume Laforge — Groovy project lead / Pivotal
@glaforge
Stay up-to-date
Groovy Weekly Newsletter (Every Tuesday) http://beta.groovy-lang.org/groovy-weekly.html
2
© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission.
Agenda
The Groovy roadmap
6
2015 20142013
Groovy 2.3
Groovy 2.4Groovy 2.2
Groovy 2.5 ?
Groovy 3.0 ?
Groovy 2.3
• JDK 8 runtime support • Traits • New and updates AST transformations • NIO2 module • JSON improvements & performance gains • New Markup template engine • Documentation overhaul
7
Groovy 2.4
• Android support !
• New website !
• Potentially • Macro system? • New grammar?
8
Groovy 3.0
• New Meta-Object Protocol !
• Invoke-dynamic based runtime !
• Rewritten language grammar with Antlr v4 • unless re-scheduled for Groovy 2.4 • successful GSoC, but not fully complete coverage
9
© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission.
Groovy 2.3
© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission.
JDK 8 support
JDK 8 support — closures vs lambdas
12
IntStream.range(1, 100).forEach(s -‐> System.out.println(s)); !Files.lines(Paths.get('README.adoc')) .map(it -‐> it.toUpperCase()) .forEach(it -‐> System.out.println(it));
JDK 8 support — closures vs lambdas
12
IntStream.range(1, 100).forEach(s -‐> System.out.println(s)); !Files.lines(Paths.get('README.adoc')) .map(it -‐> it.toUpperCase()) .forEach(it -‐> System.out.println(it));
IntStream.range(1, 100).forEach { println it } !Files.lines(Paths.get('README.adoc')) .map { it.toUpperCase() } .forEach { println it }
JDK 8 support — closures vs lambdas
12
IntStream.range(1, 100).forEach(s -‐> System.out.println(s)); !Files.lines(Paths.get('README.adoc')) .map(it -‐> it.toUpperCase()) .forEach(it -‐> System.out.println(it));
IntStream.range(1, 100).forEach { println it } !Files.lines(Paths.get('README.adoc')) .map { it.toUpperCase() } .forEach { println it }
Use Groovy closureswherever you passlambdas in Java 8
To know all about AST transformations!
13
Groovy in the light of Java 8 by Guillaume Laforge Tue 12:45pm / F. Park 1
© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission.
Traits
Traits
• Like interfaces, but with method bodies • similar to Java 8 interface default methods
• Elegant way to compose behavior • multiple inheritance without the « diamond » problem
• Traits can also be stateful • traits can have properties like normal classes
• Compatible with static typing and static compilation • class methods from traits also visible from Java classes
• Also possible to implement traits at runtime 15
Traits: a simple example
16
trait FlyingAbility { String fly() { "I'm flying!" } } !
class Bird implements FlyingAbility {} def b = new Bird() !
assert b.fly() == "I'm flying!"
Traits: a simple example
16
trait FlyingAbility { String fly() { "I'm flying!" } } !
class Bird implements FlyingAbility {} def b = new Bird() !
assert b.fly() == "I'm flying!"
« trait », a new keyword for a new concept
Traits: a simple example
16
trait FlyingAbility { String fly() { "I'm flying!" } } !
class Bird implements FlyingAbility {} def b = new Bird() !
assert b.fly() == "I'm flying!"
a class « implements »
a trait
Traits: a simple example
16
trait FlyingAbility { String fly() { "I'm flying!" } } !
class Bird implements FlyingAbility {} def b = new Bird() !
assert b.fly() == "I'm flying!"
the fly() method from the trait is available
Traits: a simple example
16
trait FlyingAbility { String fly() { "I'm flying!" } } !
class Bird implements FlyingAbility {} def b = new Bird() !
assert b.fly() == "I'm flying!"
Traits: stateful
17
trait Named { String name } !
class Bird implements Named {} def b = new Bird(name: 'Colibri') !
assert b.name == 'Colibri'
Traits: stateful
17
trait Named { String name } !
class Bird implements Named {} def b = new Bird(name: 'Colibri') !
assert b.name == 'Colibri'
a Groovy property
Traits: stateful
17
trait Named { String name } !
class Bird implements Named {} def b = new Bird(name: 'Colibri') !
assert b.name == 'Colibri'
implement the trait
Traits: stateful
17
trait Named { String name } !
class Bird implements Named {} def b = new Bird(name: 'Colibri') !
assert b.name == 'Colibri'
Groovy named argument constructor
Traits: stateful
17
trait Named { String name } !
class Bird implements Named {} def b = new Bird(name: 'Colibri') !
assert b.name == 'Colibri'
access the property
Traits: stateful
17
trait Named { String name } !
class Bird implements Named {} def b = new Bird(name: 'Colibri') !
assert b.name == 'Colibri'
Traits: inheritance
18
trait Named { String name } !
trait FlyingAbility extends Named { String fly() { "I'm a flying ${name}!" } } !
class Bird implements FlyingAbility {} def b = new Bird(name: 'Colibri') !
assert b.name == 'Colibri' assert b.fly() == "I'm a flying Colibri!"
Traits: inheritance
18
trait Named { String name } !
trait FlyingAbility extends Named { String fly() { "I'm a flying ${name}!" } } !
class Bird implements FlyingAbility {} def b = new Bird(name: 'Colibri') !
assert b.name == 'Colibri' assert b.fly() == "I'm a flying Colibri!"
extend the Named trait
Traits: inheritance
18
trait Named { String name } !
trait FlyingAbility extends Named { String fly() { "I'm a flying ${name}!" } } !
class Bird implements FlyingAbility {} def b = new Bird(name: 'Colibri') !
assert b.name == 'Colibri' assert b.fly() == "I'm a flying Colibri!"
access the name property
Traits: inheritance
18
trait Named { String name } !
trait FlyingAbility extends Named { String fly() { "I'm a flying ${name}!" } } !
class Bird implements FlyingAbility {} def b = new Bird(name: 'Colibri') !
assert b.name == 'Colibri' assert b.fly() == "I'm a flying Colibri!"
implement the composite trait
Traits: inheritance
18
trait Named { String name } !
trait FlyingAbility extends Named { String fly() { "I'm a flying ${name}!" } } !
class Bird implements FlyingAbility {} def b = new Bird(name: 'Colibri') !
assert b.name == 'Colibri' assert b.fly() == "I'm a flying Colibri!"
Traits: multiple inheritance & dynamic access
19
trait FlyingAbility { String fly() { "I'm a flying $name!" } } !
trait Named { String name } !
class Bird implements Named, FlyingAbility {} def b = new Bird(name: 'Colibri') !
assert b.name == 'Colibri' assert b.fly() == "I'm a flying Colibri!"
Traits: multiple inheritance & dynamic access
19
trait FlyingAbility { String fly() { "I'm a flying $name!" } } !
trait Named { String name } !
class Bird implements Named, FlyingAbility {} def b = new Bird(name: 'Colibri') !
assert b.name == 'Colibri' assert b.fly() == "I'm a flying Colibri!"
access a dynamic property
Traits: multiple inheritance & dynamic access
19
trait FlyingAbility { String fly() { "I'm a flying $name!" } } !
trait Named { String name } !
class Bird implements Named, FlyingAbility {} def b = new Bird(name: 'Colibri') !
assert b.name == 'Colibri' assert b.fly() == "I'm a flying Colibri!"
implements two traits!
Traits: multiple inheritance & dynamic access
19
trait FlyingAbility { String fly() { "I'm a flying $name!" } } !
trait Named { String name } !
class Bird implements Named, FlyingAbility {} def b = new Bird(name: 'Colibri') !
assert b.name == 'Colibri' assert b.fly() == "I'm a flying Colibri!"
dynamic ‘name’ property interpolated
Traits: multiple inheritance & dynamic access
19
trait FlyingAbility { String fly() { "I'm a flying $name!" } } !
trait Named { String name } !
class Bird implements Named, FlyingAbility {} def b = new Bird(name: 'Colibri') !
assert b.name == 'Colibri' assert b.fly() == "I'm a flying Colibri!"
Traits: what about conflicts?
20
trait KiteSurfer { String surf() { 'kite' } } !trait WebSurfer { String surf() { 'web' } } !class Person { String name } !class Hipster extends Person implements KiteSurfer, WebSurfer {} !def h = new Hipster() assert h.surf() == 'web'
Traits: what about conflicts?
20
trait KiteSurfer { String surf() { 'kite' } } !trait WebSurfer { String surf() { 'web' } } !class Person { String name } !class Hipster extends Person implements KiteSurfer, WebSurfer {} !def h = new Hipster() assert h.surf() == 'web'
two surf() methods
Traits: what about conflicts?
20
trait KiteSurfer { String surf() { 'kite' } } !trait WebSurfer { String surf() { 'web' } } !class Person { String name } !class Hipster extends Person implements KiteSurfer, WebSurfer {} !def h = new Hipster() assert h.surf() == 'web'
Traits: what about conflicts?
20
trait KiteSurfer { String surf() { 'kite' } } !trait WebSurfer { String surf() { 'web' } } !class Person { String name } !class Hipster extends Person implements KiteSurfer, WebSurfer {} !def h = new Hipster() assert h.surf() == 'web'
extending a class and implementing the two traits
Traits: what about conflicts?
20
trait KiteSurfer { String surf() { 'kite' } } !trait WebSurfer { String surf() { 'web' } } !class Person { String name } !class Hipster extends Person implements KiteSurfer, WebSurfer {} !def h = new Hipster() assert h.surf() == 'web'
Traits: what about conflicts?
20
trait KiteSurfer { String surf() { 'kite' } } !trait WebSurfer { String surf() { 'web' } } !class Person { String name } !class Hipster extends Person implements KiteSurfer, WebSurfer {} !def h = new Hipster() assert h.surf() == 'web'
last declared trait wins!
Traits: what about conflicts?
20
trait KiteSurfer { String surf() { 'kite' } } !trait WebSurfer { String surf() { 'web' } } !class Person { String name } !class Hipster extends Person implements KiteSurfer, WebSurfer {} !def h = new Hipster() assert h.surf() == 'web'
Traits: what about conflicts?
21
trait KiteSurfer { String surf() { 'kite' } } !trait WebSurfer { String surf() { 'web' } } !class Person { String name } !class Hipster extends Person implements WebSurfer, KiteSurfer {} !def h = new Hipster() assert h.surf() == 'kite'
Traits: what about conflicts?
21
trait KiteSurfer { String surf() { 'kite' } } !trait WebSurfer { String surf() { 'web' } } !class Person { String name } !class Hipster extends Person implements WebSurfer, KiteSurfer {} !def h = new Hipster() assert h.surf() == 'kite'
reverse the order!
Traits: what about conflicts?
21
trait KiteSurfer { String surf() { 'kite' } } !trait WebSurfer { String surf() { 'web' } } !class Person { String name } !class Hipster extends Person implements WebSurfer, KiteSurfer {} !def h = new Hipster() assert h.surf() == 'kite'
Traits: what about conflicts?
22
trait KiteSurfer { String surf() { 'kite' } } !trait WebSurfer { String surf() { 'web' } } !class Person { String name } !class Hipster extends Person implements WebSurfer, KiteSurfer { String surf() { KiteSurfer.super.surf() } } !def h = new Hipster() assert h.surf() == 'kite'
Traits: what about conflicts?
22
trait KiteSurfer { String surf() { 'kite' } } !trait WebSurfer { String surf() { 'web' } } !class Person { String name } !class Hipster extends Person implements WebSurfer, KiteSurfer { String surf() { KiteSurfer.super.surf() } } !def h = new Hipster() assert h.surf() == 'kite'
Be explicit! Override surf()
& use ‘super’
Traits: what about conflicts?
22
trait KiteSurfer { String surf() { 'kite' } } !trait WebSurfer { String surf() { 'web' } } !class Person { String name } !class Hipster extends Person implements WebSurfer, KiteSurfer { String surf() { KiteSurfer.super.surf() } } !def h = new Hipster() assert h.surf() == 'kite'
Your class method takes precedence over the traits
Traits: what about conflicts?
22
trait KiteSurfer { String surf() { 'kite' } } !trait WebSurfer { String surf() { 'web' } } !class Person { String name } !class Hipster extends Person implements WebSurfer, KiteSurfer { String surf() { KiteSurfer.super.surf() } } !def h = new Hipster() assert h.surf() == 'kite'
trait Named { String name } !
class Animal {} class NamedAnimal implements Named {} !
def na = new NamedAnimal(name: 'Felix') !
assert na.name == 'Felix'
Traits: runtime implementation
23
trait Named { String name } !
class Animal {} class NamedAnimal implements Named {} !
def na = new NamedAnimal(name: 'Felix') !
assert na.name == 'Felix'
Traits: runtime implementation
23
Somewhat artificial to have to create an intermediary class to
get named animals
trait Named { String name } !
class Animal {} class NamedAnimal implements Named {} !
def na = new NamedAnimal(name: 'Felix') !
assert na.name == 'Felix'
Traits: runtime implementation
23
trait Named { String name } !
class Animal {} !
!
def na = new Animal() as Named na.name = 'Felix' assert na.name == 'Felix'
Traits: runtime implementation
24
trait Named { String name } !
class Animal {} !
!
def na = new Animal() as Named na.name = 'Felix' assert na.name == 'Felix'
Traits: runtime implementation
24
Runtime trait, with Groovy’s usual
coercion mechanism
trait Named { String name } !
class Animal {} !
!
def na = new Animal() as Named na.name = 'Felix' assert na.name == 'Felix'
Traits: runtime implementation
24
Traits: runtime implementation
25
trait Named { String name } !
trait Quacks { String quack() { 'Quack!' } } !
class Animal {} !
def na = new Animal().withTraits Named, Quacks na.name = 'Daffy' assert na.name == 'Daffy' assert na.quack() == 'Quack!'
Traits: runtime implementation
25
trait Named { String name } !
trait Quacks { String quack() { 'Quack!' } } !
class Animal {} !
def na = new Animal().withTraits Named, Quacks na.name = 'Daffy' assert na.name == 'Daffy' assert na.quack() == 'Quack!'
Implement several traits at once, at runtime
Traits: runtime implementation
25
trait Named { String name } !
trait Quacks { String quack() { 'Quack!' } } !
class Animal {} !
def na = new Animal().withTraits Named, Quacks na.name = 'Daffy' assert na.name == 'Daffy' assert na.quack() == 'Quack!'
Traits: miscellaneous
• Traits can… !
• have private fields and methods • have abstract methods • implement interfaces • extend other traits or implement several traits • be statically type checked and compiled
26
To know all about traits!
27
Rethinking API design with traits by Cédric Champeau Tue 2:30pm / Trinity 3
© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission.
AST transforms
New: @TailRecursive
29
import groovy.transform.TailRecursive !
@TailRecursive def fact(BigInteger n, accu = 1G) { if (n < 2) accu else fact(n -‐ 1, n * accu) } !
assert fact(1000) > 10e2566
New: @TailRecursive
29
import groovy.transform.TailRecursive !
@TailRecursive def fact(BigInteger n, accu = 1G) { if (n < 2) accu else fact(n -‐ 1, n * accu) } !
assert fact(1000) > 10e2566
Rewrites tail recursive friendly function serially
New: @TailRecursive
29
import groovy.transform.TailRecursive !
@TailRecursive def fact(BigInteger n, accu = 1G) { if (n < 2) accu else fact(n -‐ 1, n * accu) } !
assert fact(1000) > 10e2566
Doesn’t blow up with a stack overflow error
New: @TailRecursive
29
import groovy.transform.TailRecursive !
@TailRecursive def fact(BigInteger n, accu = 1G) { if (n < 2) accu else fact(n -‐ 1, n * accu) } !
assert fact(1000) > 10e2566
Downside of tail recursion is you might have to rewrite
your algo to be tailrec friendly
New: @TailRecursive
29
import groovy.transform.TailRecursive !
@TailRecursive def fact(BigInteger n, accu = 1G) { if (n < 2) accu else fact(n -‐ 1, n * accu) } !
assert fact(1000) > 10e2566
New: @Sortable
30
import groovy.transform.* !
@Sortable class Person { String lastName String firstName int age }
New: @Sortable
30
import groovy.transform.* !
@Sortable class Person { String lastName String firstName int age }
Makes the class Comparable by multiple Comparators
New: @Sortable
30
import groovy.transform.* !
@Sortable class Person { String lastName String firstName int age }
First compare by lastName, then by firstName, etc.
New: @Sortable
30
import groovy.transform.* !
@Sortable class Person { String lastName String firstName int age }
You can also specify ‘includes’ / ‘excludes’
properties
New: @Sortable
30
import groovy.transform.* !
@Sortable class Person { String lastName String firstName int age }
@BaseScript improvements
31
abstract class CustomBase extends Script { int meaningOfLife = 42 }
@BaseScript(CustomBase) import groovy.transform.BaseScript !
assert meaningOfLife == 42
@BaseScript improvements
31
abstract class CustomBase extends Script { int meaningOfLife = 42 }
@BaseScript(CustomBase) import groovy.transform.BaseScript !
assert meaningOfLife == 42
You can add your own base methods and properties to all compiled scripts
@BaseScript improvements
31
abstract class CustomBase extends Script { int meaningOfLife = 42 }
@BaseScript(CustomBase) import groovy.transform.BaseScript !
assert meaningOfLife == 42
Define the base script class for this script
@BaseScript improvements
31
abstract class CustomBase extends Script { int meaningOfLife = 42 }
@BaseScript(CustomBase) import groovy.transform.BaseScript !
assert meaningOfLife == 42
Ability to put the annotation on imports & package
@BaseScript improvements
31
abstract class CustomBase extends Script { int meaningOfLife = 42 }
@BaseScript(CustomBase) import groovy.transform.BaseScript !
assert meaningOfLife == 42
@BaseScript custom abstract method
32
abstract class CustomBase extends Script { def run() { before() internalRun() after() } ! abstract internalRun() ! def before() { println 'before' } def after() { println 'after' } }
@BaseScript custom abstract method
32
abstract class CustomBase extends Script { def run() { before() internalRun() after() } ! abstract internalRun() ! def before() { println 'before' } def after() { println 'after' } }
import groovy.transform.BaseScript @BaseScript CustomBase script !println 'Hello'
@BaseScript custom abstract method
32
abstract class CustomBase extends Script { def run() { before() internalRun() after() } ! abstract internalRun() ! def before() { println 'before' } def after() { println 'after' } }
import groovy.transform.BaseScript @BaseScript CustomBase script !println 'Hello'
You can define your own abstract method for script bodies
@BaseScript custom abstract method
32
abstract class CustomBase extends Script { def run() { before() internalRun() after() } ! abstract internalRun() ! def before() { println 'before' } def after() { println 'after' } }
import groovy.transform.BaseScript @BaseScript CustomBase script !println 'Hello'
To know all about AST transformations!
33
Groovy AST transformations by Paul King Wed 2:30pm / Trinity 3
To know all about AST transformations!
34
Writing AST transformations by Simon / Sadogursky Thu 10:30pm / F. Park 3
© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission.
NIO2 module
JDK 7+ NIO2 module
• All the familiar methods on File retrofitted on Path as well
36
path.withReader { Reader r -‐> ... } path.eachLine { String line -‐> ... } path.eachFileRecurse { Path p -‐> ... } path << 'some content' path << bytes path.readLines() …
JDK 7+ NIO2 module
• All the familiar methods on File retrofitted on Path as well
36
path.withReader { Reader r -‐> ... } path.eachLine { String line -‐> ... } path.eachFileRecurse { Path p -‐> ... } path << 'some content' path << bytes path.readLines() …
Feature request to add all the java.nio.file.Files static utility
methods as GDK
JDK 7+ NIO2 module
• All the familiar methods on File retrofitted on Path as well
36
path.withReader { Reader r -‐> ... } path.eachLine { String line -‐> ... } path.eachFileRecurse { Path p -‐> ... } path << 'some content' path << bytes path.readLines() …
© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission.
JSON
JSON parser / builder perf. increase
• Re-implementation of JSON support for speed & efficiency • parser forked off the Boon JSON project • serializer carefully fine-tuned !
• Article on the parsing speed improvements • http://rick-hightower.blogspot.fr/2014/04/groovy-and-boon-provide-fastest-json.html
38
JSON parser / builder perf. increase
• Re-implementation of JSON support for speed & efficiency • parser forked off the Boon JSON project • serializer carefully fine-tuned !
• Article on the parsing speed improvements • http://rick-hightower.blogspot.fr/2014/04/groovy-and-boon-provide-fastest-json.html
38
JSON parser / builder perf. increase
• Re-implementation of JSON support for speed & efficiency • parser forked off the Boon JSON project • serializer carefully fine-tuned !
• Article on the parsing speed improvements • http://rick-hightower.blogspot.fr/2014/04/groovy-and-boon-provide-fastest-json.html
38
Benchmark gives 3x to 4x performance factor
over Jackson and GSON
JSON parser / builder perf. increase
• Re-implementation of JSON support for speed & efficiency • parser forked off the Boon JSON project • serializer carefully fine-tuned !
• Article on the parsing speed improvements • http://rick-hightower.blogspot.fr/2014/04/groovy-and-boon-provide-fastest-json.html
38
New modes for parsing
• Original JsonSlurper renamed to JsonSlurperClassic !
• Additional parsing modes: • INDEX_OVERLAY: super fast for <2MB payloads
o using a « parsing overlay » technique • CHARACTER_SOURCE: for >2MB payloads
o implemented with sliding windows over readers • LAX: beyond the JSON spec, nice for configuration files
o support single quotes, / and # comments • CHAR_BUFFER: general purpose
39
JsonSlurper for configuration files
40
import groovy.json.* import static groovy.json.JsonParserType.* !def parser = new JsonSlurper().setType(LAX) !def conf = parser.parseText ''' // configuration file { // no quote for key, single quoted value environment: 'production' # pound-‐style comment 'server': 5 } ''' !assert conf.environment == 'production' assert conf.server == 5
JsonSlurper for configuration files
40
import groovy.json.* import static groovy.json.JsonParserType.* !def parser = new JsonSlurper().setType(LAX) !def conf = parser.parseText ''' // configuration file { // no quote for key, single quoted value environment: 'production' # pound-‐style comment 'server': 5 } ''' !assert conf.environment == 'production' assert conf.server == 5
More tolerant parser: single quotes,
non-quoted keys, // and # comments,
missing comas
JsonSlurper for configuration files
40
import groovy.json.* import static groovy.json.JsonParserType.* !def parser = new JsonSlurper().setType(LAX) !def conf = parser.parseText ''' // configuration file { // no quote for key, single quoted value environment: 'production' # pound-‐style comment 'server': 5 } ''' !assert conf.environment == 'production' assert conf.server == 5
© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission.
Markup template engine
</>
Markup template engine
• Based on the principles of Groovy’s « builders » • and particularly the MarkupBuilder class
for generating arbitrary XML / HTML payloads !
• Compiled statically for fast template rendering !
• Internationalization aware • provide the desired Locale in the configuration object • usual suffix notation template_fr_FR.tpl !
• Custom base template class • ability to provide reusable methods across your templates 42
Markup template engine
• Based on the principles of Groovy’s « builders » • and particularly the MarkupBuilder class
for generating arbitrary XML / HTML payloads !
• Compiled statically for fast template rendering !
• Internationalization aware • provide the desired Locale in the configuration object • usual suffix notation template_fr_FR.tpl !
• Custom base template class • ability to provide reusable methods across your templates 42
Spring Boot approved
Markup template engine — the idea
43
cars { cars.each { car(make: it.make, name: it.name) } }
Markup template engine — the idea
43
cars { cars.each { car(make: it.make, name: it.name) } }
Your template
Markup template engine — the idea
43
cars { cars.each { car(make: it.make, name: it.name) } }
model = [cars: [! new Car(make: 'Peugeot', name: '508'), ! new Car(make: 'Toyota', name: 'Prius’)!]]
Markup template engine — the idea
43
cars { cars.each { car(make: it.make, name: it.name) } }
model = [cars: [! new Car(make: 'Peugeot', name: '508'), ! new Car(make: 'Toyota', name: 'Prius’)!]]
Feed a model into your template
Markup template engine — the idea
43
cars { cars.each { car(make: it.make, name: it.name) } }
model = [cars: [! new Car(make: 'Peugeot', name: '508'), ! new Car(make: 'Toyota', name: 'Prius’)!]]
<cars>! <car make='Peugeot' name='508'/>! <car make='Toyota' name='Prius'/>!</cars>
Markup template engine — the idea
43
cars { cars.each { car(make: it.make, name: it.name) } }
model = [cars: [! new Car(make: 'Peugeot', name: '508'), ! new Car(make: 'Toyota', name: 'Prius’)!]]
<cars>! <car make='Peugeot' name='508'/>! <car make='Toyota' name='Prius'/>!</cars>
Generate the XML output
Markup template engine — the idea
43
cars { cars.each { car(make: it.make, name: it.name) } }
model = [cars: [! new Car(make: 'Peugeot', name: '508'), ! new Car(make: 'Toyota', name: 'Prius’)!]]
<cars>! <car make='Peugeot' name='508'/>! <car make='Toyota' name='Prius'/>!</cars>
Markup template engine — in action
44
import groovy.text.markup.* !def config = new TemplateConfiguration() def engine = new MarkupTemplateEngine(config) def tmpl = engine.createTemplate(''' p("Hello ${model.name}") ''') def model = [name: 'World'] System.out << tmpl.make(model)
Markup template engine — includes
45
// include another template include template: 'foo.tpl' // include raw content include unescaped: 'raw.txt' !
// escape & include include escaped: 'to_escape.txt'
Markup template engine
46
// escaped automatically yield 'some raw content' !// include raw content yieldUnescaped 'content' !// <?xml version='1.0'?> xmlDeclaration()
Markup template engine
46
// escaped automatically yield 'some raw content' !// include raw content yieldUnescaped 'content' !// <?xml version='1.0'?> xmlDeclaration()
// <!-‐-‐comment-‐-‐> comment 'comment' !// adds new lines newLine() !// process. instruct. pi(/* ... */)
Markup template engine — configuration options
!!!
• declaration encoding !
• expand empty elements !
• use double quotes !
• newline string !!!!!!!
!!
!• auto escape
!• auto indent
!• base template class
!• locale
47
Markup template engine — static!
• Type-checked templates available • use createTypeCheckedModelTemplate()
instead of createTemplate() !
• Advantages • get compilation errors
o if a variable is not available o if you make mistakes in the code snippets
• even faster templates
48
Markup template engine — static!
• With typed check model creation method
!
!
!
!
!
!
!
!
!
• Or declare your model types in the template
49
Markup template engine — static!
• With typed check model creation method
!
!
!
!
!
!
!
!
!
• Or declare your model types in the template
49
def modelTypes = [cars: "List<Car>"] !def tmpl = engine. createTypeCheckedModelTemplate( "page.tpl", modelTypes)
Markup template engine — static!
• With typed check model creation method
!
!
!
!
!
!
!
!
!
• Or declare your model types in the template
49
def modelTypes = [cars: "List<Car>"] !def tmpl = engine. createTypeCheckedModelTemplate( "page.tpl", modelTypes)
modelTypes = { List<Car> cars } !cars.each { car -‐> p("Car name: $car.name") }
Markup template engine — static!
• With typed check model creation method
!
!
!
!
!
!
!
!
!
• Or declare your model types in the template
49
def modelTypes = [cars: "List<Car>"] !def tmpl = engine. createTypeCheckedModelTemplate( "page.tpl", modelTypes)
modelTypes = { List<Car> cars } !cars.each { car -‐> p("Car name: $car.name") }
Works with createTemplate() too
Markup template engine — static!
• With typed check model creation method
!
!
!
!
!
!
!
!
!
• Or declare your model types in the template
49
def modelTypes = [cars: "List<Car>"] !def tmpl = engine. createTypeCheckedModelTemplate( "page.tpl", modelTypes)
modelTypes = { List<Car> cars } !cars.each { car -‐> p("Car name: $car.name") }
© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission.
Documentation overhaul
GroovyDoc
51
GroovyDoc
51
GroovyDoc
51
Groovy GDK documentation
52
Groovy GDK documentation
52
Brand new documentation
53
© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission.
Groovy 2.4
Android support
• You can use Groovy to code Android apps! • use Groovy 2.4.0-beta-1+ • prefer @CompileStatic !
• Two great posts to get started: • http://melix.github.io/blog/2014/06/grooid.html • http://melix.github.io/blog/2014/06/grooid2.html
56
New York Times — Getting Groovy with Android
57
Android support
58
Android support
58
Android support
58
Source code available:https://github.com/melix/gr8confagenda
To know all about AST transformations!
59
Groovy & Android, a winning pair? by Cédric Champeau Thu 12:45pm / Trinity 3
Groovy Macros
!
• Sergei Egorov wants to contribute a macro module • https://github.com/groovy/groovy-core/pull/470 !
• Simplify creation of AST transformations • less boilerplate manipulating the Groovy AST API • more powerful and less limited than AstBuilder
60
Groovy Macros
!
• Authoring AST transformations can be verbose:
61
def someVariable = new ConstantExpression("xyz") def returnStatement = new ReturnStatement( new ConstructorCallExpression( ClassHelper.make(SomeCoolClass), new ArgumentListExpression(someVariable) ) )
Groovy Macros
• With Groovy Macros, it could be simpler:
62
def someVariable = macro { "xyz" } def returnStatement = macro { new SomeCoolClass($v{ someVariable }) }
Groovy Macros
• With Groovy Macros, it could be simpler:
62
def someVariable = macro { "xyz" } def returnStatement = macro { new SomeCoolClass($v{ someVariable }) }
Special « macro » command
Groovy Macros
• With Groovy Macros, it could be simpler:
62
def someVariable = macro { "xyz" } def returnStatement = macro { new SomeCoolClass($v{ someVariable }) }
Special « macro » command
Quasi-quotation
© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission.
Groovy 3.0
© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission.
New Age Meta-Object Protocol
MOP 2
Goals for the new MOP
• Leverage & build upon JDK 7+ invoke dynamic • get Java-like performance even for dynamic code
• Rationalize the sedimentation of meta-programming • more coherence, less corner cases & inconsistencies
• Provide a notion of « realm » • shield users of « monkey patching » • finer-grained control of meta-programming reach
• Private visibility anyone?
66
© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission.
Rewriting the Groovy grammar
with Antlr v4
Antlr v4 Grammar
Antlr v4 grammar
• Problems • Groovy still uses Antlr v2!
o but version 3 and 4 are out • Groovy’s grammar evolved from a Java grammar
o harder to fix and evolve, especially with Antlr v2 • Advantages
• Start from a clean slate • Antlr 4 more tolerant
and powerful regarding ambiguities • Time to clean some grammar & syntax warts! • Need to implement the Java 8 constructs!
68
Antlr v4 grammar
• Problems • Groovy still uses Antlr v2!
o but version 3 and 4 are out • Groovy’s grammar evolved from a Java grammar
o harder to fix and evolve, especially with Antlr v2 • Advantages
• Start from a clean slate • Antlr 4 more tolerant
and powerful regarding ambiguities • Time to clean some grammar & syntax warts! • Need to implement the Java 8 constructs!
68
A « Google Summer of Code » student is currently helping
© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission.
Support the new Java 8
language features
Java 8 language support
Java 8 support
• Additional grammar & semantic features to support • to keep saying Groovy / Java interoperability is awesome!
• New in Java 8 • lambdas • method references • default methods in interfaces • stream API, date / time API • annotations on types & repeated annotations
70
Java 8 support
• Additional grammar & semantic features to support • to keep saying Groovy / Java interoperability is awesome!
• New in Java 8 • lambdas • method references • default methods in interfaces • stream API, date / time API • annotations on types & repeated annotations
70
Groovy had already: closures, method pointers, mixins,
enriched collection & time APIs
To know all about AST transformations!
71
How to get Groovy with Java 8 by Peter Ledbrook Thu 10:30pm / Trinity 3
© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission.
Summary
Groovy rocks the JVM since 2003!
© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission.
Q & A
Image credits• Big rock
• http://wallpaper.preview-reviews.com/12852-red-rocks-in-a-snowstorm • Android robot
• http://crackberry.com/sites/crackberry.com/files/styles/large/public/topic_images/2013/ANDROID.png?itok=xhm7jaxS • Modern MOP
• http://i933.photobucket.com/albums/ad179/autobin/Wonder%20Mop/wondermop4.jpg • Jason
• http://static.comicvine.com/uploads/original/3/32405/1031312-jason_19_inch_figure_l.jpg • Jigsaw
• http://www.psdgraphics.com/file/psd-jigsaw-icon.jpg • Many thanks
• http://www.trys.ie/wp-content/uploads/2013/06/many-thanks.jpg
76