Slide 1

Slide 1 text

@glaforge #devoxx #groovylang Groovy in the light of Java 8 Guillaume Laforge Groovy project manager

Slide 2

Slide 2 text

@glaforge #devoxx #groovylang Stay up-to-date Groovy Weekly newsletter (every Tuesday) 
 http://beta.groovy-lang.org/groovy-weekly.html 2

Slide 3

Slide 3 text

@glaforge #devoxx #groovylang Goal of this talk

Slide 4

Slide 4 text

@glaforge #devoxx #groovylang A recurring question… Do we still need Groovy now that we have Java 8? 4

Slide 5

Slide 5 text

@glaforge #devoxx #groovylang To those who said no… 5

Slide 6

Slide 6 text

@glaforge #devoxx #groovylang 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

Slide 7

Slide 7 text

@glaforge #devoxx #groovylang What about redundancy? • Closures • Traits • Truth & null handling • Functional with collections • Method closures • Lambdas • Default methods • Optional • Stream API • Method references 7

Slide 8

Slide 8 text

@glaforge #devoxx #groovylang What’s new in Java 8?

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

@glaforge #devoxx #groovylang 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

Slide 13

Slide 13 text

@glaforge #devoxx #groovylang 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

Slide 14

Slide 14 text

@glaforge #devoxx #groovylang New Java 8 syntax

Slide 15

Slide 15 text

@glaforge #devoxx #groovylang 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

Slide 16

Slide 16 text

@glaforge #devoxx #groovylang 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

Slide 17

Slide 17 text

No content

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

No content

Slide 20

Slide 20 text

@glaforge #devoxx #groovylang Lambda expressions 15 double highestScore = students .filter(Student s -> s.getGradYear() == 2011) .map(Student s -> s.getScore()) .max();

Slide 21

Slide 21 text

@glaforge #devoxx #groovylang Lambda expressions 16 double highestScore = students .filter(Student s -> s.getGradYear() == 2011) .map(Student s -> s.getScore()) .max();

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

@glaforge #devoxx #groovylang Lambda expressions 16 double highestScore = students .filter(Student s -> s.getGradYear() == 2011) .map(Student s -> s.getScore()) .max();

Slide 26

Slide 26 text

@glaforge #devoxx #groovylang Lambda expressions 17 double highestScore = students .findAll { it.gradYear == 2011 } .collect { it.score} .max()

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

@glaforge #devoxx #groovylang Lambda expressions 17 double highestScore = students .findAll { it.gradYear == 2011 } .collect { it.score} .max()

Slide 30

Slide 30 text

@glaforge #devoxx #groovylang Lambda expressions 18 double highestScore = students .filter { Student s -> s.gradYear == 2011 } .map { Student s -> s.getScore() } .max()

Slide 31

Slide 31 text

@glaforge #devoxx #groovylang Lambda expressions 18 double highestScore = students .filter { Student s -> s.gradYear == 2011 } .map { Student s -> s.getScore() } .max() Same coercion to Predicate but works for abstract classes too

Slide 32

Slide 32 text

@glaforge #devoxx #groovylang Lambda expressions 18 double highestScore = students .filter { Student s -> s.gradYear == 2011 } .map { Student s -> s.getScore() } .max()

Slide 33

Slide 33 text

@glaforge #devoxx #groovylang The various lambda syntaxes 19 String name -> name.length() (int left, int right) -> left + right (String left, String sep, String right) -> { System.out.println(left + sep + right) }

Slide 34

Slide 34 text

@glaforge #devoxx #groovylang The various lambda syntaxes 19 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

Slide 35

Slide 35 text

@glaforge #devoxx #groovylang The various lambda syntaxes 19 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

Slide 36

Slide 36 text

@glaforge #devoxx #groovylang The various lambda syntaxes 19 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

Slide 37

Slide 37 text

@glaforge #devoxx #groovylang The various lambda syntaxes 19 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

Slide 38

Slide 38 text

@glaforge #devoxx #groovylang Closures vs lambdas 20 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));

Slide 39

Slide 39 text

@glaforge #devoxx #groovylang Closures vs lambdas 20 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 }

Slide 40

Slide 40 text

@glaforge #devoxx #groovylang Closures vs lambdas 20 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

Slide 41

Slide 41 text

