Les nouveautés
de Groovy 2
GuillaumeLaforge
Groovy Project Manager
SpringSource / VMware
GuillaumeLaforge
@glaforge 
http://glaforge.appspot.com 
http://gplus.to/glaforge 
Langage dynamique
optionnellement typé
Groovy
...statiquement vérifié
et compilé
Groovy
syntaxe dérivant de Java :
facile à apprendre !
Groovy
1.7 million
downloads
Ablossoming
Ecosystem
GVM
GVM
GVM
GROOVY
ENVIRONMENT
MANAGER
GVM:GroovyenVironmentManager
• 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 Groovy2.0
Modularity
Java 7: ProjectCoin & invokedynamic
Static typechecking & compilation
Modularité
« Tout le monde n’a pas besoin de tout,
tout le temps, en même temps ! »
LamodularitédeGroovy
• 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
LesnouveauxJARs
• 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
LesnouveauxJARs
• 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é »
Lesmodulesd’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")
Lesmodulesd’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
Lesmodulesd’extension
• Créer sa propre extension
• contribuer des méthodes statiques
package	
  foo
class	
  StaticStringExtension	
  {
	
  	
  	
  	
  static	
  hi(String	
  self)	
  {
	
  	
  	
  	
  	
  	
  	
  	
  "Hi!"
	
  	
  	
  	
  }
}
//	
  usage:	
  String.hi()
Descripteurdesmodulesd’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
Une histoire de
canard...
Littérauxbinaires
• 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»dansleslitté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
Catchd’exceptionsmultiples
• Un seul bloc catch pour plusieurs
exceptions, plutôt que dupliquer les blocs
try	
  {
	
  	
  	
  	
  /*	
  ...	
  */
}	
  catch(IOException	
  |	
  NullPointerException	
  e)	
  {
	
  	
  	
  	
  /*	
  un	
  seul	
  bloc	
  */
}
Coin-Coin !
Supportd’invokedynamicdeJDK7
• 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 type
Compilation statique
Vérificationstatiquesdetype
• 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érificationstatiquedetype
• 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érificationstatiquedetype
• Le compilateur doit inférer les types...
• moins besoin de types explicites et de casts
• inférence fine
• « flow typing »
• « lowest upper bound »
Vérificationstatiquedetype
• 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
Fautesdefrappe
import	
  groovy.transform.TypeChecked
	
  
void	
  method()	
  {}
	
  
@TypeChecked	
  test()	
  {
	
  	
  	
  	
  //	
  Cannot	
  find	
  matching	
  method	
  metthhoood()
	
  	
  	
  	
  metthhoood()
	
  
	
  	
  	
  	
  def	
  name	
  =	
  "Guillaume"
	
  	
  	
  	
  //	
  variable	
  naamme	
  is	
  undeclared
	
  	
  	
  	
  println	
  naamme
}
Fautesdefrappe
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
Fautesdefrappe
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
Fautesdefrappe
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
Mauvaisesaffectationsdevariable
//	
  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'
Mauvaisesaffectationsdevariable
//	
  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
Mauvaisesaffectationsdevariable
//	
  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
Mauvaisesaffectationsdevariable
//	
  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
Mauvaistypederetour
//	
  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
}
Mauvaistypederetour
//	
  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
Mauvaistypederetour
//	
  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érencedetype
@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érencedetype
@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érencedetype
@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érencedetype
@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érencedetype
@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élangerdynamiqueetstatiquementvé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élangerdynamiqueetstatiquementvé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élangerdynamiqueetstatiquementvé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érificationsparinstanceof
@TypeChecked	
  
