56 More control on annotation collector DUPLICATE Annotations from the annotation collection will always be inserted. PREFER_COLLECTOR Annotations from the collector will be added and any existing annotations with the same name will be removed. PREFER_EXPLICIT Annotations from the collector will be ignored if any existing annotations with the same name are found. PREFER_EXPLICIT_MERGED Annotations from the collector will be ignored if any existing annotations with the same name are found but any new parameters on the collector annotation will be added to existing annotations. PREFER_COLLECTOR_MERGED Annotations from the collector will be added and any existing annotations with the same name will be removed but any new parameters found within existing annotations will be merged into the added annotation.
57 Pre/post events for @TupleConstructor import groovy.transform.TupleConstructor @TupleConstructor(pre = { first = first?.toLowerCase() }) class Person { String first } def p = new Person('Jack') assert p.first == 'jack'
57 Pre/post events for @TupleConstructor import groovy.transform.TupleConstructor @TupleConstructor(pre = { first = first?.toLowerCase() }) class Person { String first } def p = new Person('Jack') assert p.first == 'jack' import groovy.transform.TupleConstructor import static groovy.test.GroovyAssert.shouldFail @TupleConstructor(pre = { assert first }) class Person { String first } def p = new Person('Jack') shouldFail { def unknown = new Person() }
59 Prevent @TupleConstructor default ctors @TupleConstructor(defaults = true) class Person { String first, last int age } Generates only: Person(String first, String last, int age) { /*...*/ }
62 @Immutable support in class hierarchy import groovy.transform.*
@EqualsAndHashCode class Person { String name } @Immutable @TupleConstructor(includeSuperProperties = true) @EqualsAndHashCode(callSuper = true) @ToString(includeNames = true, includeSuperProperties = true) class Athlete extends Person { String sport }
@Immutable class Person { String name Optional address }
def p = new Person('Joe', Optional.of('Home'))
assert p.toString() == 'Person(Joe, Optional[Home])' assert p.address.get() == 'Home' @Immutable class Person { String name Optional birth } Fails compilation, as Date is mutable
65 New @AutoImplement transformation @AutoImplement(exception = IOException) class MyWriter extends Writer { } @AutoImplement(exception = UnsupportedOperationException, message = 'Not supported by MyIterator') class MyIterator implements Iterator { } @AutoImplement(code = { throw new UnsupportedOperationException( 'Should never be called but was called on ' + new Date()) }) class EmptyIterator implements Iterator { boolean hasNext() { false } }
67 @Delegate on getters too class Person { String name @Delegate String getName() { name.reverse() } } def p = new Person(name: 'Erine') assert p.toUpperCase() == 'ENIRE'
68 JAXB marshalling shortcuts import groovy.transform.EqualsAndHashCode import javax.xml.bind.JAXBContext import javax.xml.bind.annotation.* @EqualsAndHashCode @XmlAccessorType(XmlAccessType.FIELD) @XmlRootElement class Person { String name int age }
68 JAXB marshalling shortcuts import groovy.transform.EqualsAndHashCode import javax.xml.bind.JAXBContext import javax.xml.bind.annotation.* @EqualsAndHashCode @XmlAccessorType(XmlAccessType.FIELD) @XmlRootElement class Person { String name int age } def jaxbContext = JAXBContext.newInstance(Person) def p = new Person(name: 'Marion', age: 8) def xml = jaxbContext.marshal(p) assert jaxbContext.unmarshal(xml, Person) == p
71 With… tap… assert new Person().with { name = 'Guillaume' age = 39 return it }.toString() == 'Person(Guillaume, 39)' @Canonical class Person { String name int age }
71 With… tap… assert new Person().with { name = 'Guillaume' age = 39 return it }.toString() == 'Person(Guillaume, 39)' assert new Person().tap { name = 'Guillaume' age = 39 }.toString() == 'Person(Guillaume, 39)' @Canonical class Person { String name int age }
73 A customizable JSON serializer class Person { String name String title int age String password Date dob URL favoriteUrl } Person person = new Person(name: 'John', title: null, age: 21, password: 'secret', dob: Date.parse('yyyy-MM-dd', '1984-12-15'), favoriteUrl: new URL('http://groovy-lang.org/'))
74 A customizable JSON serializer def generator = new JsonGenerator.Options() .addConverter(URL) { URL u, String key -> if (key == 'favoriteUrl') { u.getHost() } else { u } } .build() Data type to customize
74 A customizable JSON serializer def generator = new JsonGenerator.Options() .addConverter(URL) { URL u, String key -> if (key == 'favoriteUrl') { u.getHost() } else { u } } .build() Data type to customize Optional key
76 AST macros: the old way @Retention(RetentionPolicy.SOURCE) @Target([ElementType.TYPE]) @GroovyASTTransformationClass([ "metaprogramming.AddMethodASTTransformation"]) @interface AddMethod { }
76 AST macros: the old way @Retention(RetentionPolicy.SOURCE) @Target([ElementType.TYPE]) @GroovyASTTransformationClass([ "metaprogramming.AddMethodASTTransformation"]) @interface AddMethod { } Let’s decorate a class with an additional method
return macro(CompilePhase.SEMANTIC_ANALYSIS, true) { return java.security.MessageDigest .getInstance('MD5') .digest($v { fieldVar }.getBytes()) .encodeHex() .toString() } } Substitute embedded $v value with a variable from the context
93 Lambdas! // all the shapes (x, y) -> x + y (x, y) -> { x + y } (int x, int y) -> x + y def c = (int x, int y = 0) -> x + y assert c(1) == 1 implicit return
93 Lambdas! // all the shapes (x, y) -> x + y (x, y) -> { x + y } (int x, int y) -> x + y def c = (int x, int y = 0) -> x + y assert c(1) == 1 implicit return default argument
101 Picture credits The elephant in the room http://www.elephantsinthelivingroom.org/backgrounds/elephant-in-room.jpg Road https://pixabay.com/fr/route-marquage-de-route-rue-miles-166543/ Prague https://pixabay.com/fr/prague-r%C3%A9publique-tch%C3%A8que-ville-1168302/ Wise men http://img03.deviantart.net/4431/i/2012/044/f/6/three_wise_men_color_by_csoro-d4pmlv2.jpg Rocket lift-off https://pixabay.com/fr/fus%C3%A9e-ses-9-lancement-cap-canaveral-1245696/ Java beans https://pixabay.com/fr/grains-de-caf%C3%A9-caf%C3%A9-caf%C3%A9ine-boire-167001/ Ring http://www.zastavki.com/pictures/originals/2013/Movies__037523_.jpg Letter G https://pixabay.com/fr/typographie-geschtaltung-fontes-1069409/ Grammar https://pixabay.com/fr/grammaire-abc-dictionnaire-mots-390029/