@glaforge #devoxx #groovylang Closures vs lambdas 20 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)

Slide 42

Slide 42 text

@glaforge #devoxx #groovylang Closures vs lambdas 20 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 }

Slide 43

Slide 43 text

@glaforge #devoxx #groovylang Beyond: Closure default parameters 21 def mult = { int a, int b = 10 -> a * b } assert mult(2, 3) == 6 assert mult(5) == 50

Slide 44

Slide 44 text

@glaforge #devoxx #groovylang Beyond: Closure default parameters 21 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

Slide 45

Slide 45 text

@glaforge #devoxx #groovylang Beyond: Duck typing polymorphism 22 def adder = { a, b -> a + b } assert adder(100, 200) == 300 assert adder('X', 'Y') == 'XY'

Slide 46

Slide 46 text

@glaforge #devoxx #groovylang Beyond: Duck typing polymorphism 22 def adder = { a, b -> a + b } assert adder(100, 200) == 300 assert adder('X', 'Y') == 'XY' Works both for numbers and for strings

Slide 47

Slide 47 text

Builders

Slide 48

Slide 48 text

Builders What would Java lambda builders look like?

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

@glaforge #devoxx #groovylang Lambda-based builders uglier and less 24 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"); }); });

Slide 51

Slide 51 text

@glaforge #devoxx #groovylang Lambda-based builders uglier and less 24 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

Slide 52

Slide 52 text

@glaforge #devoxx #groovylang Lambda-based builders uglier and less 24 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

Slide 53

Slide 53 text

@glaforge #devoxx #groovylang Lambda-based builders uglier and less 24 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

Slide 54

Slide 54 text

@glaforge #devoxx #groovylang Neater Groovy builder! 25 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" } } }

Slide 55

Slide 55 text

@glaforge #devoxx #groovylang Neater Groovy builder! 25 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" } } }

Slide 56

Slide 56 text

No content

Slide 57

Slide 57 text

Aren’t Groovy builders more readable and lean?

Slide 58

Slide 58 text

@glaforge #devoxx #groovylang To those who said no… 27

Slide 59

Slide 59 text

Memoization

Slide 60

Slide 60 text

@glaforge #devoxx #groovylang Closure and method memoization 29 def fib2 = { long n -> if (n < 2) 1 else call(n - 1) + call(n - 2) }.memoize()

Slide 61

Slide 61 text

@glaforge #devoxx #groovylang Closure and method memoization 29 def fib2 = { long n -> if (n < 2) 1 else call(n - 1) + call(n - 2) }.memoize() Closures: memoize()

Slide 62

Slide 62 text

@glaforge #devoxx #groovylang Closure and method memoization 29 @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()

Slide 63

Slide 63 text

@glaforge #devoxx #groovylang Closure and method memoization 29 @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

Slide 64

Slide 64 text

No content

Slide 65

Slide 65 text

Tail recursion

Slide 66

Slide 66 text

@glaforge #devoxx #groovylang Closure and method tail recursion 31 def fact = { n, accu = 1G -> if (n < 2) accu else fact.trampoline(n - 1, n * accu) }.trampoline()

Slide 67

Slide 67 text

@glaforge #devoxx #groovylang Closure and method tail recursion 31 def fact = { n, accu = 1G -> if (n < 2) accu else fact.trampoline(n - 1, n * accu) }.trampoline() Closures: Tail recursion with trampoline()

Slide 68

Slide 68 text

@glaforge #devoxx #groovylang Closure and method tail recursion 31 @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()

Slide 69

Slide 69 text

@glaforge #devoxx #groovylang Closure and method tail recursion 31 @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

Slide 70

Slide 70 text

@glaforge #devoxx #groovylang Method references 32 button.setOnAction(event -> System.out.println(event));

Slide 71

Slide 71 text

@glaforge #devoxx #groovylang Method references 32 button.setOnAction(event -> System.out.println(event)); button.setOnAction(System.out::println);

Slide 72

Slide 72 text

@glaforge #devoxx #groovylang Method references — 3 main cases • Three main cases: 33 instance::instanceMethod SomeClass::staticMethod SomeClass::instanceMethod

Slide 73

Slide 73 text

@glaforge #devoxx #groovylang Method references — 3 main cases • Three main cases: 33 instance::instanceMethod SomeClass::staticMethod SomeClass::instanceMethod Not covered by Groovy method closures yet!