void	
  test(Object	
  val)	
  {
	
  	
  	
  	
  if	
  (val	
  instanceof	
  String)	
  {
	
  	
  	
  	
  	
  	
  	
  	
  println	
  val.toUpperCase()
	
  	
  	
  	
  }	
  else	
  if	
  (val	
  instanceof	
  Number)	
  {
	
  	
  	
  	
  	
  	
  	
  	
  println	
  "X"	
  *	
  val.intValue()
	
  	
  	
  	
  }
}
Vérificationsparinstanceof
@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érificationsparinstanceof
@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érificationsparinstanceof
@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)
LowestUpperBound
• Le plus petit « super » type commun
• peut-être virtuel (« non-dénotable »)
@TypeChecked	
  test()	
  {
	
  	
  	
  	
  //	
  an	
  integer	
  and	
  a	
  BigDecimal
	
  	
  	
  	
  return	
  [1234,	
  3.14]
}
LowestUpperBound
• 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>
Flowtyping
• 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érificationstatiqueetcodedynamique
• 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
Pasdemétaprogrammationdynamique
@TypeChecked	
  
void	
  test()	
  {
	
  	
  	
  	
  Integer.metaClass.foo	
  =	
  {}
	
  	
  	
  	
  123.foo()
}
Pasdemétaprogrammationdynamique
@TypeChecked	
  
void	
  test()	
  {
	
  	
  	
  	
  Integer.metaClass.foo	
  =	
  {}
	
  	
  	
  	
  123.foo()
}
Accès au champ
dynamique
metaClass interdit
Pasdemétaprogrammationdynamique
@TypeChecked	
  
void	
  test()	
  {
	
  	
  	
  	
  Integer.metaClass.foo	
  =	
  {}
	
  	
  	
  	
  123.foo()
}
Accès au champ
dynamique
metaClass interditMéthode non
reconnue
Typeexplicitepourlesparamètresdeclosure
@TypeChecked	
  test()	
  {
	
  	
  	
  	
  ["a",	
  "b",	
  "c"].collect	
  {
	
  	
  	
  	
  	
  	
  	
  	
  it.toUpperCase()	
  //	
  Pas	
  d’accord	
  !
	
  	
  	
  	
  }
}
Typeexplicitepourlesparamètresdeclosure
@TypeChecked	
  test()	
  {
	
  	
  	
  	
  ["a",	
  "b",	
  "c"].collect	
  {	
  String	
  it	
  -­‐>
	
  	
  	
  	
  	
  	
  	
  	
  it.toUpperCase()	
  //	
  OK,	
  une	
  String
	
  	
  	
  	
  }
}
Typeexplicitepourlesparamètresdeclosure
@TypeChecked	
  test()	
  {
	
  	
  	
  	
  ["a",	
  "b",	
  "c"].collect	
  {	
  String	
  it	
  -­‐>
	
  	
  	
  	
  	
  	
  	
  	
  it.toUpperCase()	
  //	
  OK,	
  une	
  String
	
  	
  	
  	
  }
}
Obligé d’indiquer le
type explicitement
Typeexplicitepourlesparamètresdeclosure
@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 !
Compilationstatique
• 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
Avantagesdelacompilationstatique
• 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énientsdelacompilationstatique
• 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
Mixercompilationstatiqueetcodedynamique
@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()
}
Mixercompilationstatiqueetcodedynamique
@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é
Mixercompilationstatiqueetcodedynamique
@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
Mixercompilationstatiqueetcodedynamique
@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
Mixercompilationstatiqueetcodedynamique
@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 !
Etlaperformancedanstoutça?
• Comparaisons entre :
• Java
• Groovy
• avec compilation statique — Groovy 2.0
• avec optimisations types primitifs — Groovy 1.8+
• sans optimisation — Groovy 1.7
Etlaperformancedanstoutç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.71.82.x
...maintenant
Groovy2.1
Support complet d’invoke dynamic
Méta-annotations
Configuration avancée du compilateur
Extensions du typechecker
Invoke Dynamic
Support complet
de Invoke Dynamic
Supportcompletd’invokedynamic
• 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	
  {}
