Les nouveautés de Groovy 2 -- Mix-IT 2013
-
Upload
guillaume-laforge -
Category
Technology
-
view
1.177 -
download
19
description
Transcript of Les nouveautés de Groovy 2 -- Mix-IT 2013
Les nouveautés de Groovy 2
Guillaume LaforgeGroovy Project ManagerSpringSource / VMware
Guillaume Laforge @glaforge
http://glaforge.appspot.com http://gplus.to/glaforge
Langage dynamiqueoptionnellement typé
Groovy
...statiquement vérifié et compilé
Groovy
syntaxe dérivant de Java :facile à apprendre !
Groovy
1.7 million downloads
A blossomingEcosystem
GV
M
GVM
GVMGROOVYENVIRONMENTMANAGER
GVM: Groovy enVironment Manager
• Nouveau venu dans la communauté• http://gvmtool.net/ — @gvmtool
• Gérer les versions parallèles de différents projets de l’écosystème
• Supporte...• Groovy, Grails, Griffon, Gradle, Vert.x
• Sur Linux, MacOS, Cygwin, Solaris, FreeBSD
Commençons par Groovy 2.0
ModularityJava 7: Project Coin & invoke dynamicStatic type checking & compilation
Modularité
« Tout le monde n’a pas besoin de tout,tout le temps, en même temps ! »
La modularité de Groovy
• Le JAR « groovy-all » de... 6 Mo !
• En plus du langage, des APIs :• moteur de template, scripting the tâches Ant,
construction d’interfaces Swing...
• Proposer un coeur plus léger• et des modules par API
• Brancher des méthodes d’extension
Les nouveaux JARs
• Un JAR principal plus petit 3 Mo
• Modules
– console– docgenerator– groovydoc– groovysh– ant– bsf
– jsr-223– jmx– sql– swing– servlet– templates
– test– testng– json– xml
Les nouveaux JARs
• Un JAR principal plus petit 3 Mo
• Modules
– console– docgenerator– groovydoc– groovysh– ant– bsf
– jsr-223– jmx– sql– swing– servlet– templates
– test– testng– json– xml
« Fais ton marché »
Les modules d’extension
• Créer sa propre extension• contribuer des méthodes d’instance
package foo
class StringExtension { static introduces(String self, String name) { "Hi ${name), I’m ${self}" }}
// usage: "Guillaume".introduces("Cédric")
Les modules d’extension
• Créer sa propre extension• contribuer des méthodes d’instance
package foo
class StringExtension { static introduces(String self, String name) { "Hi ${name), I’m ${self}" }}
// usage: "Guillaume".introduces("Cédric")
Même structure que les catégories
Les modules d’extension
• Créer sa propre extension• contribuer des méthodes statiques
package foo
class StaticStringExtension { static hi(String self) { "Hi!" }}
// usage: String.hi()
Descripteur des modules d’extension
• META-INF/• services/• org.codehaus.groovy.runtime.ExtensionModule
moduleName = stringExtensionsmoduleVersion = 1.0// liste de noms de classe séparées par des virgulesextensionClasses = foo.StringExtension// liste de noms de classe séparées par des virgulesstaticExtensionClasses = foo.StaticStringExtension
Thème Java 7
Syntaxe de « Project Coin »Support d’invoke dynamic
Une histoire de canard...
Littéraux binaires
• En plus de décimal, octal, et héxa...
• On a une représentation binaire :
int x = 0b10101111assert x == 175 byte aByte = 0b00100001assert aByte == 33 int anInt = 0b1010000101000101assert anInt == 41285
Les « underscores » dans les littéraux
• Utilisation des « underscores » pour séparer les unités au choix
long creditCardNumber = 1234_5678_9012_3456Llong socialSecurityNumbers = 999_99_9999Lfloat monetaryAmount = 12_345_132.12long hexBytes = 0xFF_EC_DE_5Elong hexWords = 0xFFEC_DE5Elong maxLong = 0x7fff_ffff_ffff_ffffLlong alsoMaxLong = 9_223_372_036_854_775_807Llong bytes = 0b11010010_01101001_10010100_10010010
Catch d’exceptions multiples
• Un seul bloc catch pour plusieurs exceptions, plutôt que dupliquer les blocs
try { /* ... */} catch(IOException | NullPointerException e) { /* un seul bloc */}
Coin-Coin !
Support d’invoke dynamic de JDK 7
• Nouveau « flag » pour compiler avec « indy »• on proposera peut-être un backport (pour JDK < 7)
• Avantages• plus de performance à l’exécution• en théorie...
• Sur le long terme, on pourra remplacer• « call site caching » ➔ MethodHandles• « metaclass registry » ➔ ClassValues
• et le JIT « inlinera » plus facilement le code
Thème « statique »
Vérification statique de typeCompilation statique
Vérification statiques de type
• But : rendre le compilateur « grincheux » !
• jeter des erreurs à la compilation• et non pas au runtime !
Tout le monde n’a pas besoin de dynamique
tout le temps !
Tout le monde n’a pas besoin de dynamique
tout le temps !
Nah !
Vérification statique de type
• Le compilateur grincheux souhaite...
• dire quand il y a une faute de frappe dans le nom d’une méthode ou d’une variable
• râler quand on appelle une méthode inexistante
• ou quand on fait de mauvaises affectations ou utilise un mauvais type de retour
Vérification statique de type
• Le compilateur doit inférer les types...
• moins besoin de types explicites et de casts
• inférence fine • « flow typing »• « lowest upper bound »
Vérification statique de type
• Mais le compilateur doit comprendre les méthodes d’extension de Groovy
• permet d’avoir un bon niveau de dynamisme malgré les restrictions supplémentaires
Fautes de frappe
import groovy.transform.TypeChecked void method() {} @TypeChecked test() { // Cannot find matching method metthhoood() metthhoood() def name = "Guillaume" // variable naamme is undeclared println naamme}
Fautes de frappe
import groovy.transform.TypeChecked void method() {} @TypeChecked test() { // Cannot find matching method metthhoood() metthhoood() def name = "Guillaume" // variable naamme is undeclared println naamme}
Erreur de compilation
Fautes de frappe
import groovy.transform.TypeChecked void method() {} @TypeChecked test() { // Cannot find matching method metthhoood() metthhoood() def name = "Guillaume" // variable naamme is undeclared println naamme}
Erreur de compilation
Erreur de compilation
Fautes de frappe
import groovy.transform.TypeChecked void method() {} @TypeChecked test() { // Cannot find matching method metthhoood() metthhoood() def name = "Guillaume" // variable naamme is undeclared println naamme}
Erreur de compilation
Erreur de compilation
Annotation niveau classe ou méthode
Mauvaises affectations de variable
// cannot assign value of type... to variable...int x = new Object()Set set = new Object() String[] strings = ['a','b','c']int str = strings[0] // cannot find matching method plus()int i = 0i += '1'
Mauvaises affectations de variable
// cannot assign value of type... to variable...int x = new Object()Set set = new Object() String[] strings = ['a','b','c']int str = strings[0] // cannot find matching method plus()int i = 0i += '1'
Erreurs de compilation
Mauvaises affectations de variable
// cannot assign value of type... to variable...int x = new Object()Set set = new Object() String[] strings = ['a','b','c']int str = strings[0] // cannot find matching method plus()int i = 0i += '1'
Erreurs de compilation
Erreurs de compilation
Mauvaises affectations de variable
// cannot assign value of type... to variable...int x = new Object()Set set = new Object() String[] strings = ['a','b','c']int str = strings[0] // cannot find matching method plus()int i = 0i += '1'
Erreurs de compilation
Erreurs de compilation
Erreurs de compilation
Mauvais type de retour
// checks if/else branch return values@TypeCheckedint method() { if (true) { 'String' } else { 42 }}// works for switch/case & try/catch/finally // transparent toString() implied@TypeCheckedString greeting(String name) { def sb = new StringBuilder() sb << "Hi " << name}
Mauvais type de retour
// checks if/else branch return values@TypeCheckedint method() { if (true) { 'String' } else { 42 }}// works for switch/case & try/catch/finally // transparent toString() implied@TypeCheckedString greeting(String name) { def sb = new StringBuilder() sb << "Hi " << name}
Erreur de compilation
Mauvais type de retour
// checks if/else branch return values@TypeCheckedint method() { if (true) { 'String' } else { 42 }}// works for switch/case & try/catch/finally // transparent toString() implied@TypeCheckedString greeting(String name) { def sb = new StringBuilder() sb << "Hi " << name}
Erreur de compilation
Au final, appèle le toString() de StringBuilder
Inférence de type
@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 }}
Inférence de type
@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 }}
Variable optionnellement typée
Inférence de type
@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 }}
Variable optionnellement typée
Type String inféré
Inférence de type
@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 }}
Variable optionnellement typée
Méthode trim() ajoutée dynamiquement par Groovy
Type String inféré
Inférence de type
@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 }}
Variable optionnellement typée
Type des éléments d’un tableau inféré
Méthode trim() ajoutée dynamiquement par Groovy
Type String inféré
Mélanger dynamique et statiquement vérifié
@TypeCheckedString greeting(String name) { // call method with dynamic behavior // but with proper signature generateMarkup(name.toUpperCase())} // usual dynamic behaviorString generateMarkup(String name) { def sw = new StringWriter() new MarkupBuilder(sw).html { body { div name } } sw.toString()}
Mélanger dynamique et statiquement vérifié
@TypeCheckedString greeting(String name) { // call method with dynamic behavior // but with proper signature generateMarkup(name.toUpperCase())} // usual dynamic behaviorString generateMarkup(String name) { def sw = new StringWriter() new MarkupBuilder(sw).html { body { div name } } sw.toString()}
Statiquement vérifié
Mélanger dynamique et statiquement vérifié
@TypeCheckedString greeting(String name) { // call method with dynamic behavior // but with proper signature generateMarkup(name.toUpperCase())} // usual dynamic behaviorString generateMarkup(String name) { def sw = new StringWriter() new MarkupBuilder(sw).html { body { div name } } sw.toString()}
Statiquement vérifié
Dynamique
Vérifications par instanceof
@TypeChecked void test(Object val) {
if (val instanceof String) { println val.toUpperCase() } else if (val instanceof Number) { println "X" * val.intValue() }}
Vérifications par instanceof
@TypeChecked void test(Object val) {
if (val instanceof String) { println val.toUpperCase() } else if (val instanceof Number) { println "X" * val.intValue() }}
Pas besoin de cast
Vérifications par instanceof
@TypeChecked void test(Object val) {
if (val instanceof String) { println val.toUpperCase() } else if (val instanceof Number) { println "X" * val.intValue() }}
Pas besoin de cast
Pas besoin de cast
Vérifications par instanceof
@TypeChecked void test(Object val) {
if (val instanceof String) { println val.toUpperCase() } else if (val instanceof Number) { println "X" * val.intValue() }}
Pas besoin de cast
Pas besoin de cast
Comprends la méthode du GDK : String#multuply(int)
Lowest Upper Bound
• Le plus petit « super » type commun• peut-être virtuel (« non-dénotable »)
@TypeChecked test() { // an integer and a BigDecimal return [1234, 3.14]}
Lowest Upper Bound
• Le plus petit « super » type commun• peut-être virtuel (« non-dénotable »)
@TypeChecked test() { // an integer and a BigDecimal return [1234, 3.14]}
Type inféré :List<Number & Comparable>
Flow typing
• La vérification statique « suit » le type des valeurs assignées dans les variables
@TypeChecked test() { def var = 123 // int inferé int x = var // var est un int var = "123" // assigne une String dans var
x = var.toInteger() // pas besoin de cast
var = 123 x = var.toUpperCase() // erreur, var est un int !}
Pô très clean ton code, non mais allô quoi ?
Pô très clean ton code, non mais allô quoi ?
Ben non !
Vérification statique et code dynamique
• La vérification statique à la compilation• @TypeChecked ne change pas le comportement• ne pas confondre avec compilation statique
• La plupart des fonctionnalités dynamiques ne peuvent être vérifiées
• changement de métaclasse, catégories...• variables dynamiques dans le « script binding »
• Mais métaprogrammation compile-time OK• si suffisamment d’informations de type
Pas de métaprogrammation dynamique
@TypeChecked void test() { Integer.metaClass.foo = {} 123.foo()}
Pas de métaprogrammation dynamique
@TypeChecked void test() { Integer.metaClass.foo = {} 123.foo()}
Accès au champ dynamique
metaClass interdit
Pas de métaprogrammation dynamique
@TypeChecked void test() { Integer.metaClass.foo = {} 123.foo()}
Accès au champ dynamique
metaClass interditMéthode non reconnue
Type explicite pour les paramètres de closure
@TypeChecked test() { ["a", "b", "c"].collect { it.toUpperCase() // Pas d’accord ! }}
Type explicite pour les paramètres de closure
@TypeChecked test() { ["a", "b", "c"].collect { String it -‐> it.toUpperCase() // OK, une String }}
Type explicite pour les paramètres de closure
@TypeChecked test() { ["a", "b", "c"].collect { String it -‐> it.toUpperCase() // OK, une String }}
Obligé d’indiquer le type explicitement
Type explicite pour les paramètres de closure
@TypeChecked test() { ["a", "b", "c"].collect { String it -‐> it.toUpperCase() // OK, une String }}
Obligé d’indiquer le type explicitement
La liste peut contenir n’importe quoi à l’exécution !
Mais si c’est pô dynamique, on peut compiler statiquement ?
Mais si c’est pô dynamique, on peut compiler statiquement ?
Ben oui !
Compilation statique
• Etant donné que le code est vérifié, que l’on infère beaucoup d’information de type...on peut aussi bien compiler statiquement !
• càd générer le même bytecode que javac
• Aussi intéressant pour ceux qui sont bloqués en JDK < 7, pour bénéficier d’améliorations de performances
Avantages de la compilation statique
• On gagne :• de la « type safety »• grâce à la vérification statique • car la compilation statique s’appuie dessus
• du code plus rapide• aussi proche que la performance de Java
• du code immunisé contre le « monkey patching »• la métaprogrammation dynamique peut
interférer avec vos frameworks• du bytecode généré plus petit
Ouais, ch’fais c’que j’veux
avec ton code
Ouais, ch’fais c’que j’veux
avec ton code
Niark !
Inconvénients de la compilation statique
• On y perds...
• Certaines fonctionnalités dynamiques• changement de métaclasse, catégories
• Le « dynamic dispatch » de méthode peut différer• même si grâce à l’inférence de type, elle est aussi
proche de Groovy « classique » que possible
Mixer compilation statique et code dynamique@CompileStaticString greeting(String name) { // call method with dynamic behavior // but with proper signature generateMarkup(name.toUpperCase())} // usual dynamic behaviorString generateMarkup(String name) { def sw = new StringWriter() new MarkupBuilder(sw).html { body { div name } } sw.toString()}
Mixer compilation statique et code dynamique@CompileStaticString greeting(String name) { // call method with dynamic behavior // but with proper signature generateMarkup(name.toUpperCase())} // usual dynamic behaviorString generateMarkup(String name) { def sw = new StringWriter() new MarkupBuilder(sw).html { body { div name } } sw.toString()}
Statiquement compilé
Mixer compilation statique et code dynamique@CompileStaticString greeting(String name) { // call method with dynamic behavior // but with proper signature generateMarkup(name.toUpperCase())} // usual dynamic behaviorString generateMarkup(String name) { def sw = new StringWriter() new MarkupBuilder(sw).html { body { div name } } sw.toString()}
Statiquement compilé
Dynamique
Mixer compilation statique et code dynamique@CompileStaticString greeting(String name) { // call method with dynamic behavior // but with proper signature generateMarkup(name.toUpperCase())} // usual dynamic behaviorString generateMarkup(String name) { def sw = new StringWriter() new MarkupBuilder(sw).html { body { div name } } sw.toString()}
Statiquement compilé
Dynamique
Appel d’une méthode au
contenu dynamique
Mixer compilation statique et code dynamique@CompileStaticString greeting(String name) { // call method with dynamic behavior // but with proper signature generateMarkup(name.toUpperCase())} // usual dynamic behaviorString generateMarkup(String name) { def sw = new StringWriter() new MarkupBuilder(sw).html { body { div name } } sw.toString()}
Statiquement compilé
Dynamique
Appel d’une méthode au
contenu dynamique
La signature d’une méthode est un
contrat !
Et la performance dans tout ça ?
• Comparaisons entre :
• Java
• Groovy• avec compilation statique — Groovy 2.0• avec optimisations types primitifs — Groovy 1.8+• sans optimisation — Groovy 1.7
Et la performance dans tout ça ?
Fibonacci Pi (π) quadrature
Binarytrees
Java
Staticcompilation
Primitive optimizations
No prim.optimizations
191 ms 97 ms 3.6 s
197 ms 101 ms 4.3 s
360 ms 111 ms 23.7 s
2590 ms 3220 ms 50.0 s1.7
1.8
2.x
...maintenantGroovy 2.1
Support complet d’invoke dynamicMéta-annotationsConfiguration avancée du compilateurExtensions du type checker
Invoke Dynamic
Support complet de Invoke Dynamic
Support complet d’invoke dynamic
• Dans Groovy 2.0, tous les appels de méthode ne passaient pas par « indy »
• seulement les appels de méthodes normals• utilisation conjointe du « call site caching »
• Sur JDK 7, avec le JAR « indy », Groovy 2.1 utilise « invoke dynamic » partout
• Sur JDK < 7, encore du « call site caching »
Méta-annotations
Un annotation pour les gouverner toutes !
Méta-annotations
• Créer des méta-annotations qui combinent et / ou paramétrisent d’autres annotations
• Et qui fonctionnent avec les annotations des transformations d’AST
Méta-annotations
@Immutable@ToString(excludes = ["age"])@AnnotationCollector@interface MyAlias {}
Méta-annotations
@Immutable@ToString(excludes = ["age"])@AnnotationCollector@interface MyAlias {}
Annotations collectées
Méta-annotations
@Immutable@ToString(excludes = ["age"])@AnnotationCollector@interface MyAlias {}
Annotations collectées
Le collecteur
Méta-annotations
@Immutable@ToString(excludes = ["age"])@AnnotationCollector@interface MyAlias {}
Annotations collectées
Le collecteur
Votre propre alias d’annotation
Méta-annotations
@Immutable@ToString(excludes = ["age"])@AnnotationCollector@interface MyAlias {}
@MyAliasclass Foo { String name int age}
Annotations collectées
Le collecteur
Votre propre alias d’annotation
Méta-annotations
@Immutable@ToString(excludes = ["age"])@AnnotationCollector@interface MyAlias {}
@MyAliasclass Foo { String name int age}
Annotations collectées
Le collecteur
Votre propre alias d’annotation
Utilisez votre méta-annotation
L’annotation@DelegatesTo
Améliorer l’outillage pour le support des
Domain-Specific Languages
Annotation @DelegatesTo
• La vérification statique fonctionne bien avec certains Domain-Specific Languages
• « command chains », méthodes d’extension...
• Mais pas pour les DSLs utilisant des closures et de la délégation d’appel
• souvent utilisé dans les DSLs comme Gradle
task copyTask(type: Copy) { from 'src/main/webapp' into 'build/explodedWar'}
Annotation @DelegatesTo
exec(spec) { foo()}
Annotation @DelegatesToclass ExecSpec { void foo()}
exec(spec) { foo()}
Annotation @DelegatesToclass ExecSpec { void foo()}
void exec(ExecSpec sp, Closure c) { c.delegate = sp c()}
exec(spec) { foo()}
Annotation @DelegatesToclass ExecSpec { void foo()}
void exec(ExecSpec sp, Closure c) { c.delegate = sp c()}
exec(spec) { foo()}
Le vérificateur statique ne sait rien de la méthode foo()
Annotation @DelegatesToclass ExecSpec { void foo()}
void exec(ExecSpec sp, Closure c) { c.delegate = sp c()}
exec(spec) { foo()}
Annoter avec @DelegatesTo(ExecSpec)
Le vérificateur statique ne sait rien de la méthode foo()
Annotation @DelegatesTo
• Avec une autre stratégie de délégation
void exec(ExecSpec sp, Closure c) { c.delegate = sp c.resolveStrategy = DELEGATE_FIRST c()}
Annotation @DelegatesTo
• Avec une autre stratégie de délégation
void exec(ExecSpec sp, Closure c) { c.delegate = sp c.resolveStrategy = DELEGATE_FIRST c()}
Annoter avec@DelegatesTo(value = ExecSpec,
strategy = DELEGATE_FIRST)
Annotation @DelegatesTo
• Utiliser Target pour préciser à qui déléguer
void exec(ExecSpec sp, Closure c) { c.delegate = sp c()}
Annotation @DelegatesTo
• Utiliser Target pour préciser à qui déléguer
void exec(ExecSpec sp, Closure c) { c.delegate = sp c()}
@DelegatesTo.Target(‘‘id’’)
Annotation @DelegatesTo
• Utiliser Target pour préciser à qui déléguer
void exec(ExecSpec sp, Closure c) { c.delegate = sp c()}
@DelegatesTo.Target(‘‘id’’) @DelegatesTo(target = ‘‘id’’)
Annotation @DelegatesTo
• Intéressant surtout pour les DSLs utilisation la délégation d’appel dans les closures
• Excellent pour...• documenter les APIs• l’intégration avec l’IDE• complétion de code, navigation...
• fonctionne avec la vérification statique et la compilation statique
Etendre le vérificateur
Pour aller plus loin que Java lui même
Etendre le vérificateur statique de type
• Etendre le vérificateur pour le rendre encore plus intelligent !
• voire même plus intelligent que celui de Java :-)
• En créant sa propre extension
@TypeChecked(extensions = 'MyExtension.groovy')void exec() { // code to be further checked...}
Etendre le vérificateur statique de type
• Etendre le vérificateur pour le rendre encore plus intelligent !
• voire même plus intelligent que celui de Java :-)
• En créant sa propre extension
@TypeChecked(extensions = 'MyExtension.groovy')void exec() { // code to be further checked...}
On pourra créer une méta-annotation
• Aider le vérificateur lorsque...
• impossible d’inférer un type
• aucune méthode trouvée
• pas d’attribut trouvé
• assignation incorrecte
Etendre le vérificateur statique de type
• Votre extension a accès à une API orientée événement
Etendre le vérificateur statique de type
• onMethodSelection
• afterMethodCall• beforeMethodCall
• afterVisitMethod• beforeVisitMethod• methodNotFound
• unresolvedVariable• unresolvedProperty• unresolvedAttribute
• incompatibleAssignment
Etendre le vérificateur statique de type
onMethodSelection { expr, method -‐> ... }afterMethodCall { mc -‐> ... }unresolvedVariable { var -‐> ... }methodNotFound { receiver, name, argList, argTypes, call -‐> ... }incompatibleAssignment { lhsType, rhsType, expr -‐> ... }
Etendre le vérificateur statique de type
onMethodSelection { expr, method -‐> ... }afterMethodCall { mc -‐> ... }unresolvedVariable { var -‐> ... }methodNotFound { receiver, name, argList, argTypes, call -‐> ... }incompatibleAssignment { lhsType, rhsType, expr -‐> ... }
MyExtension.groovy
Etendre le vérificateur statique de type
onMethodSelection { expr, method -‐> ... }afterMethodCall { mc -‐> ... }unresolvedVariable { var -‐> ... }methodNotFound { receiver, name, argList, argTypes, call -‐> ... }incompatibleAssignment { lhsType, rhsType, expr -‐> ... }
MyExtension.groovy
Apprenez votre AST Groovy !
Etendre le vérificateur statique de type
onMethodSelection { expr, method -‐> ... }afterMethodCall { mc -‐> ... }unresolvedVariable { var -‐> ... }methodNotFound { receiver, name, argList, argTypes, call -‐> ... }incompatibleAssignment { lhsType, rhsType, expr -‐> ... }
MyExtension.groovy
Apprenez votre AST Groovy !
Pas besoin d’être compilé
• Quelques exemples...
• Vérifier qu’une chaîne représentant une requête SQL est valide
• Vérifier le type des arguments passés à sprintf() avec le pattern de la chaîne
Etendre le vérificateur statique de type
Configurer le compilateur
Classe de script de baseScript de configuration
DSL de configuration
Customiser le compilateur
• Groovy 1.8 a introduit la notion de « customizer »
• rajouter des imports transparents• appliquer des transformations d’AST• filtrer / sécuriser les scripts
• Avec le « static type checker » et la « compilation statique », on nous a demandé s’il était possible de les appliquer par défaut
Customiser le compilateur
• Nouvelles options
• --basescript pour définir une classe de base pour les scripts
• --configscript pour indiquer un script qui va configurer CompilerConfiguration
Customiser le compilateur
• Rajouter la transformation @ToString
•import groovy.transform.ToStringimport org.codehaus.groovy.control.customizers .ASTTransformationCustomizer
configuration.addCompilationCustomizer( new ASTTransformationCustomizer(ToString))
Customiser le compilateur
• Rajouter la transformation @ToString
•import groovy.transform.ToStringimport org.codehaus.groovy.control.customizers .ASTTransformationCustomizer
configuration.addCompilationCustomizer( new ASTTransformationCustomizer(ToString))
Instance de CompilerConfigurationinjectée par défaut
Customiser le compilateur
• Un petit DSL pour simplifier la configurationconfiguration.customizers { // apply to MyBean.groovy source(basename: 'MyBean') { ast(ToString) }}
Customiser le compilateur
• Un petit DSL pour simplifier la configurationconfiguration.customizers { // apply to MyBean.groovy source(basename: 'MyBean') { ast(ToString) }}
configuration.customizers { // apply to *.gbean files source(extension: '.gbean') { ast(ToString) }}
Customiser le compilateur
• Un petit DSL pour simplifier la configurationconfiguration.customizers { // apply to MyBean.groovy source(basename: 'MyBean') { ast(ToString) }}
configuration.customizers { // apply to *.gbean files source(extension: '.gbean') { ast(ToString) }}
configuration.customizers { // custom filter logic source(unitValidator: { unit -‐> ... }) { ast(ToString) imports { staticStar 'java.lang.Math' } }}
Pour en savoir plus...Groovy 2.0http://groovy.codehaus.org/Groovy+2.0+release+notes
Groovy 2.1http://groovy.codehaus.org/Groovy+2.1+release+notes
Et après ?Groovy 3 !
Nouveau « MOP »Nouvelle grammaire Antlr v4Support des lambdas de Java 8
Parlons un peu de roadmap...
2014 2014 20132012
Groovy 2.1
Groovy 3.0Groovy 2.0
Parlons un peu de roadmap...
2014 2014 20132012
Groovy 2.1
Groovy 3.0Groovy 2.0
Parlons un peu de roadmap...
2014 2014 20132012
Groovy 2.1
Groovy 3.0Groovy 2.0
MOP
2
GrammaireAntlr 4
λLambdas
JDK 8
Conclusion — 1/2
• Un écosystème riche et fleurissant
• Groovy 2.0• plus de modularité• un thème « statique »• vérification statique de type• compilation statique
• un thème JDK 7• support de invoke dynamic• syntaxe project coin
Conclusion — 2/2
• Groovy 2.1• support complet de invoke dynamic• @DelegatesTo• extension du type checker pour les DSLSs• méta-annotations
• Et au-delà... • un nouveau MOP (Meta-Object Protocol)• une nouvelle grammaire avec Antlr v4• le support des lambdas de JDK 8
Questions & Réponses
N’oubliez pas l’atelier...
Groovy, les mains dans le cambouis
14h30 — 16h00 / Salle Dijkstra
Merci ! @glaforge
http://glaforge.appspot.com http://gplus.to/glaforge
Crédits images• cerisier
http://wallpaperswide.com/cherry_blossom_3-wallpapers.html
• NKOTBhttp://images1.fanpop.com/images/photos/2300000/nkotb-new-kids-on-the-block-2314664-1280-960.jpg
• tomateshttp://www.infoescola.com/wp-content/uploads/2011/01/tomate.jpg
• patateshttp://toooof.free.fr/blogs/captainslip/screenshots/pommes_de_terre.jpg
• canardhttp://www.objets-publicitaires-pro.com/images/objet-publicitaire/produit/large/canard-geant-a-personnaliser-jaune.jpg
• grincheuxhttps://si0.twimg.com/profile_images/3115998027/b47c180a703a5ffa7d1437a66f545dc0.jpeg
• singehttp://static.ddmcdn.com/gif/how-to-draw-animals-31.jpg
• warninghttp://th07.deviantart.net/fs71/PRE/i/2012/261/8/6/warning_gangnam_style_zone_by_untoucheddesigns-d5f6bal.png
• coyotehttp://nittygriddy.com/wp-content/uploads/2011/01/Wiley-Coyote-Help.jpg
• ringhttp://img.banggood.com/images/upload/2012/limin/SKU028431_11.JPG
• magnifying glasshttp://www.renders-graphiques.fr/image/upload/normal/loupe.png
• chronomètrehttp://www.moineau-instruments.com/59-thickbox/chronometre-mecanique-1-10-t15-mn-2-fonctions.jpg
• that’s all folkshttp://4.bp.blogspot.com/-wJxosualm48/T4M_spcUUjI/AAAAAAAAB8E/njfLjNZQdsc/s1600/thats-all-folks.jpg
• MOPhttp://imagethumbnails.milo.com/024/913/894/trimmed/24913521_25989894_trimmed.jpg
• grammarhttp://edudemic.com/wp-content/uploads/2012/11/connected-learner-grammar.jpg