Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Groovy in the light of Java 8 -- JavaOne 2014

Groovy in the light of Java 8 -- JavaOne 2014

With Java 8 out, what is the impact of Groovy? Is it still relevant? How can developers can benefit from Java 8 with Groovy?

Guillaume Laforge

October 02, 2014
Tweet

More Decks by Guillaume Laforge

Other Decks in Programming

Transcript

  1. Groovy
    in the light of
    Java 8
    Guillaume Laforge
    Groovy project lead
    Pivotal
    @glaforge

    View Slide

  2. Stay up-to-date
    Groovy Weekly Newsletter (Every Tuesday)
    http://beta.groovy-lang.org/groovy-weekly.html
    2

    View Slide

  3. @glaforge — Groovy in the light of Java 8
    Goal of this talk

    View Slide

  4. A recurring question…
    Do we still need
    Groovy now that
    we have Java 8?
    4

    View Slide

  5. To those who said no…
    5

    View Slide

  6. But more precisely…
    • Will Java lambdas replace Groovy closures?

    • What are the differences between them?

    !
    • Will Groovy support all the new Java 8 language constructs?

    • lambdas, default methods, method references…

    !
    • How Groovy developers can benefit from Java 8?

    !
    • What does Groovy offer beyond Java 8?
    6

    View Slide

  7. What about redundancy?
    !
    !
    !
    !
    !
    • Closures

    • Traits

    • Truth & null handling

    • Functional with collections

    • Method closures

    !
    !
    !
    !
    !
    !
    • Lambdas

    • Default methods

    • Optional

    • Stream API

    • Method references
    7

    View Slide

  8. @glaforge — Groovy in the light of Java 8
    What’s new in Java 8?

    View Slide

  9. View Slide

  10. This is not a Java 8 crash courses
    with all the details :-)

    View Slide

  11. This is not a Java 8 crash courses
    with all the details :-)
    We want to understand the
    implications with regards to Groovy

    View Slide

  12. What’s new in Java 8?
    !
    • New syntax
    • Streams
    • Profiles

    • Security enhancements

    • JavaFX

    • Tools

    • i18n

    • Date / time API
    • Nashorn / JavaScript
    !
    !
    • Pack200

    • IO / NIO improvements
    • New utility classes

    • JDBC

    • Networking

    • Concurrency

    • JAXP

    • Hotspot

    • Java Mission Control
    10

    View Slide

  13. What’s new in Java 8?
    !
    • New syntax
    • Streams
    • Profiles

    • Security enhancements

    • JavaFX

    • Tools

    • i18n

    • Date / time API
    • Nashorn / JavaScript
    !
    !
    • Pack200

    • IO / NIO improvements
    • New utility classes

    • JDBC

    • Networking

    • Concurrency

    • JAXP

    • Hotspot

    • Java Mission Control
    10
    Great concise resource with the whole list:
    http://bit.ly/new-in-java-8

    View Slide

  14. @glaforge — Groovy in the light of Java 8
    Support the
    new Java 8
    language features
    New Java 8 syntax

    View Slide

  15. New Java 8 syntax constructs
    • Lambda expressions

    • Method references

    • Static & default methods in interfaces

    • Repeating annotations

    • Annotations on types

    • Improved type inference

    • Method parameter reflection
    12

    View Slide

  16. New Java 8 syntax constructs
    • Lambda expressions
    • Method references
    • Static & default methods in interfaces
    • Repeating annotations
    • Annotations on types
    • Improved type inference

    • Method parameter reflection
    13

    View Slide

  17. View Slide

  18. View Slide

  19. View Slide

  20. Lambda expressions
    15
    double highestScore = students
    .filter(Student s -> s.getGradYear() == 2011)
    .map(Student s -> s.getScore())
    .max();

    View Slide

  21. Lambda expressions
    16
    double highestScore = students
    .filter(Student s -> s.getGradYear() == 2011)
    .map(Student s -> s.getScore())
    .max();

    View Slide

  22. Lambda expressions
    16
    double highestScore = students
    .filter(Student s -> s.getGradYear() == 2011)
    .map(Student s -> s.getScore())
    .max();
    Coercion into a Predicate
    « functional interface »

    View Slide

  23. Lambda expressions
    16
    double highestScore = students
    .filter(Student s -> s.getGradYear() == 2011)
    .map(Student s -> s.getScore())
    .max();
    There’s no function type!

    View Slide

  24. Lambda expressions
    16
    double highestScore = students
    .filter(Student s -> s.getGradYear() == 2011)
    .map(Student s -> s.getScore())
    .max();
    Pipeline being built
    Single pass!

    View Slide

  25. Lambda expressions
    16
    double highestScore = students
    .filter(Student s -> s.getGradYear() == 2011)
    .map(Student s -> s.getScore())
    .max();

    View Slide

  26. Lambda expressions
    17
    double highestScore = students
    .findAll { it.gradYear == 2011 }
    .collect { it.score}
    .max()

    View Slide

  27. Lambda expressions
    17
    double highestScore = students
    .findAll { it.gradYear == 2011 }
    .collect { it.score}
    .max()
    In Groovy, that would be…

    View Slide

  28. Lambda expressions
    17
    double highestScore = students
    .findAll { it.gradYear == 2011 }
    .collect { it.score}
    .max()
    Drawback: intermediary data structures
    Unless you use iterator variants

    View Slide

  29. Lambda expressions
    17
    double highestScore = students
    .findAll { it.gradYear == 2011 }
    .collect { it.score}
    .max()

    View Slide

  30. The various lambda syntaxes
    18
    String name -> name.length()
    !
    (int left, int right) -> left + right
    !
    (String left, String sep, String right) ->
    { System.out.println(left + sep + right) }

    View Slide

  31. The various lambda syntaxes
    18
    String name -> name.length()
    !
    (int left, int right) -> left + right
    !
    (String left, String sep, String right) ->
    { System.out.println(left + sep + right) }
    One parameter: no parens
    Expression on right: no curly

    View Slide

  32. The various lambda syntaxes
    18
    String name -> name.length()
    !
    (int left, int right) -> left + right
    !
    (String left, String sep, String right) ->
    { System.out.println(left + sep + right) }
    Parentheses required for more
    that one parameter

    View Slide

  33. The various lambda syntaxes
    18
    String name -> name.length()
    !
    (int left, int right) -> left + right
    !
    (String left, String sep, String right) ->
    { System.out.println(left + sep + right) }
    Statements require curly braces
    Return keyword required if non-void returning

    View Slide

  34. The various lambda syntaxes
    18
    String name -> name.length()
    !
    (int left, int right) -> left + right
    !
    (String left, String sep, String right) ->
    { System.out.println(left + sep + right) }
    Clever type inference can
    help get rid of parameter
    type declarations

    View Slide

  35. Closures vs lambdas
    19
    IntStream.range(1, 100).forEach(s ->
    System.out.println(s));
    !
    Files.lines(Paths.get('README.adoc'))
    .map(it -> it.toUpperCase())
    .forEach(it -> System.out.println(it));

    View Slide

  36. Closures vs lambdas
    19
    IntStream.range(1, 100).forEach(s ->
    System.out.println(s));
    !
    Files.lines(Paths.get('README.adoc'))
    .map(it -> it.toUpperCase())
    .forEach(it -> System.out.println(it));
    IntStream.range(1, 100).forEach { println it }
    !
    Files.lines(Paths.get('README.adoc'))
    .map { it.toUpperCase() }
    .forEach { println it }

    View Slide

  37. Closures vs lambdas
    19
    IntStream.range(1, 100).forEach(s ->
    System.out.println(s));
    !
    Files.lines(Paths.get('README.adoc'))
    .map(it -> it.toUpperCase())
    .forEach(it -> System.out.println(it));
    IntStream.range(1, 100).forEach { println it }
    !
    Files.lines(Paths.get('README.adoc'))
    .map { it.toUpperCase() }
    .forEach { println it }
    Use Groovy closures
    wherever you pass
    lambdas in Java 8

    View Slide

  38. Closures vs lambdas
    19
    IntStream.range(1, 100).forEach(s ->
    System.out.println(s));
    !
    Files.lines(Paths.get('README.adoc'))
    .map(it -> it.toUpperCase())
    .forEach(it -> System.out.println(it));
    IntStream.range(1, 100).forEach { println it }
    !
    Files.lines(Paths.get('README.adoc'))
    .map { it.toUpperCase() }
    .forEach { println it }
    Groovy coerces to SAM types
    (Single Abstract Method)

    View Slide

  39. Closures vs lambdas
    19
    IntStream.range(1, 100).forEach(s ->
    System.out.println(s));
    !
    Files.lines(Paths.get('README.adoc'))
    .map(it -> it.toUpperCase())
    .forEach(it -> System.out.println(it));
    IntStream.range(1, 100).forEach { println it }
    !
    Files.lines(Paths.get('README.adoc'))
    .map { it.toUpperCase() }
    .forEach { println it }

    View Slide

  40. Beyond: Closure default parameters
    20
    def mult = { int a, int b = 10 -> a * b }
    !
    assert mult(2, 3) == 6
    assert mult(5) == 50

    View Slide

  41. Beyond: Closure default parameters
    20
    def mult = { int a, int b = 10 -> a * b }
    !
    assert mult(2, 3) == 6
    assert mult(5) == 50
    Default value if the
    parameter is not specified

    View Slide

  42. Beyond: Duck typing polymorphism
    21
    def adder = { a, b -> a + b }
    !
    assert adder(100, 200) == 300
    assert adder('X', 'Y') == 'XY'

    View Slide

  43. Beyond: Duck typing polymorphism
    21
    def adder = { a, b -> a + b }
    !
    assert adder(100, 200) == 300
    assert adder('X', 'Y') == 'XY'
    Works both for numbers
    and for strings

    View Slide

  44. Builders

    View Slide

  45. Builders
    What would Java lambda
    builders look like?

    View Slide

  46. Builders
    What would Java lambda
    builders look like?
    Aren’t Groovy builders
    more powerful?

    View Slide

  47. Lambda-based builders uglier and less powerful
    23
    MarkupBuilder pom = new XmlMarkupBuilder()
    pom.el("modelVersion", "4.0.0");
    pom.el("groupId", "com.github");
    pom.el("artifactId", "lambda-builder");
    pom.el("version", "1.0-SNAPSHOT");
    pom.el("dependencies", () -> {
    pom.el("dependency", () -> {
    pom.el("groupId", "junit");
    pom.el("artifactId", "junit");
    pom.elx("version", "4.11");
    });
    pom.el("dependency", () -> {
    pom.el("groupId", "commons-beanutils");
    pom.el("artifactId", "commons-beanutils");
    pom.elx("version", "1.7.0");
    });
    });

    View Slide

  48. Lambda-based builders uglier and less powerful
    23
    MarkupBuilder pom = new XmlMarkupBuilder()
    pom.el("modelVersion", "4.0.0");
    pom.el("groupId", "com.github");
    pom.el("artifactId", "lambda-builder");
    pom.el("version", "1.0-SNAPSHOT");
    pom.el("dependencies", () -> {
    pom.el("dependency", () -> {
    pom.el("groupId", "junit");
    pom.el("artifactId", "junit");
    pom.elx("version", "4.11");
    });
    pom.el("dependency", () -> {
    pom.el("groupId", "commons-beanutils");
    pom.el("artifactId", "commons-beanutils");
    pom.elx("version", "1.7.0");
    });
    });
    Repeated « pom »:
    No delegate like in
    Groovy’s closures

    View Slide

  49. Lambda-based builders uglier and less powerful
    23
    MarkupBuilder pom = new XmlMarkupBuilder()
    pom.el("modelVersion", "4.0.0");
    pom.el("groupId", "com.github");
    pom.el("artifactId", "lambda-builder");
    pom.el("version", "1.0-SNAPSHOT");
    pom.el("dependencies", () -> {
    pom.el("dependency", () -> {
    pom.el("groupId", "junit");
    pom.el("artifactId", "junit");
    pom.elx("version", "4.11");
    });
    pom.el("dependency", () -> {
    pom.el("groupId", "commons-beanutils");
    pom.el("artifactId", "commons-beanutils");
    pom.elx("version", "1.7.0");
    });
    });
    Zero-arg lamdas
    not as lean

    View Slide

  50. Lambda-based builders uglier and less powerful
    23
    MarkupBuilder pom = new XmlMarkupBuilder()
    pom.el("modelVersion", "4.0.0");
    pom.el("groupId", "com.github");
    pom.el("artifactId", "lambda-builder");
    pom.el("version", "1.0-SNAPSHOT");
    pom.el("dependencies", () -> {
    pom.el("dependency", () -> {
    pom.el("groupId", "junit");
    pom.el("artifactId", "junit");
    pom.elx("version", "4.11");
    });
    pom.el("dependency", () -> {
    pom.el("groupId", "commons-beanutils");
    pom.el("artifactId", "commons-beanutils");
    pom.elx("version", "1.7.0");
    });
    });
    Generic method +
    string: No dynamic
    method

    View Slide

  51. Neater Groovy builder!
    24
    def pom = new PomBuilder().project {
    modelVersion "4.0.0"
    groupId "com.github"
    artifactId "lambda-builder"
    version "1.0-SNAPSHOT"
    dependencies {
    dependency {
    groupId "junit"
    artifactId "junit"
    version "4.11"
    }
    dependency {
    groupId "commons-beanutils"
    artifactId "commons-beanutils"
    version "1.7.0"
    }
    }
    }

    View Slide

  52. Neater Groovy builder!
    24
    def pom = new PomBuilder().project {
    modelVersion "4.0.0"
    groupId "com.github"
    artifactId "lambda-builder"
    version "1.0-SNAPSHOT"
    dependencies {
    dependency {
    groupId "junit"
    artifactId "junit"
    version "4.11"
    }
    dependency {
    groupId "commons-beanutils"
    artifactId "commons-beanutils"
    version "1.7.0"
    }
    }
    }

    View Slide

  53. View Slide

  54. Aren’t Groovy builders
    more readable and lean?

    View Slide

  55. To those who said no…
    26

    View Slide

  56. Memoization

    View Slide

  57. Closure and method memoization
    28
    def fib2 = { long n ->
    if (n < 2) 1
    else call(n - 1) + call(n - 2)
    }.memoize()

    View Slide

  58. Closure and method memoization
    28
    def fib2 = { long n ->
    if (n < 2) 1
    else call(n - 1) + call(n - 2)
    }.memoize()
    Closures:
    memoize()

    View Slide

  59. Closure and method memoization
    28
    @Memoized
    long fib(long n) {
    if (n < 2) 1
    else fib(n - 1) + fib(n - 2)
    }
    def fib2 = { long n ->
    if (n < 2) 1
    else call(n - 1) + call(n - 2)
    }.memoize()
    Closures:
    memoize()

    View Slide

  60. Closure and method memoization
    28
    @Memoized
    long fib(long n) {
    if (n < 2) 1
    else fib(n - 1) + fib(n - 2)
    }
    def fib2 = { long n ->
    if (n < 2) 1
    else call(n - 1) + call(n - 2)
    }.memoize()
    Closures:
    memoize()
    Methods:
    memoization AST
    transformation

    View Slide

  61. View Slide

  62. Tail
    recursion

    View Slide

  63. Closure and method tail recursion
    30
    def fact = { n, accu = 1G ->
    if (n < 2) accu
    else fact.trampoline(n - 1, n * accu)
    }.trampoline()

    View Slide

  64. Closure and method tail recursion
    30
    def fact = { n, accu = 1G ->
    if (n < 2) accu
    else fact.trampoline(n - 1, n * accu)
    }.trampoline()
    Closures:
    Tail recursion with
    trampoline()

    View Slide

  65. Closure and method tail recursion
    30
    @groovy.transform.TailRecursive
    def fact(n, accu = 1G) {
    if (n < 2) accu
    else fact(n - 1, n * accu)
    }
    def fact = { n, accu = 1G ->
    if (n < 2) accu
    else fact.trampoline(n - 1, n * accu)
    }.trampoline()
    Closures:
    Tail recursion with
    trampoline()

    View Slide

  66. Closure and method tail recursion
    30
    @groovy.transform.TailRecursive
    def fact(n, accu = 1G) {
    if (n < 2) accu
    else fact(n - 1, n * accu)
    }
    def fact = { n, accu = 1G ->
    if (n < 2) accu
    else fact.trampoline(n - 1, n * accu)
    }.trampoline()
    Closures:
    Tail recursion with
    trampoline()
    Methods:
    Tail recursion with
    @TailRecursive
    transformation

    View Slide

  67. Method references
    31
    button.setOnAction(event -> System.out.println(event));

    View Slide

  68. Method references
    31
    button.setOnAction(event -> System.out.println(event));
    button.setOnAction(System.out::println);

    View Slide

  69. Method references — 3 main cases
    • Three main cases:
    32
    instance::instanceMethod
    !
    SomeClass::staticMethod
    !
    SomeClass::instanceMethod

    View Slide

  70. Method references — 3 main cases
    • Three main cases:
    32
    instance::instanceMethod
    !
    SomeClass::staticMethod
    !
    SomeClass::instanceMethod
    Not covered by
    Groovy method
    closures yet!

    View Slide

  71. Groovy’s method closure
    33
    instance.&instanceMethod
    !
    SomeClass.&staticMethod
    !
    SomeClass.&instanceMethod

    View Slide

  72. Groovy’s method closure
    33
    instance.&instanceMethod
    !
    SomeClass.&staticMethod
    !
    SomeClass.&instanceMethod
    Choices:
    Adopt ::
    Deprecate .&
    Enhance .&

    View Slide

  73. Static methods in interfaces
    • You can put static utility methods in interfaces, 

    instead of in companion classes (like « Collections »)
    34
    public interface Stream {
    // ...
    static Stream empty() {
    return new Stream { ... }
    }
    }

    View Slide

  74. Default methods in interfaces
    • Define default behavior

    • possibly to enrich existing interfaces
    35
    public interface Stream {
    // ...
    default Builder add(T t) { ... }
    }

    View Slide

  75. Groovy Traits
    • Like interfaces, but with method bodies
    • similar to Java 8 interface default methods
    • Elegant way to compose behavior
    • multiple inheritance without the « diamond » problem
    • Traits can also be stateful
    • traits can have properties like normal classes
    • Compatible with static typing and static compilation
    • class methods from traits also visible from Java classes
    • Also possible to implement traits at runtime 36

    View Slide

  76. Simple trait
    37
    trait FlyingAbility {
    String fly() { "I'm flying!" }
    }
    !
    class Bird implements FlyingAbility {}
    def b = new Bird()
    !
    assert b.fly() == "I'm flying!"

    View Slide

  77. Trait with state
    38
    trait Named {
    String name
    }
    !
    class Bird implements Named {}
    def b = new Bird(name: 'Colibri')
    !
    assert b.name == 'Colibri'

    View Slide

  78. Multiple inheritance
    39
    trait KiteSurfer { String surf() { 'kite' } }
    !
    trait WebSurfer { String surf() { 'web' } }
    !
    class Person { String name }
    !
    class Hipster extends Person
    implements KiteSurfer, WebSurfer {}
    !
    def h = new Hipster()
    assert h.surf() == 'web'

    View Slide

  79. Annotations
    on types
    Repeating
    annotations

    View Slide

  80. Repeating annotations
    41
    @Schedule(dayOfMonth = "last")
    @Schedule(dayOfWeek = "Fri", hour = 23)
    public void doPeriodicCleanup() { ... }

    View Slide

  81. Repeating annotations
    41
    @Schedule(dayOfMonth = "last")
    @Schedule(dayOfWeek = "Fri", hour = 23)
    public void doPeriodicCleanup() { ... }
    @Schedule annotation
    repeated twice

    View Slide

  82. Repeating annotations
    41
    @Schedule(dayOfMonth = "last")
    @Schedule(dayOfWeek = "Fri", hour = 23)
    public void doPeriodicCleanup() { ... }
    @Repeatable(Schedules.class)
    public @interface Schedule {
    String dayOfMonth() default "first";
    String dayOfWeek() default "Mon";
    int hour() default 12;
    }

    View Slide

  83. Repeating annotations
    41
    @Schedule(dayOfMonth = "last")
    @Schedule(dayOfWeek = "Fri", hour = 23)
    public void doPeriodicCleanup() { ... }
    @Repeatable(Schedules.class)
    public @interface Schedule {
    String dayOfMonth() default "first";
    String dayOfWeek() default "Mon";
    int hour() default 12;
    }
    Container annotation for
    the repeated annotationd

    View Slide

  84. Repeating annotations
    41
    @Schedule(dayOfMonth = "last")
    @Schedule(dayOfWeek = "Fri", hour = 23)
    public void doPeriodicCleanup() { ... }
    @Repeatable(Schedules.class)
    public @interface Schedule {
    String dayOfMonth() default "first";
    String dayOfWeek() default "Mon";
    int hour() default 12;
    }
    public @interface Schedules {
    Schedule[] value();
    }

    View Slide

  85. Repeating annotations
    41
    @Schedule(dayOfMonth = "last")
    @Schedule(dayOfWeek = "Fri", hour = 23)
    public void doPeriodicCleanup() { ... }
    @Repeatable(Schedules.class)
    public @interface Schedule {
    String dayOfMonth() default "first";
    String dayOfWeek() default "Mon";
    int hour() default 12;
    }
    public @interface Schedules {
    Schedule[] value();
    }
    The container
    annotation iteself

    View Slide

  86. Repeating annotations
    41
    @Schedule(dayOfMonth = "last")
    @Schedule(dayOfWeek = "Fri", hour = 23)
    public void doPeriodicCleanup() { ... }
    @Repeatable(Schedules.class)
    public @interface Schedule {
    String dayOfMonth() default "first";
    String dayOfWeek() default "Mon";
    int hour() default 12;
    }
    public @interface Schedules {
    Schedule[] value();
    }

    View Slide

  87. Repeating annotations
    41
    @Schedule(dayOfMonth = "last")
    @Schedule(dayOfWeek = "Fri", hour = 23)
    public void doPeriodicCleanup() { ... }
    @Repeatable(Schedules.class)
    public @interface Schedule {
    String dayOfMonth() default "first";
    String dayOfWeek() default "Mon";
    int hour() default 12;
    }
    public @interface Schedules {
    Schedule[] value();
    }
    Not yet supported

    View Slide

  88. Repeating annotations
    41
    @Schedule(dayOfMonth = "last")
    @Schedule(dayOfWeek = "Fri", hour = 23)
    public void doPeriodicCleanup() { ... }
    @Repeatable(Schedules.class)
    public @interface Schedule {
    String dayOfMonth() default "first";
    String dayOfWeek() default "Mon";
    int hour() default 12;
    }
    public @interface Schedules {
    Schedule[] value();
    }

    View Slide

  89. Annotations on types
    • Everywhere you can put a type, you can put an annotation
    42
    @NonNull String name;
    !
    email = (@Email String) input;
    !
    List<@NonNull String> names;
    !
    new @Interned MyObject();
    !
    void monitorTemperature() throws
    @Critical TemperatureException { ... }
    !
    class UnmodifiableList implements
    @Readonly List<@Readonly T> {...}

    View Slide

  90. Annotations on types
    • Everywhere you can put a type, you can put an annotation
    42
    @NonNull String name;
    !
    email = (@Email String) input;
    !
    List<@NonNull String> names;
    !
    new @Interned MyObject();
    !
    void monitorTemperature() throws
    @Critical TemperatureException { ... }
    !
    class UnmodifiableList implements
    @Readonly List<@Readonly T> {...}
    Not yet supported

    View Slide

  91. Annotations on types
    • Everywhere you can put a type, you can put an annotation
    42
    @NonNull String name;
    !
    email = (@Email String) input;
    !
    List<@NonNull String> names;
    !
    new @Interned MyObject();
    !
    void monitorTemperature() throws
    @Critical TemperatureException { ... }
    !
    class UnmodifiableList implements
    @Readonly List<@Readonly T> {...}
    Imagine the potential for
    targets for local AST
    transformations?

    View Slide

  92. Annotations on types
    • Everywhere you can put a type, you can put an annotation
    42
    @NonNull String name;
    !
    email = (@Email String) input;
    !
    List<@NonNull String> names;
    !
    new @Interned MyObject();
    !
    void monitorTemperature() throws
    @Critical TemperatureException { ... }
    !
    class UnmodifiableList implements
    @Readonly List<@Readonly T> {...}

    View Slide

  93. Groovy compile-time meta-annotations
    43
    @Service
    @Transactional
    class MyTransactionalService {}

    View Slide

  94. Groovy compile-time meta-annotations
    43
    @Service
    @Transactional
    class MyTransactionalService {}
    import groovy.transform.AnnotationCollector
    !
    @Service
    @Transactional
    @AnnotationCollector
    public @interface TransactionalService {}

    View Slide

  95. Groovy compile-time meta-annotations
    43
    import groovy.transform.AnnotationCollector
    !
    @Service
    @Transactional
    @AnnotationCollector
    public @interface TransactionalService {}
    !
    @TransactionalService
    class MyTransactionalService {}

    View Slide

  96. Groovy compile-time meta-annotations
    43
    import groovy.transform.AnnotationCollector
    !
    @Service
    @Transactional
    @AnnotationCollector
    public @interface TransactionalService {}
    !
    @TransactionalService
    class MyTransactionalService {}
    Can handle parameters (even
    conflicting), or you can create
    your own « processor »

    View Slide

  97. Groovy compile-time meta-annotations
    43
    import groovy.transform.AnnotationCollector
    !
    @Service
    @Transactional
    @AnnotationCollector
    public @interface TransactionalService {}
    !
    @TransactionalService
    class MyTransactionalService {}

    View Slide

  98. @glaforge — Groovy in the light of Java 8
    New Java 8 APIs

    View Slide

  99. Date
    and
    Time
    API

    View Slide

  100. Date / Time API
    46
    LocalDate.now();
    today.with(TemporalAdjusters.lastDayOfMonth()).minusDays(2);
    !
    LocalDate.of(2012, Month.MAY, 14);
    dateOfBirth.plusYears(1);
    !
    LocalDate date = LocalDate.of(2000, Month.NOVEMBER, 20);
    LocalDate nextWed =
    date.with(TemporalAdjusters.next(DayOfWeek.WEDNESDAY));

    View Slide

  101. Date / Time API
    46
    LocalDate.now();
    today.with(TemporalAdjusters.lastDayOfMonth()).minusDays(2);
    !
    LocalDate.of(2012, Month.MAY, 14);
    dateOfBirth.plusYears(1);
    !
    LocalDate date = LocalDate.of(2000, Month.NOVEMBER, 20);
    LocalDate nextWed =
    date.with(TemporalAdjusters.next(DayOfWeek.WEDNESDAY));
    Groovy could add some
    operator overloading?

    View Slide

  102. Date / Time API
    46
    LocalDate.now();
    today.with(TemporalAdjusters.lastDayOfMonth()).minusDays(2);
    !
    LocalDate.of(2012, Month.MAY, 14);
    dateOfBirth.plusYears(1);
    !
    LocalDate date = LocalDate.of(2000, Month.NOVEMBER, 20);
    LocalDate nextWed =
    date.with(TemporalAdjusters.next(DayOfWeek.WEDNESDAY));

    View Slide

  103. Groovy’s date / time handling
    47
    import static java.util.Calendar.*
    import groovy.time.*
    import org.codehaus.groovy.runtime.TimeCategory
    !
    def cal = Calendar.instance
    cal.set(year: 2010, month: JULY, date: 9)
    !
    assert FRIDAY == cal[DAY_OF_WEEK]
    !
    use (TimeCategory) {
    2.years + 3.months + 15.days + 23.minutes + 2.seconds
    !
    1.week - 1.day
    new Date() + 6.days
    !
    3.days.ago
    new Date() - 3
    }

    View Slide

  104. Groovy’s date / time handling
    47
    import static java.util.Calendar.*
    import groovy.time.*
    import org.codehaus.groovy.runtime.TimeCategory
    !
    def cal = Calendar.instance
    cal.set(year: 2010, month: JULY, date: 9)
    !
    assert FRIDAY == cal[DAY_OF_WEEK]
    !
    use (TimeCategory) {
    2.years + 3.months + 15.days + 23.minutes + 2.seconds
    !
    1.week - 1.day
    new Date() + 6.days
    !
    3.days.ago
    new Date() - 3
    }
    Groovy could provide the
    same for Date / Time

    View Slide

  105. Groovy’s date / time handling
    47
    import static java.util.Calendar.*
    import groovy.time.*
    import org.codehaus.groovy.runtime.TimeCategory
    !
    def cal = Calendar.instance
    cal.set(year: 2010, month: JULY, date: 9)
    !
    assert FRIDAY == cal[DAY_OF_WEEK]
    !
    use (TimeCategory) {
    2.years + 3.months + 15.days + 23.minutes + 2.seconds
    !
    1.week - 1.day
    new Date() + 6.days
    !
    3.days.ago
    new Date() - 3
    }

    View Slide

  106. Stream
    API

    View Slide

  107. map
    map
    map
    map
    map
    reduce
    reduce reduce
    reduce
    reduce

    View Slide

  108. map
    map
    map
    map
    map
    reduce
    reduce reduce
    reduce
    reduce
    Map / filter / reduce
    explained to
    your 6 year old

    View Slide

  109. map
    map
    map
    map
    map
    reduce
    reduce reduce
    reduce
    reduce

    View Slide

  110. Stream
    50
    persons.stream()
    .filter( p -> p.getAge() < 18 )
    .map( p -> p.getName().toUpperCase() )
    .sorted()
    .collect(Collectors.joining(", "));

    View Slide

  111. Groovy’s functional style with the GDK methods
    51
    persons
    .findAll { it.getAge() < 18 }
    .collect { it.name.toUpperCase() }
    .sort()
    .joining(", ")

    View Slide

  112. Groovy using streams too!
    52
    persons.stream()
    .filter { it.age < 18 }
    .map { it.name.toUpperCase() }
    .sorted()
    .collect(Collectors.joining(", "))

    View Slide

  113. Groovy using streams too!
    52
    persons.stream()
    .filter { it.age < 18 }
    .map { it.name.toUpperCase() }
    .sorted()
    .collect(Collectors.joining(", "))
    Leveraging closure to
    « SAM » type coercion

    View Slide

  114. Groovy using streams too!
    52
    persons.stream()
    .filter { it.age < 18 }
    .map { it.name.toUpperCase() }
    .sorted()
    .collect(Collectors.joining(", "))

    View Slide

  115. Optional
    53
    Optional maybeName = Optional.of("Guillaume");
    !
    String result = maybeName.orElse("unknown")
    !
    if (maybeName.ifPresent()) {
    System.out.println(maybeName.get());
    } else {
    System.out.println("unknown");
    }

    View Slide

  116. Optional
    53
    Optional maybeName = Optional.of("Guillaume");
    !
    String result = maybeName.orElse("unknown")
    !
    if (maybeName.ifPresent()) {
    System.out.println(maybeName.get());
    } else {
    System.out.println("unknown");
    }
    Wrap something that can
    be potentially null

    View Slide

  117. Optional
    53
    Optional maybeName = Optional.of("Guillaume");
    !
    String result = maybeName.orElse("unknown")
    !
    if (maybeName.ifPresent()) {
    System.out.println(maybeName.get());
    } else {
    System.out.println("unknown");
    }

    View Slide

  118. Optional
    53
    Optional maybeName = Optional.of("Guillaume");
    !
    String result = maybeName.orElse("unknown")
    !
    if (maybeName.ifPresent()) {
    System.out.println(maybeName.get());
    } else {
    System.out.println("unknown");
    }
    Force
    handling
    the null
    value

    View Slide

  119. Optional
    53
    Optional maybeName = Optional.of("Guillaume");
    !
    String result = maybeName.orElse("unknown")
    !
    if (maybeName.ifPresent()) {
    System.out.println(maybeName.get());
    } else {
    System.out.println("unknown");
    }

    View Slide

  120. View Slide

  121. You know you can customize
    the truth in Groovy?

    View Slide

  122. You know you can customize
    the truth in Groovy?
    Just implement a custom
    asBoolean() method!

    View Slide

  123. The law of Groovy Truth
    55

    View Slide

  124. The law of Groovy Truth
    55
    Everything that’s null,
    empty, zero-sized, equal
    to zero is false

    View Slide

  125. The law of Groovy Truth
    55
    Everything that’s null,
    empty, zero-sized, equal
    to zero is false
    Otherwise,
    it’s true!

    View Slide

  126. ?:

    View Slide

  127. Groovy truth, null handling, Elvis with Optional
    57
    def maybeName = Optional.of("Guillaume")
    !
    def result = maybeName ?: "unknown"
    !
    if (maybeName) {
    println maybeName.get()
    } else {
    println "unknown"
    }
    !
    maybeName?.toUpperCase()

    View Slide

  128. Groovy truth, null handling, Elvis with Optional
    57
    def maybeName = Optional.of("Guillaume")
    !
    def result = maybeName ?: "unknown"
    !
    if (maybeName) {
    println maybeName.get()
    } else {
    println "unknown"
    }
    !
    maybeName?.toUpperCase()
    Elvis!

    View Slide

  129. Groovy truth, null handling, Elvis with Optional
    57
    def maybeName = Optional.of("Guillaume")
    !
    def result = maybeName ?: "unknown"
    !
    if (maybeName) {
    println maybeName.get()
    } else {
    println "unknown"
    }
    !
    maybeName?.toUpperCase()
    Groovy
    Truth!

    View Slide

  130. Groovy truth, null handling, Elvis with Optional
    57
    def maybeName = Optional.of("Guillaume")
    !
    def result = maybeName ?: "unknown"
    !
    if (maybeName) {
    println maybeName.get()
    } else {
    println "unknown"
    }
    !
    maybeName?.toUpperCase()
    Safe navigation

    View Slide

  131. Groovy truth, null handling, Elvis with Optional
    57
    def maybeName = Optional.of("Guillaume")
    !
    def result = maybeName ?: "unknown"
    !
    if (maybeName) {
    println maybeName.get()
    } else {
    println "unknown"
    }
    !
    maybeName?.toUpperCase()
    Interesting
    discussions on
    the mailing-list
    to further
    enhance usage of
    Optional from
    Groovy

    View Slide

  132. Groovy truth, null handling, Elvis with Optional
    57
    def maybeName = Optional.of("Guillaume")
    !
    def result = maybeName ?: "unknown"
    !
    if (maybeName) {
    println maybeName.get()
    } else {
    println "unknown"
    }
    !
    maybeName?.toUpperCase()
    Not Yet
    Implemented

    View Slide

  133. Groovy truth, null handling, Elvis with Optional
    57
    def maybeName = Optional.of("Guillaume")
    !
    def result = maybeName ?: "unknown"
    !
    if (maybeName) {
    println maybeName.get()
    } else {
    println "unknown"
    }
    !
    maybeName?.toUpperCase()

    View Slide

  134. Nashorn

    View Slide

  135. Nashorn
    Speak German?

    View Slide

  136. Call JavaScript from Groovy with JSR-223
    59
    def manager = new ScriptEngineManager()
    def engine =
    manager.getEngineByName("nashorn")
    !
    assert engine.eval("{} + []") == 0

    View Slide

  137. Call JavaScript from Groovy with JSR-223
    59
    def manager = new ScriptEngineManager()
    def engine =
    manager.getEngineByName("nashorn")
    !
    assert engine.eval("{} + []") == 0
    Sane JavaScript logic :-)

    View Slide

  138. GrooScript — http://grooscript.org/
    60
    JS

    View Slide

  139. GrooScript — http://grooscript.org/
    60
    JS
    Gradle & Grails plugins available
    Examples available with Ratpack, Node.JS…

    View Slide

  140. Turtles all
    the way
    down!

    View Slide

  141. Turtles all
    the way
    down!
    Full Groovy!

    View Slide

  142. Turtles all
    the way
    down!
    Full Groovy!
    Back to front

    View Slide

  143. Turtles all
    the way
    down!
    Full Groovy!
    Back to front
    Front to back

    View Slide

  144. JavaFx…
    !
    !
    …the new Swing

    View Slide

  145. GroovyFX
    63
    import javafx.scene.Scene
    import static groovyx.javafx.GroovyFX.start
    !
    def chamber = ["5 Stelle": 108, "Italia.\nBene commune": 340,
    "Con Monti per l'Italia": 45, "Berlusconi": 124, "others": 4]
    !
    start {
    stage(title: 'Italian chamber of Deputies', width: 1024, height: 700, visible: true) {
    Scene s = scene {
    tilePane {
    barChart(barGap: 10, categoryGap: 20, title: "Italy's election in February 2013") {
    series(name: 'Chamber (seats)',
    data: ['5 Stelle', 17.5, 'Monti', 7.8, 'Bene commune', 55, 'Berlusconi', 19.9])
    series(name: 'Senate (seats)',
    data: ['5 Stelle', 17.4, 'Monti', 6.1, 'Bene commune', 39.1, 'Berlusconi', 37.1])
    }
    pieChart(data: chamber, title: "Chamber of Deputies")
    }
    }
    s.stylesheets.add("Chart.css")
    }
    }

    View Slide

  146. GroovyFX
    63
    import javafx.scene.Scene
    import static groovyx.javafx.GroovyFX.start
    !
    def chamber = ["5 Stelle": 108, "Italia.\nBene commune": 340,
    "Con Monti per l'Italia": 45, "Berlusconi": 124, "others": 4]
    !
    start {
    stage(title: 'Italian chamber of Deputies', width: 1024, height: 700, visible: true) {
    Scene s = scene {
    tilePane {
    barChart(barGap: 10, categoryGap: 20, title: "Italy's election in February 2013") {
    series(name: 'Chamber (seats)',
    data: ['5 Stelle', 17.5, 'Monti', 7.8, 'Bene commune', 55, 'Berlusconi', 19.9])
    series(name: 'Senate (seats)',
    data: ['5 Stelle', 17.4, 'Monti', 6.1, 'Bene commune', 39.1, 'Berlusconi', 37.1])
    }
    pieChart(data: chamber, title: "Chamber of Deputies")
    }
    }
    s.stylesheets.add("Chart.css")
    }
    }
    Groovy builder to
    the rescue!

    View Slide

  147. @glaforge — Groovy in the light of Java 8
    Beyond Java

    View Slide

  148. @glaforge — Groovy in the light of Java 8
    Android

    View Slide

  149. Android support
    • You can use Groovy to code Android apps!

    • use Groovy 2.4.0-beta-1+

    • prefer @CompileStatic

    !
    • Two great posts to get started:

    • http://melix.github.io/blog/2014/06/grooid.html

    • http://melix.github.io/blog/2014/06/grooid2.html
    66

    View Slide

  150. New York Times — Getting Groovy with Android
    67

    View Slide

  151. New York Times — Getting Groovy with Android
    67
    http://bit.ly/nyt-groovy

    View Slide

  152. What does NYT likes about Groovy on Android?
    • No Java 8, no lambda on Android…
    68
    Func0 func = new Func0() {
    @Override
    public String call() {
    return "my content";
    }
    };
    Async.start(func);

    View Slide

  153. What does NYT likes about Groovy on Android?
    • No Java 8, no lambda on Android…
    69
    !
    !
    !
    !
    !
    !
    Async.start { "my content" }

    View Slide

  154. What does NYT likes about Groovy on Android?
    • No Java 8, no lambda on Android…
    69
    !
    !
    !
    !
    !
    !
    Async.start { "my content" }
    Good bye annonymous
    inner classes!

    View Slide

  155. What does NYT likes about Groovy on Android?
    !
    • Groovy code more concise and more readable

    !
    • but just as type-safe as needed!

    (with @TypeChecked)

    !
    • but just as fast as needed!

    (with @CompileStatic)
    70

    View Slide

  156. Android support
    71

    View Slide

  157. Android support
    71
    Source code available:
    https://github.com/melix/gr8confagenda

    View Slide

  158. @glaforge — Groovy in the light of Java 8
    A rich Groovy ecosystem

    View Slide

  159. Grails — web framework
    73
    @Grab("com.h2database:h2:1.3.173")
    import grails.persistence.*
    !
    @Entity
    @Resource(uri='/books')
    class Book {
    String title
    }

    View Slide

  160. Grails — web framework
    73
    @Grab("com.h2database:h2:1.3.173")
    import grails.persistence.*
    !
    @Entity
    @Resource(uri='/books')
    class Book {
    String title
    }
    One class, one command,
    and you’ve got a full REST
    CRUD application!

    View Slide

  161. Ratpack — web framework
    74
    @GrabResolver("https://oss.jfrog.org/artifactory/repo")
    @Grab("org.ratpack-framework:ratpack-groovy:0.9.8")
    import static org.ratpackframework.groovy.RatpackScript.ratpack
    import static org.ratpackframework.groovy.Template.groovyTemplate
    !
    ratpack {
    handlers {
    get {
    response.send "Welcome!"
    }
    !
    get("date") {
    render groovyTemplate("date.html")
    }
    !
    assets "public"
    }
    }

    View Slide

  162. Ratpack — web framework
    74
    @GrabResolver("https://oss.jfrog.org/artifactory/repo")
    @Grab("org.ratpack-framework:ratpack-groovy:0.9.8")
    import static org.ratpackframework.groovy.RatpackScript.ratpack
    import static org.ratpackframework.groovy.Template.groovyTemplate
    !
    ratpack {
    handlers {
    get {
    response.send "Welcome!"
    }
    !
    get("date") {
    render groovyTemplate("date.html")
    }
    !
    assets "public"
    }
    }
    Lightweight Netty-based
    web application toolkit

    View Slide

  163. @ArtifactProviderFor(GriffonModel)
    class ConsoleModel {
    String scriptSource
    @Observable Object scriptResult
    @Observable boolean enabled = true
    }
    Griffon — rich desktop applications
    75

    View Slide

  164. @ArtifactProviderFor(GriffonModel)
    class ConsoleModel {
    String scriptSource
    @Observable Object scriptResult
    @Observable boolean enabled = true
    }
    Griffon — rich desktop applications
    75
    Model

    View Slide

  165. @ArtifactProviderFor(GriffonModel)
    class ConsoleModel {
    String scriptSource
    @Observable Object scriptResult
    @Observable boolean enabled = true
    }
    Griffon — rich desktop applications
    75
    Model
    @ArtifactProviderFor(GriffonController)
    class ConsoleController {
    def model
    !
    @Inject
    Evaluator evaluator
    !
    void executeScript() {
    model.enabled = false
    def result
    try {
    result = evaluator.evaluate(model.scriptSource)
    } finally {
    model.enabled = true
    model.scriptResult = result
    }
    }
    }
    Controller

    View Slide

  166. @ArtifactProviderFor(GriffonModel)
    class ConsoleModel {
    String scriptSource
    @Observable Object scriptResult
    @Observable boolean enabled = true
    }
    Griffon — rich desktop applications
    75
    Model
    @ArtifactProviderFor(GriffonController)
    class ConsoleController {
    def model
    !
    @Inject
    Evaluator evaluator
    !
    void executeScript() {
    model.enabled = false
    def result
    try {
    result = evaluator.evaluate(model.scriptSource)
    } finally {
    model.enabled = true
    model.scriptResult = result
    }
    }
    }
    Controller
    application(title: application.configuration['application.title'],
    pack: true, locationByPlatform: true, id: 'mainWindow',
    iconImage: imageIcon('/griffon-icon-48x48.png').image,
    iconImages: [imageIcon('/griffon-icon-48x48.png').image,
    imageIcon('/griffon-icon-32x32.png').image,
    imageIcon('/griffon-icon-16x16.png').image]) {
    panel(border: emptyBorder(6)) {
    borderLayout()
    scrollPane(constraints: CENTER) {
    textArea(text: bind(target: model, 'scriptSource'),
    enabled: bind { model.enabled },
    columns: 40, rows: 10)
    }
    !
    hbox(constraints: SOUTH) {
    button(executeScriptAction)
    hstrut(5)
    label('Result:')
    hstrut(5)
    textField(editable: false,
    text: bind { model.scriptResult })
    }
    }
    }
    View

    View Slide

  167. Spock — unit testing & specification
    76
    @Grab('org.spockframework:spock-core:0.7-groovy-2.0')
    import spock.lang.*
    !
    class MathSpec extends Specification {
    def "maximum of two numbers"() {
    expect:
    Math.max(a, b) == c
    !
    where:
    a | b || c
    1 | 3 || 3
    7 | 4 || 7
    0 | 0 || 0
    }
    }

    View Slide

  168. Spock — unit testing & specification
    76
    @Grab('org.spockframework:spock-core:0.7-groovy-2.0')
    import spock.lang.*
    !
    class MathSpec extends Specification {
    def "maximum of two numbers"() {
    expect:
    Math.max(a, b) == c
    !
    where:
    a | b || c
    1 | 3 || 3
    7 | 4 || 7
    0 | 0 || 0
    }
    }
    Readable & concise expectations

    View Slide

  169. Spock — unit testing & specification
    76
    @Grab('org.spockframework:spock-core:0.7-groovy-2.0')
    import spock.lang.*
    !
    class MathSpec extends Specification {
    def "maximum of two numbers"() {
    expect:
    Math.max(a, b) == c
    !
    where:
    a | b || c
    1 | 3 || 3
    7 | 4 || 7
    0 | 0 || 0
    }
    }
    Readable & concise expectations
    Awesome data-driven tests
    with a wiki-like notation

    View Slide

  170. Geb — browser automation
    77
    import geb.Browser
    !
    Browser.drive {
    go "http://myapp.com/login"
    !
    assert $("h1").text() == "Please Login"
    !
    $("form.login").with {
    username = "admin"
    password = "password"
    login().click()
    }
    !
    assert $("h1").text() == 

    "Admin Section"
    }

    View Slide

  171. Geb — browser automation
    77
    import geb.Browser
    !
    Browser.drive {
    go "http://myapp.com/login"
    !
    assert $("h1").text() == "Please Login"
    !
    $("form.login").with {
    username = "admin"
    password = "password"
    login().click()
    }
    !
    assert $("h1").text() == 

    "Admin Section"
    }
    Drive your browser

    View Slide

  172. Geb — browser automation
    77
    import geb.Browser
    !
    Browser.drive {
    go "http://myapp.com/login"
    !
    assert $("h1").text() == "Please Login"
    !
    $("form.login").with {
    username = "admin"
    password = "password"
    login().click()
    }
    !
    assert $("h1").text() == 

    "Admin Section"
    }
    Drive your browser
    JQuery-like selectors

    View Slide

  173. Geb — browser automation
    77
    import geb.Browser
    !
    Browser.drive {
    go "http://myapp.com/login"
    !
    assert $("h1").text() == "Please Login"
    !
    $("form.login").with {
    username = "admin"
    password = "password"
    login().click()
    }
    !
    assert $("h1").text() == 

    "Admin Section"
    }
    Drive your browser
    JQuery-like selectors
    Fill & submit forms

    View Slide

  174. Gradle — build automation
    78
    apply plugin: 'java'
    apply plugin: 'eclipse'
    !
    sourceCompatibility = 1.5
    version = '1.0'
    jar {
    manifest {
    attributes 'Implementation-Title': 'Gradle Quickstart'
    }
    }
    !
    repositories {
    mavenCentral()
    }
    !
    dependencies {
    compile ‘commons-collections:commons-collections:3.2’
    testCompile 'junit:junit:4.+'
    }
    !
    uploadArchives {
    repositories {
    flatDir {
    dirs 'repos'
    }
    }
    }

    View Slide

  175. Gradle — build automation
    78
    apply plugin: 'java'
    apply plugin: 'eclipse'
    !
    sourceCompatibility = 1.5
    version = '1.0'
    jar {
    manifest {
    attributes 'Implementation-Title': 'Gradle Quickstart'
    }
    }
    !
    repositories {
    mavenCentral()
    }
    !
    dependencies {
    compile ‘commons-collections:commons-collections:3.2’
    testCompile 'junit:junit:4.+'
    }
    !
    uploadArchives {
    repositories {
    flatDir {
    dirs 'repos'
    }
    }
    }
    Powerful and readable DSL
    for automating your builds
    and deployments

    View Slide

  176. GPars — concurrency / parallelism / async / …
    79
    import static groovyx.gpars.actor.Actors.actor
    !
    def decryptor = actor {
    loop {
    react { message ->
    if (message instanceof String) reply message.reverse()
    else stop()
    }
    }
    }
    !
    def console = actor {
    decryptor.send 'lellarap si yvoorG'
    react {
    println 'Decrypted message: ${it}'
    decryptor.send false
    }
    }
    !
    [decryptor, console]*.join()

    View Slide

  177. GPars — concurrency / parallelism / async / …
    79
    import static groovyx.gpars.actor.Actors.actor
    !
    def decryptor = actor {
    loop {
    react { message ->
    if (message instanceof String) reply message.reverse()
    else stop()
    }
    }
    }
    !
    def console = actor {
    decryptor.send 'lellarap si yvoorG'
    react {
    println 'Decrypted message: ${it}'
    decryptor.send false
    }
    }
    !
    [decryptor, console]*.join()
    Actors…

    View Slide

  178. GPars — concurrency / parallelism / async / …
    79
    import static groovyx.gpars.actor.Actors.actor
    !
    def decryptor = actor {
    loop {
    react { message ->
    if (message instanceof String) reply message.reverse()
    else stop()
    }
    }
    }
    !
    def console = actor {
    decryptor.send 'lellarap si yvoorG'
    react {
    println 'Decrypted message: ${it}'
    decryptor.send false
    }
    }
    !
    [decryptor, console]*.join()
    Actors…
    But also:
    Dataflow concurrency, CSP, agents,
    concurrent collection processing,
    fork / join, composable async
    functions, STM

    View Slide

  179. @glaforge — Groovy in the light of Java 8
    Groovy modules

    View Slide

  180. Groovy modules
    • Ant scripting

    • JMX

    • JSON

    • Servlet

    • Swing

    • SQL

    • Templating

    • Testing

    • XML
    81

    View Slide

  181. Groovy modules
    • Ant scripting
    • JMX

    • JSON
    • Servlet

    • Swing

    • SQL

    • Templating
    • Testing

    • XML
    82

    View Slide

  182. Ant + XML
    83
    def writer = new StringWriter()
    def mkp = new MarkupBuilder(writer)
    !
    mkp.html {
    head { title 'Build notification' }
    body { p 'Your build was successful' }
    }
    !
    new AntBuilder().mail(mailhost: 'localhost',
    messagemimetype: 'text/html',
    subject: 'Build successful') {
    !
    from address: '[email protected]'
    to address: '[email protected]'
    message writer
    attchments {
    fileset(dir: 'dist') {
    include name: '**/logs*.txt'
    }
    }
    }

    View Slide

  183. Ant + XML
    83
    def writer = new StringWriter()
    def mkp = new MarkupBuilder(writer)
    !
    mkp.html {
    head { title 'Build notification' }
    body { p 'Your build was successful' }
    }
    !
    new AntBuilder().mail(mailhost: 'localhost',
    messagemimetype: 'text/html',
    subject: 'Build successful') {
    !
    from address: '[email protected]'
    to address: '[email protected]'
    message writer
    attchments {
    fileset(dir: 'dist') {
    include name: '**/logs*.txt'
    }
    }
    }
    Generate some HTML
    with the XML support

    View Slide

  184. Ant + XML
    83
    def writer = new StringWriter()
    def mkp = new MarkupBuilder(writer)
    !
    mkp.html {
    head { title 'Build notification' }
    body { p 'Your build was successful' }
    }
    !
    new AntBuilder().mail(mailhost: 'localhost',
    messagemimetype: 'text/html',
    subject: 'Build successful') {
    !
    from address: '[email protected]'
    to address: '[email protected]'
    message writer
    attchments {
    fileset(dir: 'dist') {
    include name: '**/logs*.txt'
    }
    }
    }
    Generate some HTML
    with the XML support
    Use the Ant builder
    and the mail task

    View Slide

  185. Ant + XML
    83
    def writer = new StringWriter()
    def mkp = new MarkupBuilder(writer)
    !
    mkp.html {
    head { title 'Build notification' }
    body { p 'Your build was successful' }
    }
    !
    new AntBuilder().mail(mailhost: 'localhost',
    messagemimetype: 'text/html',
    subject: 'Build successful') {
    !
    from address: '[email protected]'
    to address: '[email protected]'
    message writer
    attchments {
    fileset(dir: 'dist') {
    include name: '**/logs*.txt'
    }
    }
    }
    Generate some HTML
    with the XML support
    Use the Ant builder
    and the mail task
    Use the Ant’s fileset

    View Slide

  186. JSON support — creating JSON
    84
    import groovy.json.*
    !
    def json = new JsonBuilder()
    json.person {
    name 'Guillaume'
    age 37
    daughters 'Marion', 'Erine'
    address {
    street '1 Main Street'
    zip 75001
    city 'Paris'
    }
    }

    View Slide

  187. JSON support — creating JSON
    84
    import groovy.json.*
    !
    def json = new JsonBuilder()
    json.person {
    name 'Guillaume'
    age 37
    daughters 'Marion', 'Erine'
    address {
    street '1 Main Street'
    zip 75001
    city 'Paris'
    }
    }
    {
    "person": {
    "name": "Guillaume",
    "age": 37,
    "daughters": [
    "Marion",
    "Erine"
    ],
    "address": {
    "street": "1 Main Street",
    "zip": 75001,
    "city": "Paris"
    }
    }
    }

    View Slide

  188. JSON support — parsing JSON
    85
    import groovy.json.*
    !
    def url = 

    "https://api.github.com/repos/groovy/groovy-core/commits"
    !
    def commits = new JsonSlurper().parseText(url.toURL().text)
    !
    assert commits[0].commit.author.name == 'Cedric Champeau'

    View Slide

  189. JSON support — parsing JSON
    85
    import groovy.json.*
    !
    def url = 

    "https://api.github.com/repos/groovy/groovy-core/commits"
    !
    def commits = new JsonSlurper().parseText(url.toURL().text)
    !
    assert commits[0].commit.author.name == 'Cedric Champeau'
    The power of a dynamic language!

    View Slide

  190. Template module — new markup template engine
    • Based on the principles of Groovy’s « builders »

    • and particularly the MarkupBuilder class

    for generating arbitrary XML / HTML payloads

    !
    • Compiled statically for fast template rendering

    !
    • Internationalization aware

    • provide the desired Locale in the configuration object

    • usual suffix notation template_fr_FR.tpl

    !
    • Custom base template class

    • ability to provide reusable methods across your templates 86

    View Slide

  191. Template module — new markup template engine
    • Based on the principles of Groovy’s « builders »

    • and particularly the MarkupBuilder class

    for generating arbitrary XML / HTML payloads

    !
    • Compiled statically for fast template rendering

    !
    • Internationalization aware

    • provide the desired Locale in the configuration object

    • usual suffix notation template_fr_FR.tpl

    !
    • Custom base template class

    • ability to provide reusable methods across your templates 86
    Spring Boot
    approved

    View Slide

  192. Markup template engine — the idea
    87
    cars {
    cars.each {
    car(make: it.make, name: it.name)
    }
    }

    View Slide

  193. Markup template engine — the idea
    87
    cars {
    cars.each {
    car(make: it.make, name: it.name)
    }
    }
    Your template

    View Slide

  194. Markup template engine — the idea
    87
    cars {
    cars.each {
    car(make: it.make, name: it.name)
    }
    }
    model = [cars: [
    new Car(make: 'Peugeot', name: '508'),
    new Car(make: 'Toyota', name: 'Prius’)
    ]]

    View Slide

  195. Markup template engine — the idea
    87
    cars {
    cars.each {
    car(make: it.make, name: it.name)
    }
    }
    model = [cars: [
    new Car(make: 'Peugeot', name: '508'),
    new Car(make: 'Toyota', name: 'Prius’)
    ]]
    Feed a model into
    your template

    View Slide

  196. Markup template engine — the idea
    87
    cars {
    cars.each {
    car(make: it.make, name: it.name)
    }
    }
    model = [cars: [
    new Car(make: 'Peugeot', name: '508'),
    new Car(make: 'Toyota', name: 'Prius’)
    ]]




    View Slide

  197. Markup template engine — the idea
    87
    cars {
    cars.each {
    car(make: it.make, name: it.name)
    }
    }
    model = [cars: [
    new Car(make: 'Peugeot', name: '508'),
    new Car(make: 'Toyota', name: 'Prius’)
    ]]




    Generate the
    XML output

    View Slide

  198. Markup template engine — the idea
    87
    cars {
    cars.each {
    car(make: it.make, name: it.name)
    }
    }
    model = [cars: [
    new Car(make: 'Peugeot', name: '508'),
    new Car(make: 'Toyota', name: 'Prius’)
    ]]




    View Slide

  199. Markup template engine — in action
    88
    import  groovy.text.markup.*  
    !
    def  config  =  new  TemplateConfiguration()  
    def  engine  =  new  MarkupTemplateEngine(config)  
    def  tmpl  =  engine.createTemplate('''  
           p("Hello  ${model.name}")  
    ''')  
    def  model  =  [name:  'World']  
    System.out  <<  tmpl.make(model)

    View Slide

  200. @glaforge — Groovy in the light of Java 8
    Summary

    View Slide

  201. Back to our original question…
    Do we still need
    Groovy now that
    we have Java 8?
    90

    View Slide

  202. View Slide

  203. Longer answer: Yes, because…
    • You can benefit from Java 8 in Groovy
    92
    Synergy

    the whole is 

    greater than
    the sum of
    the parts

    View Slide

  204. Longer answer: Yes, because…
    • Groovy goes beyond what Java 8 offers
    93
    Beyond

    Groovy always
    tries to add
    something
    to the table

    View Slide

  205. Questions still open: Syntax support for…
    • lambdas
    • not necessarily,

    (confusing / duplication)

    !
    • method references
    • enhance method closures

    • or replace them with
    method references

    !
    • interface default methods
    • yes: traits methods aren’t
    default methods

    • repeated annotations
    • yes: not urgent

    • but less boilerplate is good

    !
    • annotations on type
    • yes: opens up new
    possibilities for targets of
    local AST transformation

    !
    • interface static methods
    • yes: for Java compatibility
    94

    View Slide

  206. Further possible API enhancements
    • Make Optional Groovy-friendly
    • with regards to Groovy Truth
    • accessing the wrapped value
    !
    • More Groovy methods for…
    • NIO
    • Streams
    • Date / time
    !
    • Operator overloading for Date / time
    • for arithmetics on instants and durations
    95

    View Slide

  207. Further possible API enhancements
    • Make Optional Groovy-friendly
    • with regards to Groovy Truth
    • accessing the wrapped value
    !
    • More Groovy methods for…
    • NIO
    • Streams
    • Date / time
    !
    • Operator overloading for Date / time
    • for arithmetics on instants and durations
    95
    Community
    feedback &
    contributions
    welcome!

    View Slide

  208. @glaforge — Groovy in the light of Java 8
    Q & A

    View Slide

  209. View Slide

  210. Image credits
    • Question mark
    • http://www.mynamesnotmommy.com/wp-content/uploads/2013/05/question-mark.png

    • Get out!
    • http://static.comicvine.com/uploads/original/11/117995/3772037-0075368930-27616.jpg

    • Yes
    • http://soloprpro.com/wp-content/uploads/2013/08/yes.jpg

    • Synergy
    • http://www.wildblueberries.com/wp-content/uploads/blogger/_YhH8fDK5-kU/S_5kYWwgAbI/AAAAAAAAAKU/JQ_-ISfT9KY/s1600/
    teamwork.jpg

    • Buzz Lightyear
    • http://www.disneypictures.net/data/media/202/Buzz_Lightyear_hd.jpg

    • Start wars spaceship
    • http://swc.fs2downloads.com/media/screenshots/Support_Trans/Shuttle/lambda003.jpg

    • Lambda character
    • http://lambda.ninjackaton.ninja-squad.com/images/lambda.png

    • Man clock
    • http://3.bp.blogspot.com/-7hLQ9tnmA84/TuTIoLRLMTI/AAAAAAAABWM/g7ahyLCRjJQ/s1600/Harold+Lloyd+Safety+Last.jpg

    • Stream
    • http://wallpaperswide.com/forest_stream-wallpapers.html

    • Nashorn (rhino)
    • http://2010sdafrika.files.wordpress.com/2012/07/hi_257587-nashorn-c-naturepl-com-mark-carwardine-wwf-canon.jpg 98

    View Slide

  211. Image credits
    • Brain
    • http://www.semel.ucla.edu/sites/all/files/users/user-412/dreamstime_xxl_17754591%20(2).jpg
    • Many thanks
    • http://www.trys.ie/wp-content/uploads/2013/06/many-thanks.jpg
    • Swing
    • http://makemesomethingspecial.co.uk/wp-content/uploads/2012/10/Solid-Oak-Handmade-Spliced-Swing-With-Personalised-
    Engraving-10867.jpg
    • Disclaimer
    • http://3.bp.blogspot.com/-RGnBpjXTCQA/Tj2h_JsLigI/AAAAAAAABbg/AB5ZZYzuE5w/s1600/disclaimer.jpg
    • Hammer / justice / truth
    • http://www.bombayrealty.in/images/disclaimer.jpg
    • Law
    • http://www.permanentmakeupbymv.com/wp-content/uploads/2014/07/law-2.jpg
    • Glasses / readable
    • http://a.fastcompany.net/multisite_files/coexist/imagecache/1280/poster/2013/02/1681393-poster-1280-responsive-eye-chart.jpg
    • We need you
    • http://www.bostonbreakerssoccer.com/imgs/ABOUT/volopps/we%20need%20you.JPG
    • Golden Gate
    • http://www.airpano.com/files/San-Francisco-Golden-Gate-USA/sf_golden_gate.jpg
    99

    View Slide

  212. Image credits
    • Turtles
    • http://33.media.tumblr.com/77095e3a37acb2272133c405b1f7ba54/tumblr_myfydjNgXJ1s20kxvo1_1280.jpg
    • Annotations
    • http://3.bp.blogspot.com/-f94n9BHko_s/T35ELs7nYvI/AAAAAAAAAKg/qe06LRPH9U4/s1600/IMG_1721.JPG
    • Builders
    • http://detroittraining.com/wp-content/uploads/Construction-Women2.jpg
    • Sandwich ingredients
    • http://www.fromages-de-terroirs.com/IMG/MEULE_DETOUREE_72_DPI_-2.jpg
    • http://eboutique-hebergement.orange-business.com/WebRoot/Orange/Shops/Madeinalsace/4B02/6320/943E/DB4F/DDBF/
    0A0A/33E8/4BC8/iStock_000008775559XSmall.jpg
    • http://www.cmonprimeur.fr/images/25834-vegetable-pictures%5B1%5D.jpg
    • http://1.bp.blogspot.com/-27UoqYeYtY4/T4PAr4zGSnI/AAAAAAAAA3s/lleE-NOh0LE/s1600/IMG_1528.JPG
    • http://www.growingpatch.com/wp-content/uploads/2014/05/tomato-9.jpg
    • http://vitaminsandhealthsupplements.com/wp-content/uploads/2013/08/fresh-sliced-tomato.jpg
    • http://2.bp.blogspot.com/-3pPmRhBHv9s/T3D-EtLlN1I/AAAAAAAAAgg/Y5oTM84nGb8/s1600/cochon+2.jpg
    • http://www.salamarket.fr/wp-content/uploads/steak-hach%C3%A9.jpg
    • http://www.quinzanisbakery.com/images/bread-vienna.jpg
    • http://www.saucissonvaudois.qc.ca/images/produits/Jambon_blanc.jpg
    • http://www.audion.com/system/public/categories/125/images/bread-sandwich.jpg
    100

    View Slide