@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
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@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
Pour aller plus loin
que Java lui même
Etendrelevérificateurstatiquedetype
• 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...
}
Etendrelevérificateurstatiquedetype
• 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
Etendrelevérificateurstatiquedetype
• Votre extension a accès à
une API orientée événement
Etendrelevérificateurstatiquedetype
• onMethodSelection
• afterMethodCall
• beforeMethodCall
• afterVisitMethod
• beforeVisitMethod
• methodNotFound
• unresolvedVariable
• unresolvedProperty
• unresolvedAttribute
• incompatibleAssignment
Etendrelevérificateurstatiquedetype
onMethodSelection	
  {	
  expr,	
  method	
  -­‐>	
  ...	
  }
afterMethodCall	
  {	
  mc	
  -­‐>	
  ...	
  }
unresolvedVariable	
  {	
  var	
  -­‐>	
  ...	
  }
methodNotFound	
  {	
  receiver,	
  name,	
  argList,	
  argTypes,	
  call	
  -­‐>	
  ...	
  }
incompatibleAssignment	
  {	
  lhsType,	
  rhsType,	
  expr	
  -­‐>	
  ...	
  }
Etendrelevérificateurstatiquedetype
onMethodSelection	
  {	
  expr,	
  method	
  -­‐>	
  ...	
  }
afterMethodCall	
  {	
  mc	
  -­‐>	
  ...	
  }
unresolvedVariable	
  {	
  var	
  -­‐>	
  ...	
  }
methodNotFound	
  {	
  receiver,	
  name,	
  argList,	
  argTypes,	
  call	
  -­‐>	
  ...	
  }
incompatibleAssignment	
  {	
  lhsType,	
  rhsType,	
  expr	
  -­‐>	
  ...	
  }
MyExtension.groovy
Etendrelevérificateurstatiquedetype
onMethodSelection	
  {	
  expr,	
  method	
  -­‐>	
  ...	
  }
afterMethodCall	
  {	
  mc	
  -­‐>	
  ...	
  }
unresolvedVariable	
  {	
  var	
  -­‐>	
  ...	
  }
methodNotFound	
  {	
  receiver,	
  name,	
  argList,	
  argTypes,	
  call	
  -­‐>	
  ...	
  }
incompatibleAssignment	
  {	
  lhsType,	
  rhsType,	
  expr	
  -­‐>	
  ...	
  }
MyExtension.groovy
Apprenez votre
AST Groovy !
Etendrelevérificateurstatiquedetype
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
Etendrelevérificateurstatiquedetype
Configurer le
compilateur
Classe de script de base
Script de configuration
DSL de configuration
Customiserlecompilateur
• 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
Customiserlecompilateur
• Nouvelles options
• --basescript
pour définir une classe de base pour les scripts
• --configscript
pour indiquer un script qui va configurer
CompilerConfiguration
Customiserlecompilateur
• Rajouter la transformation @ToString
•
import	
  groovy.transform.ToString
import	
  org.codehaus.groovy.control.customizers
	
  	
  	
  	
  	
  	
  	
  .ASTTransformationCustomizer
