Share
Les nouveautés de Groovy 2
Fort de ses 1.7 millions de téléchargements l'an passé, Groovy continue son bonhomme de chemin en tête parmi les langages de programmation alternatifs pour la JVM.
Groovy 2.0, sorti l'an passé, introduisait dans son offre de la modularité, le support de JDK 7 au niveau syntaxique avec "Project Coin" autant qu'au niveau JVM avec l'utilisation d'"invoke dynamic", et proposait des fonctionnalités de typage et de compilation statique.
Groovy 2.1, quant à lui, s'appuie sur ces bases pour compléter le support d'"invoke dynamic" pour plus de performances. Il propose des améliorations permettant de documenter, d'aider les IDEs, et de vérifier statiquement les Domain-Specific Languages construits avec Groovy. Vous pourrez créer des méta-annotations regroupant d'autres annotations, pour éviter l'annotation "hell". Et enfin, vous irez encore plus loin dans la customisation du compilateur !
Accrochez votre ceinture, paré au décollage !
Guillaume Laforge
Transcript
149 slides
-
Les nouveautés de Groovy 2 Guillaume Laforge Groovy Project Manager
SpringSource / VMware -
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 Modularity Java 7: Project Coin &
invoke dynamic Static 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 -
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 = stringExtensions moduleVersion = 1.0 // liste de noms de classe séparées par des virgules extensionClasses = foo.StringExtension // liste de noms de classe séparées par des virgules staticExtensionClasses = foo.StaticStringExtension -
Thème Java 7 Syntaxe de « Project Coin » Support
d’invoke dynamic -
Littéraux binaires • En plus de décimal, octal, et héxa...
• On a une représentation binaire : int x = 0b10101111 assert x == 175 byte aByte = 0b00100001 assert aByte == 33 int anInt = 0b1010000101000101 assert anInt == 41285 -
Les « underscores » dans les littéraux • Utilisation des
« underscores » pour séparer les unités au choix long creditCardNumber = 1234_5678_9012_3456L long socialSecurityNumbers = 999_99_9999L float monetaryAmount = 12_345_132.12 long hexBytes = 0xFF_EC_DE_5E long hexWords = 0xFFEC_DE5E long maxLong = 0x7fff_ffff_ffff_ffffL long alsoMaxLong = 9_223_372_036_854_775_807L long bytes = 0b11010010_01101001_10010100_10010010 -
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 */ } -
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 -
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 ! 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 = 0 i += '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 = 0 i += '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 = 0 i += '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 = 0 i += '1' Erreurs de compilation Erreurs de compilation Erreurs de compilation -
Mauvais type de retour // checks if/else branch return values
@TypeChecked int method() { if (true) { 'String' } else { 42 } } // works for switch/case & try/catch/finally // transparent toString() implied @TypeChecked String greeting(String name) { def sb = new StringBuilder() sb << "Hi " << name } -
Mauvais type de retour // checks if/else branch return values
@TypeChecked int method() { if (true) { 'String' } else { 42 } } // works for switch/case & try/catch/finally // transparent toString() implied @TypeChecked String greeting(String name) { def sb = new StringBuilder() sb << "Hi " << name } Erreur de compilation -
Mauvais type de retour // checks if/else branch return values
@TypeChecked int method() { if (true) { 'String' } else { 42 } } // works for switch/case & try/catch/finally // transparent toString() implied @TypeChecked String 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é @TypeChecked String greeting(String name) {
// call method with dynamic behavior // but with proper signature generateMarkup(name.toUpperCase()) } // usual dynamic behavior String generateMarkup(String name) { def sw = new StringWriter() new MarkupBuilder(sw).html { body { div name } } sw.toString() } -
Mélanger dynamique et statiquement vérifié @TypeChecked String greeting(String name) {
// call method with dynamic behavior // but with proper signature generateMarkup(name.toUpperCase()) } // usual dynamic behavior String generateMarkup(String name) { def sw = new StringWriter() new MarkupBuilder(sw).html { body { div name } } sw.toString() } Statiquement vérifié -
Mélanger dynamique et statiquement vérifié @TypeChecked String greeting(String name) {
// call method with dynamic behavior // but with proper signature generateMarkup(name.toUpperCase()) } // usual dynamic behavior String generateMarkup(String name) { def sw = new StringWriter() new MarkupBuilder(sw).html { body { div name } } sw.toString() } 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 ! } -
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 interdit Mé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 ! -
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 -
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 @CompileStatic String greeting(String name)
{ // call method with dynamic behavior // but with proper signature generateMarkup(name.toUpperCase()) } // usual dynamic behavior String generateMarkup(String name) { def sw = new StringWriter() new MarkupBuilder(sw).html { body { div name } } sw.toString() } -
Mixer compilation statique et code dynamique @CompileStatic String greeting(String name)
{ // call method with dynamic behavior // but with proper signature generateMarkup(name.toUpperCase()) } // usual dynamic behavior String generateMarkup(String name) { def sw = new StringWriter() new MarkupBuilder(sw).html { body { div name } } sw.toString() } Statiquement compilé -
Mixer compilation statique et code dynamique @CompileStatic String greeting(String name)
{ // call method with dynamic behavior // but with proper signature generateMarkup(name.toUpperCase()) } // usual dynamic behavior String generateMarkup(String name) { def sw = new StringWriter() new MarkupBuilder(sw).html { body { div name } } sw.toString() } Statiquement compilé Dynamique -
Mixer compilation statique et code dynamique @CompileStatic String greeting(String name)
{ // call method with dynamic behavior // but with proper signature generateMarkup(name.toUpperCase()) } // usual dynamic behavior String generateMarkup(String name) { def sw = new StringWriter() new MarkupBuilder(sw).html { body { div name } } sw.toString() } Statiquement compilé Dynamique Appel d’une méthode au contenu dynamique -
Mixer compilation statique et code dynamique @CompileStatic String greeting(String name)
{ // call method with dynamic behavior // but with proper signature generateMarkup(name.toUpperCase()) } // usual dynamic behavior String generateMarkup(String name) { def sw = new StringWriter() new MarkupBuilder(sw).html { body { div name } } sw.toString() } 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 Binary trees Java Static compilation 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 s 1.7 1.8 2.x -
...maintenant Groovy 2.1 Support complet d’invoke dynamic Méta-annotations Configuration avancée
du compilateur Extensions du type checker -
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 • 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 {} Annotations
collectées Le collecteur Votre propre alias d’annotation -
Méta-annotations @Immutable @ToString(excludes = ["age"]) @AnnotationCollector @interface MyAlias {} @MyAlias
class 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 {} @MyAlias
class Foo { String name int age } Annotations collectées Le collecteur Votre propre alias d’annotation Utilisez votre méta-annotation -
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 class ExecSpec { void foo()
} exec(spec) { foo() } -
Annotation @DelegatesTo class ExecSpec { void foo()
} void exec(ExecSpec sp, Closure c) { c.delegate = sp c() } exec(spec) { foo() } -
Annotation @DelegatesTo class 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 @DelegatesTo class 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 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 base Script 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.ToString import org.codehaus.groovy.control.customizers .ASTTransformationCustomizer configuration.addCompilationCustomizer( new ASTTransformationCustomizer(ToString) ) -
Customiser le compilateur • Rajouter la transformation @ToString • import
groovy.transform.ToString import org.codehaus.groovy.control.customizers .ASTTransformationCustomizer configuration.addCompilationCustomizer( new ASTTransformationCustomizer(ToString) ) Instance de CompilerConfiguration injectée par défaut -
Customiser le compilateur • Un petit DSL pour simplifier la
configuration configuration.customizers { // apply to MyBean.groovy source(basename: 'MyBean') { ast(ToString) } } -
Customiser le compilateur • Un petit DSL pour simplifier la
configuration configuration.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
configuration configuration.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' } } } -
Et après ? Groovy 3 ! Nouveau « MOP »
Nouvelle grammaire Antlr v4 Support des lambdas de Java 8 -
Parlons un peu de roadmap... 2014 2014 2013 2012 Groovy
2.1 Groovy 3.0 Groovy 2.0 -
Parlons un peu de roadmap... 2014 2014 2013 2012 Groovy
2.1 Groovy 3.0 Groovy 2.0 -
Parlons un peu de roadmap... 2014 2014 2013 2012 Groovy
2.1 Groovy 3.0 Groovy 2.0 -
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 -
N’oubliez pas l’atelier... Groovy, les mains dans le cambouis 14h30
— 16h00 / Salle Dijkstra -
Crédits images • cerisier http://wallpaperswide.com/cherry_blossom_3-wallpapers.html • NKOTB http://images1.fanpop.com/images/photos/2300000/nkotb-new-kids-on-the-block-2314664-1280-960.jpg • tomates
http://www.infoescola.com/wp-content/uploads/2011/01/tomate.jpg • patates http://toooof.free.fr/blogs/captainslip/screenshots/pommes_de_terre.jpg • canard http://www.objets-publicitaires-pro.com/images/objet-publicitaire/produit/large/canard-geant-a-personnaliser-jaune.jpg • grincheux https://si0.twimg.com/profile_images/3115998027/b47c180a703a5ffa7d1437a66f545dc0.jpeg • singe http://static.ddmcdn.com/gif/how-to-draw-animals-31.jpg • warning http://th07.deviantart.net/fs71/PRE/i/2012/261/8/6/warning_gangnam_style_zone_by_untoucheddesigns-d5f6bal.png • coyote http://nittygriddy.com/wp-content/uploads/2011/01/Wiley-Coyote-Help.jpg • ring http://img.banggood.com/images/upload/2012/limin/SKU028431_11.JPG • magnifying glass http://www.renders-graphiques.fr/image/upload/normal/loupe.png • chronomètre http://www.moineau-instruments.com/59-thickbox/chronometre-mecanique-1-10-t15-mn-2-fonctions.jpg • that’s all folks http://4.bp.blogspot.com/-wJxosualm48/T4M_spcUUjI/AAAAAAAAB8E/njfLjNZQdsc/s1600/thats-all-folks.jpg • MOP http://imagethumbnails.milo.com/024/913/894/trimmed/24913521_25989894_trimmed.jpg • grammar http://edudemic.com/wp-content/uploads/2012/11/connected-learner-grammar.jpg