Successfully reported this slideshow.
Your SlideShare is downloading. ×

Groovy 2.5 and 3.0 (Spanish)

Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Upcoming SlideShare
Write Gradle Plugins
Write Gradle Plugins
Loading in …3
×

Check these out next

1 of 88 Ad
Advertisement

More Related Content

Similar to Groovy 2.5 and 3.0 (Spanish) (20)

Advertisement

Recently uploaded (20)

Groovy 2.5 and 3.0 (Spanish)

  1. 1. GROOVY 2.5+, 3.0 1
  2. 2. HEY HOLA Name Mario Garcia Sigo trabajando en Kaleidos https://kaleidos.net 2 . 1
  3. 3. ME Sospechoso de pertenecer al: Madrid Groovy User Group Social: https://twitter.com/marioggar https://github.com/mariogarcia 2 . 2
  4. 4. QUE VENIA A CONTAROS ? Groovy en numeros Groovy roadmap 2018 / 2019 Que nos ofrece la version 2.5+ Que nos ofrece la version 3.0 3
  5. 5. GROOVY EN NUMEROS 4 . 1
  6. 6. REFERENCIAS OCI Webminar 23, may 2018 by Paul King Groovy distribution archive 4 . 2
  7. 7. CONTRIBUTORS 30+ nuevos contributors en los ultimos 16 meses 4 . 3
  8. 8. DESCARGAS 23 millones 2016 50 millones 2017 19 millones solo en el 1er Q de 2018 + 4 millones de descargas al mes y subiendo 4 . 4
  9. 9. ULTIMAS VERSIONES 2.4.15: 2018-09-04 2.5.3: 2018-10-14 2.6.0-alpha-4: 2018-06-26 3.0.0-alpha-3: 2018-06-26 4 . 5
  10. 10. ROADMAP 5 . 1
  11. 11. GROOVY 2.5.X La 2.5.x ya lleva con nosotros 5 meses (2018-05-30) Actualizaciones a buen ritmo 2.5.0: mayo 2.5.1: julio 2.5.2: agosto 5 . 2
  12. 12. GROOVY 2.5.X (II) Macros JDK 7 es el minimo Compatible con JDK9/10 con warnings 5 . 3
  13. 13. GROOVY 2.6, 3.0 Alphas de ambas desde mediados de 2018 Parrot parser (JDK8 syntax 1 - 1 y mucho mas) 2.6 JDK7 (min) Corta esperanza de vida 5 . 4
  14. 14. HABLEMOS DE GROOVY 2.5 6
  15. 15. ANNOTATIONS 7 . 1
  16. 16. 7 . 2
  17. 17. EN GENERAL Flexibilidad en antiguas anotaciones Conversion en Meta anotaciones Validacion de parametros Ayuda en la cobertura de codigo 7 . 3
  18. 18. EJEMPLOS @Immutable @AutoImplement @AutoFinal @NamedXXX @Generated 7 . 4
  19. 19. @IMMUTABLE No poder modificar los campos de una clase Si los campos son otras clases… Comprueba que sean immutables tambien O que esten en una lista blanca de clases 7 . 5
  20. 20. @IMMUTABLE (OLD) package madridgug.immutable import groovy.transform.Immutable @Immutable class Car { Brand brand (1) String model Double hp Map<?, String> extra (2) } 7 . 6
  21. 21. @IMMUTABLE (NEW - JAVA.TIME) package madridgug.immutable import java.time.LocalTime import groovy.transform.Immutable @Immutable class Brand { String name LocalTime birthdate (1) } 7 . 7
  22. 22. @IMMUTABLE (NEW - DI FRIENDLY) package madridgug.immutable import groovy.transform.Canonical import groovy.transform.ImmutableBase import groovy.transform.PropertyOptions import groovy.transform.options.ImmutablePropertyHandler @ImmutableBase @Canonical(defaults = false) @PropertyOptions(propertyHandler = ImmutablePropertyHandler) class SecurityConfig { URI provider String key } 7 . 8
  23. 23. @IMMUTABLE (DI FRIENDLY - II) + 1 vez ⇒ Meta anotacion package madridgug.immutable import groovy.transform.* import groovy.transform.options.* @ImmutableBase @TupleConstructor(defaults = false) @PropertyOptions(propertyHandler = ImmutablePropertyHandler) @AnnotationCollector @interface ImmutableDI { } 7 . 9
  24. 24. @IMMUTABLE (DI FRIENDLY - III) Annotated class Google Guice Module package madridgug.immutable @ImmutableDI class SecurityConfig2 { URI provider String key } def ctor = SecurityConfig2.getConstructor(URI, String) bind(SecurityConfig2) .toConstructor(ctor) .in(Scopes.SINGLETON) 7 . 10
  25. 25. @IMMUTABLE (DI FRIENDLY - IV) given: 'a Google Guice Injector' Injector di = Guice.createInjector(new GuiceModule()) when: 'getting the configuration instance' SecurityConfig2 config = di.getInstance(SecurityConfig2) then: 'properties should've been populated properly' config.key == 'key' config.provider == URI.create('https://nowhereprovider.io') when: 'trying to change properties again' config.key = 'another key' then: 'an error will be thrown' thrown(ReadOnlyPropertyException) 7 . 11
  26. 26. @IMMUTABLE (OPTIONAL) Considerado immutable tambien package madridgug.immutable import groovy.transform.Immutable @Immutable class Person { String name Integer age Optional<String> mobile } 7 . 12
  27. 27. @AUTOIMPLEMENT A veces tenemos que implementar un interface Pero no queremos / podemos implementarlo entero 7 . 13
  28. 28. @AUTOIMPLEMENT package madridgug.autoimplement interface MessageSender { /** * Sends a message {@link String} */ UUID sendMessage(String message) /** * Checks whether the message has been received yet or not */ boolean isMessageReceived(UUID messageId) /** * Checks whether the message has been sent yet or not */ Boolean isMessageSent(UUID messageId) } 7 . 14
  29. 29. @AUTOIMPLEMENT Default package madridgug.autoimplement import groovy.util.logging.Slf4j import groovy.transform.AutoImplement @Slf4j @AutoImplement class PartialMessageSender implements MessageSender { @Override UUID sendMessage(String message) { log.info "message: $message" return UUID.randomUUID() } } 7 . 15
  30. 30. @AUTOIMPLEMENT Throw exceptions package madridgug.autoimplement import madridgug.exception.NotEnoughTimePalException import groovy.util.logging.Slf4j import groovy.transform.AutoImplement @Slf4j @AutoImplement(exception = NotEnoughTimePalException) class NoisyMessageSender implements MessageSender { @Override UUID sendMessage(String message) { log.info "message: $message" return UUID.randomUUID() } 7 . 16
  31. 31. @AUTOIMPLEMENT Custom code package madridgug.autoimplement import static java.time.LocalDateTime.now import groovy.util.logging.Slf4j import groovy.transform.AutoImplement @Slf4j @AutoImplement(code = { log.error("Necesito + tiempo ok? Prueba a las: ${now() + 120}") }) class VeryNoisyMessageSender implements MessageSender { } 7 . 17
  32. 32. @AUTOFINAL A veces cometemos errores re-asignando una variable Deberia avisarnos en tiempo de compilacion 7 . 18
  33. 33. @AUTOFINAL package madridgug.autofinal import groovy.transform.AutoFinal class WordProcessor { @AutoFinal String reverseWord(Word word) { // word = new Word(word: 'another') (1) return word.reverse() } Integer size(Word word) { word = new Word(word: 'another') (2) return word.size() } 7 . 19
  34. 34. @DELEGATE ENHANCEMENTS Hasta ahora solo se podia utilizar sobre propiedades de la clase 7 . 20
  35. 35. @DELEGATE ENHANCEMENTS Ahora @Delegate se puede usar en getters package madridgug.delegate class TennisPlayer { List<Map> wins String name @Delegate Integer getWinSize() { return wins.size() } } 7 . 21
  36. 36. @DELEGATE ENHANCEMENTS given: 'two players' def good = new TennisPlayer(name: 'John', wins: [ [name: 'Roland Garros 2014'], [name: 'Roland Garros 2015'], [name: 'Roland Garros 2016'] ]) def bad = new TennisPlayer(name: 'Peter', wins: [ [name: 'Somewhere 2002'] ]) and: 'the good one should be greater than the bad one' good.intValue() > bad.intValue() 7 . 22
  37. 37. @NAMEDVARIANT Posibilidad de llamar a un metodo con la instancia del tipo requerido o … Descomponiendo la instancia en sus diferentes attributos 7 . 23
  38. 38. @NAMEDVARIANT package madridgug.namedvariant class Car { String brand String model Integer hp } package madridgug.namedvariant import groovy.util.logging.Slf4j import groovy.transform.NamedVariant import groovy.transform.NamedDelegate @Slf4j class CarProcessor { @NamedVariant void process(@NamedDelegate Car car) { log.info "processing: ${car.model}" } } 7 . 24
  39. 39. @NAMEDVARIANT Pasando una instancia Car car = new Car(brand: 'ferrari', model: 'F450', hp: 450) CarProcessor processor = new CarProcessor() when: 'processing the car' processor.process(car) 7 . 25
  40. 40. @NAMEDVARIANT Pasando propiedades and: 'a processor instance' CarProcessor processor = new CarProcessor() when: 'processing the car' processor.process(brand: 'ferrari', model: 'F450', hp: 450) 7 . 26
  41. 41. @NAMEDVARIANT NamedParam package madridgug.namedvariant import java.time.LocalDateTime import groovy.util.logging.Slf4j import groovy.transform.* @Slf4j class AnotherCarProcessor { @NamedVariant void process(String user, @NamedParam LocalDateTime now, @NamedDelegate Car car) { log.info "$user ha procesado el modelo ${car.model} el $now" } } 7 . 27
  42. 42. @NAMEDVARIANT Invocacion and: 'a processor instance' AnotherCarProcessor processor = new AnotherCarProcessor() when: 'processing the car' processor.process( 'John Doe', now: LocalDateTime.now(), brand: 'ferrari', model: 'F450', hp: 450, ) 7 . 28
  43. 43. @GENERATED Concebido para los autores de transformciones AST Ayuda a las herramientas de cobertura de codigo Para saber que codigo es generado y cual no Hasta ahora ni JaCoCo ni Cobertura lo tenian facil 7 . 29
  44. 44. MACROS 8 . 1
  45. 45. LAS UTILIDADES DE MACROS ABSTRAEN… La generacion de nuevo codigo El filtrado de codigo sobre el que quieres aplicar una transformacion La transformacion de codigo 8 . 2
  46. 46. UTILIDADES macro {} (generacion) MacroClass {} (generacion) @Macro (transformacion) ASTMatcher (filtrado) 8 . 3
  47. 47. MACRO METHOD Nos permite crear statements y expressions De manera mas facil y natural 8 . 4
  48. 48. MACRO METHOD Este codigo Deberia contemplar este test package madridgug.macros.method class SafeCalls { @MakeParamSafe static Integer inc(Integer a) { // if (!a) { return 1 } return a + 1 } } void 'check unsafe calls'() { expect: 'unsafe calls to return ok' SafeCalls.inc(null) == 1 } 8 . 5
  49. 49. MACRO METHOD Como crear la guarda antes del codigo ? API AST "A pelo" GeneralUtils para reducirlo macro {} 8 . 6
  50. 50. MACRO METHOD API ASTs GeneralUtils IfStatement safeGuard = new IfStatement( new NotExpression( new VariableExpression(paramName) ), new ReturnStatement(new ConstantExpression(1)), new EmptyStatement() ) IfStatement safeGuard = ifS( notX(varX(paramName)), returnS(constX(1)) ) as IfStatement 8 . 7
  51. 51. MACRO METHOD macro {} 1 Las expressiones se interpolan 2 Dentro de codigo plano VariableExpression paramRef = Utils.getParamAsVarX(methodNode) (1) IfStatement safeGuard = macro { if (! $v { paramRef }) { (2) return 1 } } 8 . 8
  52. 52. MACRO METHOD Mejor caso de uso BlockStatement getMD5Code(final String propertyName) { return macro(true) { java.security.MessageDigest.getInstance('MD5') .digest(${propertyName}.getBytes('UTF-8')) .encodeHex() .toString() } } 8 . 9
  53. 53. MACROCLASS Para crear clases y/o metodos con la misma tecnica que con el macro {} method 8 . 10
  54. 54. MACROCLASS Creacion de clase @CompileDynamic ClassNode buildTemplateClass(ClassNode reference) { def methodCount = constX(reference.methods.size()) def fieldCount = constX(reference.fields.size()) return new MacroClass() { class Statistics { java.lang.Integer getMethodCount() { return $v { methodCount } } java.lang.Integer getFieldCount() { return $v { fieldCount } } } } 8 . 11
  55. 55. MACROCLASS Creacion de clase package madridgug.macros.method @Statistics class ProcessorWithStatistics { String name void processX(){} void processY(){} void processZ(){} } 8 . 12
  56. 56. MACROCLASS Creacion de clase void 'check statistics'() { given: 'an instance of processor' ProcessorWithStatistics processor = new ProcessorWithStatistics() expect: 'number of methods' processor.methodCount == 3 and: 'number of fields' processor.fieldCount == 1 } 8 . 13
  57. 57. ASTMATCHER Clase de utilidad para filtrar, seleccionar nodos que transformar Una vez que localizas lo que quieres modificar lo modificas 8 . 14
  58. 58. ASTMATCHER @Override Expression transform(Expression exp) { Expression ref = macro { 1 + 1 } if (ASTMatcher.matches(ref, exp)) { return macro { 3 } } return super.transform(exp) } 8 . 15
  59. 59. @MACRO Transforman aquellas invocaciones a metodos que tienen el nombre anotado Parecido a las extensiones No imports required 8 . 16
  60. 60. @MACRO public class ExampleMacroMethods { @Macro public static Expression safe(MacroContext macroContext, MethodCa return ternaryX( notNullX(callExpression.getObjectExpression()), callExpression, constX(null) ); } ... } 8 . 17
  61. 61. @MACRO def nullObject = null assert null == safe(safe(nullObject.hashcode()).toString()) 8 . 18
  62. 62. @MACRO nullObject?.hashcode()?.toString() 8 . 19
  63. 63. HABLEMOS DE GROOVY 3.X 9 . 1
  64. 64. ALINEACION CON JDK9 / 10 9 . 2
  65. 65. PARROT Renovacion del parser de Groovy Groovy vuelve a ser un super conjunto de Java Entre otras cosas… lambdas syntax 9 . 3
  66. 66. LAMBDAS Lambdas static Integer applyLambdas() { return Stream .of(1, 2, 3) .filter(y -> y % 2 == 0) .map(y -> y + 1) .mapToInt(Integer::intValue) .sum() } 9 . 4
  67. 67. LAMBDAS Lambdas static Integer applyLambdas2() { return Stream .of(1, 2, 3) .reduce((Integer acc, Integer val) -> { return acc + val }).orElse(1) } 9 . 5
  68. 68. METHOD REFERENCES @CompileStatic static Integer applyMethodReferences(Integer x) { return Optional .ofNullable(x) .map(Functions::x2) .map(inc) .orElse(1) } 9 . 6
  69. 69. LAMBDAS + CLOSURES + M. REF. Todo junto static Integer applyBoth() { return Stream .of(1, 2, 3) .filter { y -> y % 2 == 0 } // closure syntax .map( y -> y + 1 ) // lambda syntax .mapToInt(Integer::intValue) // method ref .sum() } 9 . 7
  70. 70. LAMBDAS OTHERS // Sin parentesis static Function<Integer, Integer> inc = x -> x + 1 // Con valor por defecto (No existe en Java) static Function<Integer, Integer> dob = (x = 0) -> x * 2 // Con parentesis static Function<Integer, Integer> tri = (Integer x) -> x * 3 // Con llaves static Function<Integer, Integer> com = (Integer x) -> { x + 4 } 9 . 8
  71. 71. LAMBDAS OTHERS Son las lambdas realmente lambdas ? Con @CompileStatic ⇒ lambdas Sin @CompileStatic ⇒ closures 9 . 9
  72. 72. LOOPS En general todos los tipos de loops que se puedan hacer en Java Ahora se puede hacer un do / while por ejemplo 9 . 10
  73. 73. LOOPS Multi asignacion List<String> returnValues() { List<String> values = [] for (def (String u, Integer v) = ['bar', 42]; v < 45; u++, v++) { values << "$u $v" } return values } 9 . 11
  74. 74. NUEVOS OPERADORES Identidad Elvis Safe indexing 9 . 12
  75. 75. IDENTIDAD package madridgug.parrot import groovy.transform.Immutable class Identity { @Immutable class Person { String name } void checkIdentity(Person left, Person right) { if (left === right) { (1) log.info "es la misma persona" } if (left == right) { (2) log.info "son personas con caracteristicas iguales" } 9 . 13
  76. 76. ELVIS void newElvis(Integer x) { x ?= 0 // instead of x ? x : 0 println x + 1 } 9 . 14
  77. 77. SAFE INDEXING void safeIndexing() { def numbers = null println numbers?[10] // will print null } 9 . 15
  78. 78. OTROS Default methods en interfaces !in y !instanceof 9 . 16
  79. 79. @GROOVYDOC Comentarios accesibles en tiempo de ejecucion 9 . 17
  80. 80. @GROOVYDOC package madridgug.parrot class Processor { /** * @Groovydoc accesible1 (1) */ void process(String word) { println "process: $word" } @Groovydoc('accesible2') (2) void check(String word) { println "check: $word" } } 9 . 18
  81. 81. @GROOVYDOC comments annotation String content = Processor .methods .find { it.name == 'process' } .groovydoc .content assert content == 'accesible1 // <1>' String content = Processor .methods .find { it.name == 'check' } .groovydoc .content assert content == 'accesible2' 9 . 19
  82. 82. QUE QUEDA POR CONTAR ? 10 . 1
  83. 83. GROOVY 2.5 @TupleConstructor Repeated annotations Anotaciones en mas sitios (JSR-308) Mejoras en el CliBuilder with vs tap 10 . 2
  84. 84. GROOVY 3.X Mejora en la syntaxis try with resources 10 . 3
  85. 85. GROOVY ECOSYSTEM 11 . 1
  86. 86. BIBLIOTECAS Y FRAMEWORKS Nombre Version Groovy Spock 1.2-groovy-2.5 2.5.2 Micronaut 1.0.0-RC2 2.5.1 Geb 2.2 2.4.15 Grails 3.3.8 2.4.15 Griffon 2.15.0 2.4.15 11 . 2
  87. 87. WANNA KNOW MORE ? https://www.youtube.com/watch?v=ECZVbiFZPwE 12
  88. 88. QUESTIONS & ANSWERS 13

×