configuration.addCompilationCustomizer(
	
  	
  	
  	
  new	
  ASTTransformationCustomizer(ToString)
)
Customiserlecompilateur
• 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
Customiserlecompilateur
• Un petit DSL pour simplifier la configuration
configuration.customizers	
  {
	
  	
  	
  	
  //	
  apply	
  to	
  MyBean.groovy
	
  	
  	
  	
  source(basename:	
  'MyBean')	
  {
	
  	
  	
  	
  	
  	
  	
  	
  ast(ToString)
	
  	
  	
  	
  }
}
Customiserlecompilateur
• 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)
	
  	
  	
  	
  }
}
Customiserlecompilateur
• 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'
	
  	
  	
  	
  	
  	
  	
  	
  }
	
  	
  	
  	
  }
}
Pour en savoir plus...
Groovy2.0
http://groovy.codehaus.org/Groovy+2.0+release+notes
Groovy2.1
http://groovy.codehaus.org/Groovy+2.1+release+notes
Et après ?
Groovy3 !
Nouveau « MOP »
Nouvellegrammaire Antlr v4
Support des lambdasdeJava8
Parlonsunpeuderoadmap...
2014201420132012
Groovy 2.1
Groovy 3.0Groovy 2.0
Parlonsunpeuderoadmap...
2014201420132012
Groovy 2.1
Groovy 3.0Groovy 2.0
Parlonsunpeuderoadmap...
2014201420132012
Groovy 2.1
Groovy 3.0Groovy 2.0
MOP
2
Grammaire
Antlr4
λ
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,lesmainsdanslecambouis
14h30 — 16h00 / Salle Dijkstra
Merci!
@glaforge 
http://glaforge.appspot.com 
http://gplus.to/glaforge 
Créditsimages
• 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

