Share
Embed
Groovy in 2014 and beyond at Devoxx France
New presentation on all the new features of Groovy 2.3
Guillaume Laforge
April 18, 2014
Transcript
149 slides
-
@glaforge #dvxgroovy Groovy en 2014 et au-delà… Guillaume Laforge Groovy
Project Manager http://glaforge.appspot.com -
@glaforge #dvxgroovy Stay up-to-date with all things Groovy ! •
Groovy Weekly newsletter • Every Tuesday ! • http://bit.ly/groovy-weekly- subscribe -
@glaforge #dvxgroovy Stay up-to-date with all things Groovy ! •
Groovy Google+ page ! • https://plus.google.com/ +groovy -
@glaforge #dvxgroovy Stay up-to-date with all things Groovy ! •
Groovy Google+ community ! • https://plus.google.com/ communities/ 105160926044623621768 -
@glaforge #dvxgroovy The Groovy roadmap… 2015 2014 2013 Groovy 2.3
Groovy 3.0 Groovy 2.2 -
@glaforge #dvxgroovy 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 -
@glaforge #dvxgroovy Groovy 3.0 ! • New Meta-Object Protocol !
• Invoke-dynamic based runtime ! • Rewritten language grammar with Antlr v4 -
@glaforge #dvxgroovy 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 & compilation • class methods coming from traits are also visible from Java • Also possible to implement traits at runtime -
@glaforge #dvxgroovy 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 -
@glaforge #dvxgroovy 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 « trait », a new keyword for a new concept -
@glaforge #dvxgroovy 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 a class « implements » a trait -
@glaforge #dvxgroovy 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 the fly() method from the trait is available -
@glaforge #dvxgroovy 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 -
@glaforge #dvxgroovy trait Named { String
name } ! class Bird implements Named {} def b = new Bird(name: 'Colibri') ! assert b.name == 'Colibri' Traits: stateful -
@glaforge #dvxgroovy trait Named { String
name } ! class Bird implements Named {} def b = new Bird(name: 'Colibri') ! assert b.name == 'Colibri' Traits: stateful a Groovy property -
@glaforge #dvxgroovy trait Named { String
name } ! class Bird implements Named {} def b = new Bird(name: 'Colibri') ! assert b.name == 'Colibri' Traits: stateful implement the trait -
@glaforge #dvxgroovy trait Named { String
name } ! class Bird implements Named {} def b = new Bird(name: 'Colibri') ! assert b.name == 'Colibri' Traits: stateful Groovy named argument constructor -
@glaforge #dvxgroovy trait Named { String
name } ! class Bird implements Named {} def b = new Bird(name: 'Colibri') ! assert b.name == 'Colibri' Traits: stateful access the property -
@glaforge #dvxgroovy trait Named { String
name } ! class Bird implements Named {} def b = new Bird(name: 'Colibri') ! assert b.name == 'Colibri' Traits: stateful -
@glaforge #dvxgroovy 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 -
@glaforge #dvxgroovy 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 extend the Named trait -
@glaforge #dvxgroovy 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 access the name property -
@glaforge #dvxgroovy 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 implement the composite trait -
@glaforge #dvxgroovy 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 -
@glaforge #dvxgroovy 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 (& dynamism) -
@glaforge #dvxgroovy 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 (& dynamism) access a dynamic property -
@glaforge #dvxgroovy 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 (& dynamism) implements two traits! -
@glaforge #dvxgroovy 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 (& dynamism) dynamic ‘name’ property interpolated -
@glaforge #dvxgroovy 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 (& dynamism) -
@glaforge #dvxgroovy 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? -
@glaforge #dvxgroovy 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? two surf() methods -
@glaforge #dvxgroovy 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? -
@glaforge #dvxgroovy 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? extending a class and implementing the two traits -
@glaforge #dvxgroovy 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? -
@glaforge #dvxgroovy 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? last declared trait wins! -
@glaforge #dvxgroovy 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? -
@glaforge #dvxgroovy 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? -
@glaforge #dvxgroovy 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? reverse the order! -
@glaforge #dvxgroovy 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? -
@glaforge #dvxgroovy 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? -
@glaforge #dvxgroovy 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? Be explicit! Override surf() & use ‘super’ -
@glaforge #dvxgroovy 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? Your class method takes precedence over the traits -
@glaforge #dvxgroovy 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? -
@glaforge #dvxgroovy ! ! trait CustomToString { !
String toString() { "a ${this.class.name} instance" } } ! class Foo implements CustomToString {} ! assert new Foo().toString() != 'a Foo instance' Traits: forcing method override -
@glaforge #dvxgroovy ! ! trait CustomToString { !
String toString() { "a ${this.class.name} instance" } } ! class Foo implements CustomToString {} ! assert new Foo().toString() != 'a Foo instance' Traits: forcing method override ‘this’ is the ‘this’ of the class implementing the trait -
@glaforge #dvxgroovy ! ! trait CustomToString { !
String toString() { "a ${this.class.name} instance" } } ! class Foo implements CustomToString {} ! assert new Foo().toString() != 'a Foo instance' Traits: forcing method override The default Object#toString() method always prevails, in spite of the trait’s toString() -
@glaforge #dvxgroovy ! ! trait CustomToString { !
String toString() { "a ${this.class.name} instance" } } ! class Foo implements CustomToString {} ! assert new Foo().toString() != 'a Foo instance' Traits: forcing method override -
@glaforge #dvxgroovy import groovy.transform.ForceOverride ! trait CustomToString {
@ForceOverride String toString() { "a ${this.class.name} instance" } } ! class Foo implements CustomToString {} ! assert new Foo().toString() == 'a Foo instance' Traits: forcing method override -
@glaforge #dvxgroovy import groovy.transform.ForceOverride ! trait CustomToString {
@ForceOverride String toString() { "a ${this.class.name} instance" } } ! class Foo implements CustomToString {} ! assert new Foo().toString() == 'a Foo instance' Traits: forcing method override Use @ForceOverride to force the compiler to use the trait’s method -
@glaforge #dvxgroovy import groovy.transform.ForceOverride ! trait CustomToString {
@ForceOverride String toString() { "a ${this.class.name} instance" } } ! class Foo implements CustomToString {} ! assert new Foo().toString() == 'a Foo instance' Traits: forcing method override If Foo had implemented toString(), Foo’s toString() would always win -
@glaforge #dvxgroovy import groovy.transform.ForceOverride ! trait CustomToString {
@ForceOverride String toString() { "a ${this.class.name} instance" } } ! class Foo implements CustomToString {} ! assert new Foo().toString() == 'a Foo instance' Traits: forcing method override -
@glaforge #dvxgroovy trait Named { String
name } ! class Animal {} class NamedAnimal implements Named {} ! def na = new NamedAnimal(name: 'Felix') ! assert na.name == 'Felix' Traits: runtime implementation -
@glaforge #dvxgroovy trait Named { String
name } ! class Animal {} class NamedAnimal implements Named {} ! def na = new NamedAnimal(name: 'Felix') ! assert na.name == 'Felix' Traits: runtime implementation Somewhat artificial to have to create an intermediary class to get named animals -
@glaforge #dvxgroovy trait Named { String
name } ! class Animal {} class NamedAnimal implements Named {} ! def na = new NamedAnimal(name: 'Felix') ! assert na.name == 'Felix' Traits: runtime implementation -
@glaforge #dvxgroovy trait Named { String
name } ! class Animal {} ! ! def na = new Animal() as Named na.name = 'Felix' assert na.name == 'Felix' Traits: runtime implementation -
@glaforge #dvxgroovy trait Named { String
name } ! class Animal {} ! ! def na = new Animal() as Named na.name = 'Felix' assert na.name == 'Felix' Traits: runtime implementation Runtime trait, with Groovy’s usual coercion mechanism -
@glaforge #dvxgroovy trait Named { String
name } ! class Animal {} ! ! def na = new Animal() as Named na.name = 'Felix' assert na.name == 'Felix' Traits: runtime implementation -
@glaforge #dvxgroovy 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 -
@glaforge #dvxgroovy 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 Implement several traits at once, at runtime -
@glaforge #dvxgroovy 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 -
@glaforge #dvxgroovy 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 -
@glaforge #dvxgroovy New: @TailRecursive 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 -
@glaforge #dvxgroovy New: @TailRecursive 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 -
@glaforge #dvxgroovy New: @TailRecursive 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 -
@glaforge #dvxgroovy New: @TailRecursive 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 -
@glaforge #dvxgroovy New: @TailRecursive 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 -
@glaforge #dvxgroovy New: @Sortable import groovy.transform.* ! @Sortable
class Person { String lastName String firstName int age } -
@glaforge #dvxgroovy New: @Sortable import groovy.transform.* ! @Sortable
class Person { String lastName String firstName int age } Makes the class Comparable by multiple Comparators -
@glaforge #dvxgroovy New: @Sortable import groovy.transform.* ! @Sortable
class Person { String lastName String firstName int age } First compare by lastName, then by firstName, etc. -
@glaforge #dvxgroovy New: @Sortable import groovy.transform.* ! @Sortable
class Person { String lastName String firstName int age } You can also specify ‘includes’ / ‘excludes’ properties -
@glaforge #dvxgroovy New: @Sortable import groovy.transform.* ! @Sortable
class Person { String lastName String firstName int age } -
@glaforge #dvxgroovy @BaseScript improvements abstract class CustomBase extends Script {
int meaningOfLife = 42 } @BaseScript(CustomBase) import groovy.transform.BaseScript ! assert meaningOfLife == 42 -
@glaforge #dvxgroovy @BaseScript improvements 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 -
@glaforge #dvxgroovy @BaseScript improvements 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 -
@glaforge #dvxgroovy @BaseScript improvements abstract class CustomBase extends Script {
int meaningOfLife = 42 } @BaseScript(CustomBase) import groovy.transform.BaseScript ! assert meaningOfLife == 42 In 2.3, ability to put the annotation on imports & package -
@glaforge #dvxgroovy @BaseScript improvements abstract class CustomBase extends Script {
int meaningOfLife = 42 } @BaseScript(CustomBase) import groovy.transform.BaseScript ! assert meaningOfLife == 42 -
@glaforge #dvxgroovy @BaseScript custom abstract method abstract class CustomBase extends
Script { def run() { before() internalRun() after() } ! abstract internalRun() ! def before() { println 'before' } def after() { println 'after' } } -
@glaforge #dvxgroovy @BaseScript custom abstract method 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' -
@glaforge #dvxgroovy @BaseScript custom abstract method 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 -
@glaforge #dvxgroovy @BaseScript custom abstract method 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' -
@glaforge #dvxgroovy JDK 7+ NIO2 module • All the familiar
methods on File retrofitted on Path as well path.withReader { Reader r -‐> ... } path.eachLine { String line -‐> ... } path.eachFileRecurse { Path p -‐> ... } path << 'some content' path << bytes path.readLines() … -
@glaforge #dvxgroovy JDK 7+ NIO2 module • All the familiar
methods on File retrofitted on Path as well 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 methods -
@glaforge #dvxgroovy JDK 7+ NIO2 module • All the familiar
methods on File retrofitted on Path as well path.withReader { Reader r -‐> ... } path.eachLine { String line -‐> ... } path.eachFileRecurse { Path p -‐> ... } path << 'some content' path << bytes path.readLines() … -
@glaforge #dvxgroovy JSON parser / builder performance increase • Re-implementation
of JSON support for speed & efficiency • parser forked of 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 -
@glaforge #dvxgroovy JSON parser / builder performance increase • Re-implementation
of JSON support for speed & efficiency • parser forked of 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 -
@glaforge #dvxgroovy JSON parser / builder performance increase • Re-implementation
of JSON support for speed & efficiency • parser forked of 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 Benchmark gives 3x to 4x performance factor over Jackson and GSON -
@glaforge #dvxgroovy JSON parser / builder performance increase • Re-implementation
of JSON support for speed & efficiency • parser forked of 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 -
@glaforge #dvxgroovy New modes for parsing • Original JsonSlurper renamed
to JsonSlurperClassic • Additional parsing modes: • INDEX_OVERLAY: super fast for <2MB payloads • using a « parsing overlay » technique • CHARACTER_SOURCE: for >2MB payloads • implemented with sliding windows over readers • LAX: beyond the JSON spec, nice for configuration files • support single quotes, / and # comments • CHAR_BUFFER: general purpose -
@glaforge #dvxgroovy JsonSlurper for configuration files 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 -
@glaforge #dvxgroovy JsonSlurper for configuration files 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 -
@glaforge #dvxgroovy JsonSlurper for configuration files 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 -
@glaforge #dvxgroovy 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 -
@glaforge #dvxgroovy Markup template engine — the idea cars {
cars.each { car(make: it.make, name: it.name) } } -
@glaforge #dvxgroovy Markup template engine — the idea cars {
cars.each { car(make: it.make, name: it.name) } } Your template -
@glaforge #dvxgroovy Markup template engine — the idea cars {
cars.each { car(make: it.make, name: it.name) } } model = [cars: [! new Car(make: 'Peugeot', name: '508'), ! new Car(make: 'Toyota', name: 'Prius’)! ]] -
@glaforge #dvxgroovy Markup template engine — the idea 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 -
@glaforge #dvxgroovy Markup template engine — the idea 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> -
@glaforge #dvxgroovy Markup template engine — the idea 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 -
@glaforge #dvxgroovy Markup template engine — the idea 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> -
@glaforge #dvxgroovy Markup template engine — in action 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) -
@glaforge #dvxgroovy Markup template engine — includes // include another
template include template: 'foo.tpl' // include raw content include unescaped: 'raw.txt' ! // escape & include include escaped: 'to_escape.txt' -
@glaforge #dvxgroovy Markup template engine — useful methods // escaped
automatically yield 'some raw content' ! // include raw content yieldUnescaped 'content' ! // <?xml version='1.0'?> xmlDeclaration() -
@glaforge #dvxgroovy Markup template engine — useful methods // escaped
automatically yield 'some raw content' ! // include raw content yieldUnescaped 'content' ! // <?xml version='1.0'?> xmlDeclaration() // <!-‐-‐comment-‐-‐> comment 'comment' ! // adds new lines newLine() ! // processing instructions pi(/* ... */) -
@glaforge #dvxgroovy Markup template engine — configuration • Configuration options
! • declaration encoding ! • expand empty elements ! • use double quotes ! • newline string ! ! ! ! • auto escape ! • auto indent ! • base template class ! • locale -
@glaforge #dvxgroovy Markup template engine — static! • Type-checked templates
available • use createTypeCheckedModelTemplate() instead of createTemplate() • Advantages • get compilation errors • if a variable is not available • if you make mistakes in the code snippets • even faster templates -
@glaforge #dvxgroovy Markup template engine — static! • With typed
check model creation method ! ! ! ! ! • Alternative: declare your model types in the template -
@glaforge #dvxgroovy Markup template engine — static! • With typed
check model creation method ! ! ! ! ! • Alternative: declare your model types in the template def modelTypes = [cars: "List<Car>"] ! def tmpl = engine. createTypeCheckedModelTemplate( "page.tpl", modelTypes) -
@glaforge #dvxgroovy Markup template engine — static! • With typed
check model creation method ! ! ! ! ! • Alternative: declare your model types in the template def modelTypes = [cars: "List<Car>"] ! def tmpl = engine. createTypeCheckedModelTemplate( "page.tpl", modelTypes) modelTypes = { List<Car> cars } ! cars.each { car -‐> p("Car name: $car.name") } -
@glaforge #dvxgroovy Markup template engine — static! • With typed
check model creation method ! ! ! ! ! • Alternative: declare your model types in the template 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 -
@glaforge #dvxgroovy Markup template engine — static! • With typed
check model creation method ! ! ! ! ! • Alternative: declare your model types in the template def modelTypes = [cars: "List<Car>"] ! def tmpl = engine. createTypeCheckedModelTemplate( "page.tpl", modelTypes) modelTypes = { List<Car> cars } ! cars.each { car -‐> p("Car name: $car.name") } -
@glaforge #dvxgroovy Goals for the new Meta-Object Protocol • Fully
leverage and 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? -
@glaforge #dvxgroovy Antlr v4 grammar • Problems • Groovy still
uses Antlr v2! • but version 3 and 4 are out • Groovy’s grammar evolved from a Java grammar • 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! -
@glaforge #dvxgroovy Antlr v4 grammar • Problems • Groovy still
uses Antlr v2! • but version 3 and 4 are out • Groovy’s grammar evolved from a Java grammar • 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! A « Groovy Summer of Code » student to help -
@glaforge #dvxgroovy Java 8 support • Additional grammar and 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 -
@glaforge #dvxgroovy Java 8 support • Additional grammar and 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 Groovy had already: closures, method pointers, mixins, enriched collection & time APIs -
@glaforge #dvxgroovy Crédit image / Creative Commons • Rue pavée
— By-Nc-Sa • http://www.flickr.com/photos/22914687@N05/4957591422/sizes/l/ • Sous la Tour Eiffel — By-Nc-Sa • http://www.flickr.com/photos/stewiedewie/244850735/sizes/l/in/photostream/ • Sous le pont — By-Nc-Nd • http://www.landscape-photo.net/displayimage.php?pid=5194 • Paris Metro - By-Nc-Sa • http://www.flickr.com/photos/22914687@N05/6317047263/sizes/l/ ! • Slide template created by @glaforge, completed by @nmartignole for Devoxx FR2014