Slide 74

Slide 74 text

@glaforge #devoxx #groovylang Groovy’s method closure 34 instance.&instanceMethod SomeClass.&staticMethod SomeClass.&instanceMethod

Slide 75

Slide 75 text

@glaforge #devoxx #groovylang Groovy’s method closure 34 instance.&instanceMethod SomeClass.&staticMethod SomeClass.&instanceMethod Choices: Adopt :: Deprecate .& Enhance .&

Slide 76

Slide 76 text

@glaforge #devoxx #groovylang Static methods in interfaces • You can put static utility methods in interfaces, 
 instead of in companion classes (like « Collections ») 35 public interface Stream { // ... static Stream empty() { return new Stream { ... } } }

Slide 77

Slide 77 text

@glaforge #devoxx #groovylang Default methods in interfaces • Define default behavior • possibly to enrich existing interfaces 36 public interface Stream { // ... default Builder add(T t) { ... } }

Slide 78

Slide 78 text

@glaforge #devoxx #groovylang 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 37

Slide 79

Slide 79 text

@glaforge #devoxx #groovylang Simple trait 38 trait FlyingAbility { String fly() { "I'm flying!" } } class Bird implements FlyingAbility {} def b = new Bird() assert b.fly() == "I'm flying!"

Slide 80

Slide 80 text

@glaforge #devoxx #groovylang Trait with state 39 trait Named { String name } class Bird implements Named {} def b = new Bird(name: 'Colibri') assert b.name == 'Colibri'

Slide 81

Slide 81 text

@glaforge #devoxx #groovylang Multiple inheritance 40 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'

Slide 82

Slide 82 text

Annotations on types Repeating annotations

Slide 83

Slide 83 text

@glaforge #devoxx #groovylang Repeating annotations 42 @Schedule(dayOfMonth = "last") @Schedule(dayOfWeek = "Fri", hour = 23) public void doPeriodicCleanup() { ... }

Slide 84

Slide 84 text

@glaforge #devoxx #groovylang Repeating annotations 42 @Schedule(dayOfMonth = "last") @Schedule(dayOfWeek = "Fri", hour = 23) public void doPeriodicCleanup() { ... } @Schedule annotation repeated twice

Slide 85

Slide 85 text

@glaforge #devoxx #groovylang Repeating annotations 42 @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; }

Slide 86

Slide 86 text

@glaforge #devoxx #groovylang Repeating annotations 42 @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

Slide 87

Slide 87 text

@glaforge #devoxx #groovylang Repeating annotations 42 @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(); }

Slide 88

Slide 88 text

@glaforge #devoxx #groovylang Repeating annotations 42 @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

Slide 89

Slide 89 text

@glaforge #devoxx #groovylang Repeating annotations 42 @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(); }

Slide 90

Slide 90 text

@glaforge #devoxx #groovylang Repeating annotations 42 @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

Slide 91

Slide 91 text

@glaforge #devoxx #groovylang Repeating annotations 42 @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(); }

Slide 92

Slide 92 text

@glaforge #devoxx #groovylang Annotations on types • Everywhere you can put a type, you can put an annotation 43 @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> {...}

Slide 93

Slide 93 text

@glaforge #devoxx #groovylang Annotations on types • Everywhere you can put a type, you can put an annotation 43 @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

Slide 94

Slide 94 text

@glaforge #devoxx #groovylang Annotations on types • Everywhere you can put a type, you can put an annotation 43 @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?

Slide 95

Slide 95 text

@glaforge #devoxx #groovylang Annotations on types • Everywhere you can put a type, you can put an annotation 43 @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> {...}

Slide 96

Slide 96 text

@glaforge #devoxx #groovylang Groovy compile-time meta-annotations 44 @Service @Transactional class MyTransactionalService {}

Slide 97

Slide 97 text

@glaforge #devoxx #groovylang Groovy compile-time meta-annotations 44 @Service @Transactional class MyTransactionalService {} import groovy.transform.AnnotationCollector @Service @Transactional @AnnotationCollector public @interface TransactionalService {}

Slide 98

Slide 98 text

@glaforge #devoxx #groovylang Groovy compile-time meta-annotations 44 import groovy.transform.AnnotationCollector @Service @Transactional @AnnotationCollector public @interface TransactionalService {} @TransactionalService class MyTransactionalService {}

Slide 99

Slide 99 text

@glaforge #devoxx #groovylang Groovy compile-time meta-annotations 44 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 »

Slide 100

Slide 100 text

@glaforge #devoxx #groovylang Groovy compile-time meta-annotations 44 import groovy.transform.AnnotationCollector @Service @Transactional @AnnotationCollector public @interface TransactionalService {} @TransactionalService class MyTransactionalService {}

Slide 101

Slide 101 text

@glaforge #devoxx #groovylang New Java 8 APIs

Slide 102

Slide 102 text

Date and Time API

Slide 103

Slide 103 text

@glaforge #devoxx #groovylang Date / Time API 47 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));

Slide 104

Slide 104 text

@glaforge #devoxx #groovylang Date / Time API 47 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?

Slide 105

Slide 105 text

@glaforge #devoxx #groovylang Date / Time API 47 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));

Slide 106

Slide 106 text

@glaforge #devoxx #groovylang Groovy’s date / time handling 48 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 }

Slide 107

Slide 107 text

@glaforge #devoxx #groovylang Groovy’s date / time handling 48 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

Slide 108

Slide 108 text

@glaforge #devoxx #groovylang Groovy’s date / time handling 48 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 }

Slide 109

Slide 109 text

Stream API

Slide 110

Slide 110 text

map map map map map reduce reduce reduce reduce reduce

Slide 111

Slide 111 text

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

Slide 112

Slide 112 text

map map map map map reduce reduce reduce reduce reduce

Slide 113

Slide 113 text

@glaforge #devoxx #groovylang Stream 51 persons.stream() .filter( p -> p.getAge() < 18 ) .map( p -> p.getName().toUpperCase() ) .sorted() .collect(Collectors.joining(", "));

Slide 114

Slide 114 text

@glaforge #devoxx #groovylang Groovy’s functional style with GDK methods 52 persons .findAll { it.getAge() < 18 } .collect { it.name.toUpperCase() } .sort() .join(", ")

Slide 115

Slide 115 text

@glaforge #devoxx #groovylang Groovy using streams too! 53 persons.stream() .filter { it.age < 18 } .map { it.name.toUpperCase() } .sorted() .collect(Collectors.joining(", "))

Slide 116

Slide 116 text

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

Slide 117

Slide 117 text

@glaforge #devoxx #groovylang Groovy using streams too! 53 persons.stream() .filter { it.age < 18 } .map { it.name.toUpperCase() } .sorted() .collect(Collectors.joining(", "))

Slide 118

Slide 118 text

@glaforge #devoxx #groovylang Optional 54 Optional maybeName = Optional.of("Guillaume"); String result = maybeName.orElse("unknown") if (maybeName.ifPresent()) { System.out.println(maybeName.get()); } else { System.out.println("unknown"); }

Slide 119

Slide 119 text

@glaforge #devoxx #groovylang Optional 54 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

Slide 120

Slide 120 text

@glaforge #devoxx #groovylang Optional 54 Optional maybeName = Optional.of("Guillaume"); String result = maybeName.orElse("unknown") if (maybeName.ifPresent()) { System.out.println(maybeName.get()); } else { System.out.println("unknown"); }

Slide 121

Slide 121 text

@glaforge #devoxx #groovylang Optional 54 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

Slide 122

Slide 122 text

@glaforge #devoxx #groovylang Optional 54 Optional maybeName = Optional.of("Guillaume"); String result = maybeName.orElse("unknown") if (maybeName.ifPresent()) { System.out.println(maybeName.get()); } else { System.out.println("unknown"); }

Slide 123

Slide 123 text

No content

Slide 124

Slide 124 text

You know you can customize the truth in Groovy?

Slide 125

Slide 125 text

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

Slide 126

Slide 126 text

@glaforge #devoxx #groovylang The law of Groovy Truth 56

Slide 127

Slide 127 text

@glaforge #devoxx #groovylang The law of Groovy Truth 56 Everything that’s null, empty, zero-sized, equal to zero is false

Slide 128

Slide 128 text

@glaforge #devoxx #groovylang The law of Groovy Truth 56 Everything that’s null, empty, zero-sized, equal to zero is false Otherwise, it’s true!

Slide 129

Slide 129 text

?:

Slide 130

Slide 130 text

@glaforge #devoxx #groovylang Groovy truth, null handling, Elvis & Optional 58 def maybeName = Optional.of("Guillaume") def result = maybeName ?: "unknown" if (maybeName) { println maybeName.get() } else { println "unknown" } maybeName?.toUpperCase()

Slide 131

Slide 131 text

@glaforge #devoxx #groovylang Groovy truth, null handling, Elvis & Optional 58 def maybeName = Optional.of("Guillaume") def result = maybeName ?: "unknown" if (maybeName) { println maybeName.get() } else { println "unknown" } maybeName?.toUpperCase() Elvis!

Slide 132

Slide 132 text

@glaforge #devoxx #groovylang Groovy truth, null handling, Elvis & Optional 58 def maybeName = Optional.of("Guillaume") def result = maybeName ?: "unknown" if (maybeName) { println maybeName.get() } else { println "unknown" } maybeName?.toUpperCase() Groovy Truth!

Slide 133

Slide 133 text

@glaforge #devoxx #groovylang Groovy truth, null handling, Elvis & Optional 58 def maybeName = Optional.of("Guillaume") def result = maybeName ?: "unknown" if (maybeName) { println maybeName.get() } else { println "unknown" } maybeName?.toUpperCase() Safe navigation

Slide 134

Slide 134 text

@glaforge #devoxx #groovylang Groovy truth, null handling, Elvis & Optional 58 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

Slide 135

Slide 135 text

@glaforge #devoxx #groovylang Groovy truth, null handling, Elvis & Optional 58 def maybeName = Optional.of("Guillaume") def result = maybeName ?: "unknown" if (maybeName) { println maybeName.get() } else { println "unknown" } maybeName?.toUpperCase() Not Yet Implemented

Slide 136

Slide 136 text

@glaforge #devoxx #groovylang Groovy truth, null handling, Elvis & Optional 58 def maybeName = Optional.of("Guillaume") def result = maybeName ?: "unknown" if (maybeName) { println maybeName.get() } else { println "unknown" } maybeName?.toUpperCase()

Slide 137

Slide 137 text

Nashorn

Slide 138

Slide 138 text

Nashorn Speak German?

Slide 139

Slide 139 text

@glaforge #devoxx #groovylang Call JavaScript from Groovy with JSR-223 60 def manager = new ScriptEngineManager() def engine = manager.getEngineByName("nashorn") assert engine.eval("{} + []") == 0

Slide 140

Slide 140 text

@glaforge #devoxx #groovylang Call JavaScript from Groovy with JSR-223 60 def manager = new ScriptEngineManager() def engine = manager.getEngineByName("nashorn") assert engine.eval("{} + []") == 0 Sane JavaScript logic :-)

Slide 141

Slide 141 text

@glaforge #devoxx #groovylang GrooScript — http://grooscript.org/ 61 JS

Slide 142

Slide 142 text

@glaforge #devoxx #groovylang GrooScript — http://grooscript.org/ 61 JS Gradle & Grails plugins available Examples available with Ratpack, Node.JS…

Slide 143

Slide 143 text

Turtles all the way down!

Slide 144

Slide 144 text

Turtles all the way down! Full Groovy!

Slide 145

Slide 145 text

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

Slide 146

Slide 146 text

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

Slide 147

Slide 147 text

JavaFx… …the new Swing

Slide 148

Slide 148 text

@glaforge #devoxx #groovylang GroovyFX 64 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") } }

Slide 149

Slide 149 text

@glaforge #devoxx #groovylang GroovyFX 64 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!

Slide 150

Slide 150 text

@glaforge #devoxx #groovylang Beyond Java

Slide 151

Slide 151 text

@glaforge #devoxx #groovylang Android

Slide 152

Slide 152 text

@glaforge #devoxx #groovylang 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 67

Slide 153

Slide 153 text

@glaforge #devoxx #groovylang New York Times — Getting Groovy with 68

Slide 154

Slide 154 text

@glaforge #devoxx #groovylang New York Times — Getting Groovy with 68 http://bit.ly/nyt-groovy

Slide 155

Slide 155 text

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

Slide 156

Slide 156 text

@glaforge #devoxx #groovylang What does NYT likes about Groovy on Android? • No Java 8, no lambda on Android… 70 Async.start { "my content" }

Slide 157

Slide 157 text

@glaforge #devoxx #groovylang What does NYT likes about Groovy on Android? • No Java 8, no lambda on Android… 70 Async.start { "my content" } Good bye annonymous inner classes!

Slide 158

Slide 158 text

@glaforge #devoxx #groovylang 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) 71

Slide 159

Slide 159 text

@glaforge #devoxx #groovylang Android support 72

Slide 160

Slide 160 text

@glaforge #devoxx #groovylang Android support 72 Source code available: https://github.com/melix/gr8confagenda

Slide 161

Slide 161 text

@glaforge #devoxx #groovylang A rich Groovy ecosystem

Slide 162

Slide 162 text

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

Slide 163

Slide 163 text

@glaforge #devoxx #groovylang Grails — web framework 74 @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!

Slide 164

Slide 164 text

@glaforge #devoxx #groovylang Ratpack — web framework 75 @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" } }

Slide 165

Slide 165 text

@glaforge #devoxx #groovylang Ratpack — web framework 75 @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

Slide 166

Slide 166 text

@glaforge #devoxx #groovylang @ArtifactProviderFor(GriffonModel) class ConsoleModel { String scriptSource @Observable Object scriptResult @Observable boolean enabled = true } Griffon — rich desktop applications 76

Slide 167

Slide 167 text

@glaforge #devoxx #groovylang @ArtifactProviderFor(GriffonModel) class ConsoleModel { String scriptSource @Observable Object scriptResult @Observable boolean enabled = true } Griffon — rich desktop applications 76 Model

Slide 168

Slide 168 text

@glaforge #devoxx #groovylang @ArtifactProviderFor(GriffonModel) class ConsoleModel { String scriptSource @Observable Object scriptResult @Observable boolean enabled = true } Griffon — rich desktop applications 76 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

Slide 169

Slide 169 text

@glaforge #devoxx #groovylang @ArtifactProviderFor(GriffonModel) class ConsoleModel { String scriptSource @Observable Object scriptResult @Observable boolean enabled = true } Griffon — rich desktop applications 76 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

Slide 170

Slide 170 text

@glaforge #devoxx #groovylang Spock — unit testing & specification 77 @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 } }

Slide 171

Slide 171 text

@glaforge #devoxx #groovylang Spock — unit testing & specification 77 @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

Slide 172

Slide 172 text

@glaforge #devoxx #groovylang Spock — unit testing & specification 77 @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

Slide 173

Slide 173 text

@glaforge #devoxx #groovylang Geb — browser automation 78 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" }

Slide 174

Slide 174 text

@glaforge #devoxx #groovylang Geb — browser automation 78 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

Slide 175

Slide 175 text

@glaforge #devoxx #groovylang Geb — browser automation 78 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

Slide 176

Slide 176 text

@glaforge #devoxx #groovylang Geb — browser automation 78 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

Slide 177

Slide 177 text

@glaforge #devoxx #groovylang Gradle — build automation 79 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' } } }

Slide 178

Slide 178 text

@glaforge #devoxx #groovylang Gradle — build automation 79 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

Slide 179

Slide 179 text

@glaforge #devoxx #groovylang GPars: concurrency / parallelism / async / … 80 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()

Slide 180

Slide 180 text

@glaforge #devoxx #groovylang GPars: concurrency / parallelism / async / … 80 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…

Slide 181

Slide 181 text

@glaforge #devoxx #groovylang GPars: concurrency / parallelism / async / … 80 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

Slide 182

Slide 182 text

@glaforge #devoxx #groovylang Groovy modules

Slide 183

Slide 183 text

@glaforge #devoxx #groovylang Groovy modules • Ant scripting • JMX • JSON • Servlet • Swing • SQL • Templating • Testing • XML 82

Slide 184

Slide 184 text

@glaforge #devoxx #groovylang Groovy modules • Ant scripting • JMX • JSON • Servlet • Swing • SQL • Templating • Testing • XML 83

Slide 185

Slide 185 text

@glaforge #devoxx #groovylang Ant + XML 84 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' } } }

Slide 186

Slide 186 text

@glaforge #devoxx #groovylang Ant + XML 84 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

Slide 187

Slide 187 text

@glaforge #devoxx #groovylang Ant + XML 84 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

Slide 188

Slide 188 text

@glaforge #devoxx #groovylang Ant + XML 84 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

Slide 189

Slide 189 text

@glaforge #devoxx #groovylang JSON support — creating JSON 85 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' } }

Slide 190

Slide 190 text

@glaforge #devoxx #groovylang JSON support — creating JSON 85 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" } } }

Slide 191

Slide 191 text

@glaforge #devoxx #groovylang JSON support — parsing JSON 86 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'

Slide 192

Slide 192 text

@glaforge #devoxx #groovylang JSON support — parsing JSON 86 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!

Slide 193

Slide 193 text

@glaforge #devoxx #groovylang 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 87

Slide 194

Slide 194 text

@glaforge #devoxx #groovylang 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 87 Spring Boot approved

Slide 195

Slide 195 text

@glaforge #devoxx #groovylang Markup template engine — the idea 88 cars { cars.each { car(make: it.make, name: it.name) } }

Slide 196

Slide 196 text

@glaforge #devoxx #groovylang Markup template engine — the idea 88 cars { cars.each { car(make: it.make, name: it.name) } } Your template

Slide 197

Slide 197 text

@glaforge #devoxx #groovylang Markup template engine — the idea 88 cars { cars.each { car(make: it.make, name: it.name) } } model = [cars: [ new Car(make: 'Peugeot', name: '508'), new Car(make: 'Toyota', name: 'Prius’) ]]

Slide 198

Slide 198 text

@glaforge #devoxx #groovylang Markup template engine — the idea 88 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

Slide 199

Slide 199 text

@glaforge #devoxx #groovylang Markup template engine — the idea 88 cars { cars.each { car(make: it.make, name: it.name) } } model = [cars: [ new Car(make: 'Peugeot', name: '508'), new Car(make: 'Toyota', name: 'Prius’) ]]

Slide 200

Slide 200 text

@glaforge #devoxx #groovylang Markup template engine — the idea 88 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

Slide 201

Slide 201 text

@glaforge #devoxx #groovylang Markup template engine — the idea 88 cars { cars.each { car(make: it.make, name: it.name) } } model = [cars: [ new Car(make: 'Peugeot', name: '508'), new Car(make: 'Toyota', name: 'Prius’) ]]

Slide 202

Slide 202 text

@glaforge #devoxx #groovylang Markup template engine — in action 89 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)

Slide 203

Slide 203 text

@glaforge #devoxx #groovylang Summary

Slide 204

Slide 204 text

@glaforge #devoxx #groovylang Back to our original question… Do we still need Groovy now that we have Java 8? 91

Slide 205

Slide 205 text

No content

Slide 206

Slide 206 text

@glaforge #devoxx #groovylang Longer answer: Yes, because… • You can benefit from Java 8 in Groovy 93 Synergy
 the whole is 
 greater than the sum of the parts

Slide 207

Slide 207 text

@glaforge #devoxx #groovylang Longer answer: Yes, because… • Groovy goes beyond what Java 8 offers 94 Beyond
 Groovy always tries to add something to the table

Slide 208

Slide 208 text

@glaforge #devoxx #groovylang 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 • repeating 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 95

Slide 209

Slide 209 text

@glaforge #devoxx #groovylang 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 96

Slide 210

Slide 210 text

@glaforge #devoxx #groovylang 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 96 Community feedback & contributions welcome!

Slide 211

Slide 211 text

@glaforge #devoxx #groovylang Q & A

Slide 212

Slide 212 text

No content

Slide 213

Slide 213 text

@glaforge #devoxx #groovylang Image credits • Antwerp • http://www.visitflanders.in/binaries/IMG_7895.jpg, http://www.semindex.be/upload/SemIndex/images/Accommodation/23/4_zaal6_original.jpg • Antwerp central station • http://4.bp.blogspot.com/_4dEsCVlFCgA/S7horBAdM5I/AAAAAAAAALU/eXOhxk2ou-8/s1600/Antwerp+Station.jpg • 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 • 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 99

Slide 214

Slide 214 text

@glaforge #devoxx #groovylang Image credits • 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 100

Slide 215

Slide 215 text

@glaforge #devoxx #groovylang Image credits • 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 • 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 101

Slide 216

Slide 216 text

@glaforge #devoxx #groovylang Image credits • 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 102