Les nouveautés de Groovy 2 -- Mix-IT 2013

  • 2.
    Les nouveautés de Groovy2 GuillaumeLaforge Groovy Project Manager SpringSource / VMware
  • 3.
  • 4.
  • 5.
  • 6.
    syntaxe dérivant deJava : facile à apprendre ! Groovy
  • 7.
  • 8.
  • 13.
  • 15.
  • 16.
  • 17.
    GVM:GroovyenVironmentManager • Nouveau venudans 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
  • 18.
    Commençons par Groovy2.0 Modularity Java 7:ProjectCoin & invokedynamic Static typechecking & compilation
  • 19.
    Modularité « Tout lemonde n’a pas besoin de tout, tout le temps, en même temps ! »
  • 20.
    LamodularitédeGroovy • 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
  • 21.
    LesnouveauxJARs • Un JARprincipal plus petit 3 Mo • Modules – console – docgenerator – groovydoc – groovysh – ant – bsf – jsr-223 – jmx – sql – swing – servlet – templates – test – testng – json – xml
  • 22.
    LesnouveauxJARs • Un JARprincipal plus petit 3 Mo • Modules – console – docgenerator – groovydoc – groovysh – ant – bsf – jsr-223 – jmx – sql – swing – servlet – templates – test – testng – json – xml
  • 23.
  • 24.
    Lesmodulesd’extension • Créer sapropre 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")
  • 25.
    Lesmodulesd’extension • Créer sapropre 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
  • 26.
    Lesmodulesd’extension • Créer sapropre extension • contribuer des méthodes statiques package  foo class  StaticStringExtension  {        static  hi(String  self)  {                "Hi!"        } } //  usage:  String.hi()
  • 27.
    Descripteurdesmodulesd’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
  • 28.
    Thème Java 7 Syntaxede « Project Coin » Support d’invoke dynamic
  • 29.
  • 30.
    Littérauxbinaires • En plusde 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
  • 31.
    Les«underscores»dansleslitté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
  • 32.
    Catchd’exceptionsmultiples • Un seulbloc catch pour plusieurs exceptions, plutôt que dupliquer les blocs try  {        /*  ...  */ }  catch(IOException  |  NullPointerException  e)  {        /*  un  seul  bloc  */ }
  • 34.
  • 35.
    Supportd’invokedynamicdeJDK7 • 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
  • 36.
    Thème « statique» Vérification statique de type Compilation statique
  • 37.
    Vérificationstatiquesdetype • But :rendre le compilateur « grincheux » ! • jeter des erreurs à la compilation • et non pas au runtime !
  • 38.
    Tout le monden’a pas besoin de dynamique tout le temps !
  • 39.
    Tout le monden’a pas besoin de dynamique tout le temps ! Nah !
  • 40.
    Vérificationstatiquedetype • Le compilateurgrincheux 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
  • 41.
    Vérificationstatiquedetype • Le compilateurdoit inférer les types... • moins besoin de types explicites et de casts • inférence fine • « flow typing » • « lowest upper bound »
  • 42.
    Vérificationstatiquedetype • Mais lecompilateur doit comprendre les méthodes d’extension de Groovy • permet d’avoir un bon niveau de dynamisme malgré les restrictions supplémentaires
  • 43.
    Fautesdefrappe import  groovy.transform.TypeChecked   void  method()  {}   @TypeChecked  test()  {        //  Cannot  find  matching  method  metthhoood()        metthhoood()          def  name  =  "Guillaume"        //  variable  naamme  is  undeclared        println  naamme }
  • 44.
    Fautesdefrappe 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
  • 45.
    Fautesdefrappe 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
  • 46.
    Fautesdefrappe 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
  • 47.
    Mauvaisesaffectationsdevariable //  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'
  • 48.
    Mauvaisesaffectationsdevariable //  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
  • 49.
    Mauvaisesaffectationsdevariable //  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
  • 50.
    Mauvaisesaffectationsdevariable //  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
  • 51.
    Mauvaistypederetour //  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 }
  • 52.
    Mauvaistypederetour //  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
  • 53.
    Mauvaistypederetour //  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
  • 54.
    Inférencedetype @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        } }
  • 55.
    Inférencedetype @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
  • 56.
    Inférencedetype @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é
  • 57.
    Inférencedetype @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é
  • 58.
    Inférencedetype @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é
  • 59.
    Mélangerdynamiqueetstatiquementvé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() }
  • 60.
    Mélangerdynamiqueetstatiquementvé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é
  • 61.
    Mélangerdynamiqueetstatiquementvé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
  • 62.
    Vérificationsparinstanceof @TypeChecked   void  test(Object  val)  {        if  (val  instanceof  String)  {                println  val.toUpperCase()        }  else  if  (val  instanceof  Number)  {                println  "X"  *  val.intValue()        } }
  • 63.
    Vérificationsparinstanceof @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
  • 64.
    Vérificationsparinstanceof @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
  • 65.
    Vérificationsparinstanceof @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)
  • 66.
    LowestUpperBound • Le pluspetit « super » type commun • peut-être virtuel (« non-dénotable ») @TypeChecked  test()  {        //  an  integer  and  a  BigDecimal        return  [1234,  3.14] }
  • 67.
    LowestUpperBound • Le pluspetit « 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>
  • 68.
    Flowtyping • La vérificationstatique « 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  ! }
  • 69.
    Pô très cleanton code, non mais allô quoi ?
  • 70.
    Pô très cleanton code, non mais allô quoi ? Ben non !
  • 71.
    Vérificationstatiqueetcodedynamique • La vérificationstatique à 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
  • 72.
    Pasdemétaprogrammationdynamique @TypeChecked   void  test()  {        Integer.metaClass.foo  =  {}        123.foo() }
  • 73.
    Pasdemétaprogrammationdynamique @TypeChecked   void  test()  {        Integer.metaClass.foo  =  {}        123.foo() } Accès au champ dynamique metaClass interdit
  • 74.
    Pasdemétaprogrammationdynamique @TypeChecked   void  test()  {        Integer.metaClass.foo  =  {}        123.foo() } Accès au champ dynamique metaClass interditMéthode non reconnue
  • 75.
    Typeexplicitepourlesparamètresdeclosure @TypeChecked  test()  {        ["a",  "b",  "c"].collect  {                it.toUpperCase()  //  Pas  d’accord  !        } }
  • 76.
    Typeexplicitepourlesparamètresdeclosure @TypeChecked  test()  {        ["a",  "b",  "c"].collect  {  String  it  -­‐>                it.toUpperCase()  //  OK,  une  String        } }
  • 77.
    Typeexplicitepourlesparamètresdeclosure @TypeChecked  test()  {        ["a",  "b",  "c"].collect  {  String  it  -­‐>                it.toUpperCase()  //  OK,  une  String        } } Obligé d’indiquer le type explicitement
  • 78.
    Typeexplicitepourlesparamètresdeclosure @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 !
  • 79.
    Mais si c’estpô dynamique, on peut compiler statiquement ?
  • 80.
    Mais si c’estpô dynamique, on peut compiler statiquement ? Ben oui !
  • 81.
    Compilationstatique • 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
  • 82.
    Avantagesdelacompilationstatique • 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
  • 83.
  • 84.
  • 85.
    Inconvénientsdelacompilationstatique • On yperds... • 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
  • 86.
    Mixercompilationstatiqueetcodedynamique @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() }
  • 87.
    Mixercompilationstatiqueetcodedynamique @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é
  • 88.
    Mixercompilationstatiqueetcodedynamique @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
  • 89.
    Mixercompilationstatiqueetcodedynamique @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
  • 90.
    Mixercompilationstatiqueetcodedynamique @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 !
  • 91.
    Etlaperformancedanstoutça? • Comparaisons entre: • Java • Groovy • avec compilation statique — Groovy 2.0 • avec optimisations types primitifs — Groovy 1.8+ • sans optimisation — Groovy 1.7
  • 92.
  • 93.
    ...maintenant Groovy2.1 Support complet d’invokedynamic Méta-annotations Configuration avancée du compilateur Extensions du typechecker
  • 94.
  • 95.
    Supportcompletd’invokedynamic • Dans Groovy2.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 »
  • 96.
  • 97.
    Méta-annotations • Créer desméta-annotations qui combinent et / ou paramétrisent d’autres annotations • Et qui fonctionnent avec les annotations des transformations d’AST
  • 98.
  • 99.
  • 100.
  • 101.
    Méta-annotations @Immutable @ToString(excludes  =  ["age"]) @AnnotationCollector @interface  MyAlias  {} Annotations collectées Le collecteur Votre propre alias d’annotation
  • 102.
    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
  • 103.
    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
  • 104.
  • 105.
    Annotation@DelegatesTo • La vérificationstatique 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' }
  • 106.
  • 107.
    Annotation@DelegatesTo class  ExecSpec  {        void  foo() } exec(spec)  {        foo() }
  • 108.
    Annotation@DelegatesTo class  ExecSpec  {        void  foo() } void  exec(ExecSpec  sp,  Closure  c)  {        c.delegate  =  sp        c() } exec(spec)  {        foo() }
  • 109.
    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()
  • 110.
    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()
  • 111.
    Annotation@DelegatesTo • Avec uneautre stratégie de délégation void  exec(ExecSpec  sp,  Closure  c)  {        c.delegate  =  sp        c.resolveStrategy  =  DELEGATE_FIRST        c() }
  • 112.
    Annotation@DelegatesTo • Avec uneautre 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)
  • 113.
    Annotation@DelegatesTo • Utiliser Targetpour préciser à qui déléguer void  exec(ExecSpec  sp,  Closure  c)  {        c.delegate  =  sp        c() }
  • 114.
    Annotation@DelegatesTo • Utiliser Targetpour préciser à qui déléguer void  exec(ExecSpec  sp,  Closure  c)  {        c.delegate  =  sp        c() } @DelegatesTo.Target(‘‘id’’)
  • 115.
    Annotation@DelegatesTo • Utiliser Targetpour préciser à qui déléguer void  exec(ExecSpec  sp,  Closure  c)  {        c.delegate  =  sp        c() } @DelegatesTo.Target(‘‘id’’) @DelegatesTo(target = ‘‘id’’)
  • 116.
    Annotation@DelegatesTo • Intéressant surtoutpour 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
  • 117.
    Etendre le vérificateur Pour allerplus loin que Java lui même
  • 118.
    Etendrelevérificateurstatiquedetype • Etendre levé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... }
  • 119.
    Etendrelevérificateurstatiquedetype • Etendre levé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
  • 120.
    • Aider levérificateur lorsque... • impossible d’inférer un type • aucune méthode trouvée • pas d’attribut trouvé • assignation incorrecte Etendrelevérificateurstatiquedetype
  • 121.
    • Votre extensiona accès à une API orientée événement Etendrelevérificateurstatiquedetype • onMethodSelection • afterMethodCall • beforeMethodCall • afterVisitMethod • beforeVisitMethod • methodNotFound • unresolvedVariable • unresolvedProperty • unresolvedAttribute • incompatibleAssignment
  • 122.
    Etendrelevérificateurstatiquedetype onMethodSelection  {  expr,  method  -­‐>  ...  } afterMethodCall  {  mc  -­‐>  ...  } unresolvedVariable  {  var  -­‐>  ...  } methodNotFound  {  receiver,  name,  argList,  argTypes,  call  -­‐>  ...  } incompatibleAssignment  {  lhsType,  rhsType,  expr  -­‐>  ...  }
  • 123.
    Etendrelevérificateurstatiquedetype onMethodSelection  {  expr,  method  -­‐>  ...  } afterMethodCall  {  mc  -­‐>  ...  } unresolvedVariable  {  var  -­‐>  ...  } methodNotFound  {  receiver,  name,  argList,  argTypes,  call  -­‐>  ...  } incompatibleAssignment  {  lhsType,  rhsType,  expr  -­‐>  ...  } MyExtension.groovy
  • 124.
    Etendrelevérificateurstatiquedetype onMethodSelection  {  expr,  method  -­‐>  ...  } afterMethodCall  {  mc  -­‐>  ...  } unresolvedVariable  {  var  -­‐>  ...  } methodNotFound  {  receiver,  name,  argList,  argTypes,  call  -­‐>  ...  } incompatibleAssignment  {  lhsType,  rhsType,  expr  -­‐>  ...  } MyExtension.groovy Apprenez votre AST Groovy !
  • 125.
    Etendrelevérificateurstatiquedetype 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é
  • 126.
    • 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 Etendrelevérificateurstatiquedetype
  • 127.
    Configurer le compilateur Classe descript de base Script de configuration DSL de configuration
  • 128.
    Customiserlecompilateur • Groovy 1.8a 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
  • 129.
    Customiserlecompilateur • Nouvelles options •--basescript pour définir une classe de base pour les scripts • --configscript pour indiquer un script qui va configurer CompilerConfiguration
  • 130.
    Customiserlecompilateur • Rajouter latransformation @ToString • import  groovy.transform.ToString import  org.codehaus.groovy.control.customizers              .ASTTransformationCustomizer configuration.addCompilationCustomizer(        new  ASTTransformationCustomizer(ToString) )
  • 131.
    Customiserlecompilateur • Rajouter latransformation @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
  • 132.
    Customiserlecompilateur • Un petitDSL pour simplifier la configuration configuration.customizers  {        //  apply  to  MyBean.groovy        source(basename:  'MyBean')  {                ast(ToString)        } }
  • 133.
    Customiserlecompilateur • Un petitDSL 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)        } }
  • 134.
    Customiserlecompilateur • Un petitDSL 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'                }        } }
  • 135.
    Pour en savoirplus... Groovy2.0 http://groovy.codehaus.org/Groovy+2.0+release+notes Groovy2.1 http://groovy.codehaus.org/Groovy+2.1+release+notes
  • 136.
    Et après ? Groovy3! Nouveau « MOP » Nouvellegrammaire Antlr v4 Support des lambdasdeJava8
  • 137.
  • 138.
  • 139.
  • 140.
  • 141.
  • 142.
  • 144.
    Conclusion—1/2 • Un écosystèmeriche 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
  • 145.
    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
  • 146.
  • 147.
  • 148.
  • 149.
    Créditsimages • 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