SlideShare a Scribd company logo
1 of 86
Download to read offline
G3 Summit
Taking advantage of
Groovy Annotations
Iván López - @ilopmar
➢ Iván López - @ilopmar
➢ Groovy & Grails developer
Member of Grails team at OCI
➢ @MadridGUG coordinator
http://www.madridgug.com
➢ Greach organizer (@greachconf)
http://greachconf.com
➢ Speaker: SpringOne 2GX, GR8Conf, Codemotion,
GeeCon, Spring IO, Greach, JavaCro, RigaDevDay,...
About me...
“
The best code is not code at all
1.
A little bit of theory
AST and compilation
▷ Abstract Syntax Tree
▷ AST modified during compilation
▷ Hook into the compiler phases
AST Transformations
▷ Global ▷ Local
2.
Out-of-the-box ASTs
AST transformations categories
▷ Code generation
▷ Class design
▷ Logging improvements
▷ Declarative concurrency
▷ Cloning and externalizing
▷ Safe scripting
▷ Compiler directives
▷ Dependencies handling
Code generation
@ToString
▷ Human readable toString
▷ Effective Java by Joshua Bloch (item 10)
class User {
String name
Integer age
}
def u = new User(name: 'Iván', age: 36)
println u // User@1d2a54b2
@groovy.transform.ToString
class User {
String name
Integer age
}
def u = new User(name: 'Iván', age: 36)
assert u.toString() == 'User(Iván, 36)'
class User {
String name
Integer age
}
def u = new User(name: 'Iván', age: 36)
println u // User@1d2a54b2
@groovy.transform.ToString
class User {
String name
Integer age
}
def u = new User(name: 'Iván', age: 36)
assert u.toString() == 'User(Iván, 36)'
String toString() {
def _result = new StringBuilder()
_result.append('User(')
_result.append(this.name)
_result.append(', ')
_result.append(this.age)
_result.append(')')
return _result.toString()
}
class User {
String name
Integer age
}
def u = new User(name: 'Iván', age: 36)
println u // User@1d2a54b2
@ToString
▷ includeNames, excludes, includes, includeSuper,
includeSuperProperties, includeFields, ignoreNulls,
includePackage, cache
@ToString
▷ includeNames, excludes, includes, includeSuper,
includeSuperProperties, includeFields, ignoreNulls,
includePackage, cache
@groovy.transform.ToString(includeNames = true, excludes = ['name'])
class User {
String name
Integer age
}
def u = new User(name: 'Iván', age: 36)
assert u.toString() == 'User(age:36)'
@EqualsAndHashCode
▷ Generate equals and hashCode implementations
▷ Effective Java items 8 & 9
@EqualsAndHashCode
▷ Generate equals and hashCode implementations
▷ Effective Java items 8 & 9
@groovy.transform.EqualsAndHashCode
class User {
String name
Integer age
}
def u1 = new User(name: 'Iván', age: 36)
def u2 = new User(name: 'Iván', age: 36)
assert u1 == u2
assert u1.hashCode() == u2.hashCode()
int hashCode() {
def _result = HashCodeHelper.initHash()
_result = HashCodeHelper.updateHash(_result, this.name)
_result = HashCodeHelper.updateHash(_result, this.age)
return _result
}
boolean canEqual(Object other) {
return other instanceof User
}
boolean equals(Object other) {
if (other == null) { return false }
if (this.is(other)) { return true }
if (!(other instanceof User)) { return false }
User otherTyped = ((other) as User)
if (!(otherTyped.canEqual(this))) { return false }
if (!(this.getName().is(otherTyped.getName()))) {
if (this.getName().is(this) && !(otherTyped.getName().is(otherTyped)) || !(this.getName().is(this)) && otherTyped.getName().is(otherTyped))
return false
} else {
if (!(this.getName().is(this) && otherTyped.getName().is(otherTyped))) {
if (!(this.getName() == otherTyped.getName())) {
return false
}
}
}
}
if (!(this.getAge().is(otherTyped.getAge()))) {
if (this.getAge().is(this) && !(otherTyped.getAge().is(otherTyped)) || !(this.getAge().is(this)) && otherTyped.getAge().is(otherTyped)) {
return false
} else {
if (!(this.getAge().is(this) && otherTyped.getAge().is(otherTyped))) {
if (!(this.getAge() == otherTyped.getAge())) {
return false
}
}
}
}
return true
}
@EqualsAndHashCode
▷ excludes, includes, callSuper, includeFields, cache,
useCanEqual
@EqualsAndHashCode
▷ excludes, includes, callSuper, includeFields, cache,
useCanEqual
@groovy.transform.EqualsAndHashCode(includes = 'name')
class User {
String name
Integer age
}
def u1 = new User(name: 'Iván', age: 36)
def u2 = new User(name: 'Iván', age: 42)
assert u1 == u2
assert u1.hashCode() == u2.hashCode()
@TupleConstructor
▷ Generate constructors
@TupleConstructor
▷ Generate constructors
@groovy.transform.TupleConstructor
class User {
String name
Integer age
}
@TupleConstructor
▷ Generate constructors
@groovy.transform.TupleConstructor
class User {
String name
Integer age
}
// Default map constructor
def u1 = new User(name: 'Iván', age: 36)
@TupleConstructor
▷ Generate constructors
@groovy.transform.TupleConstructor
class User {
String name
Integer age
}
// Default map constructor
def u1 = new User(name: 'Iván', age: 36)
// Generated tuple constructor
def u2 = new User('Iván', 36)
def u3 = new User('Iván')
@TupleConstructor
▷ Generate constructors
@groovy.transform.TupleConstructor
class User {
String name
Integer age
}
// Default map constructor
def u1 = new User(name: 'Iván', age: 35)
// Generated tuple constructor
def u2 = new User('Iván', 36)
def u3 = new User('Iván')
User(String name = null, Integer age = null) {
this.name = name
this.age = age
}
@TupleConstructor
▷ excludes, includes, includeFields, includeProperties,
includeSuperFields, includeSuperProperties,
callSuper, force
@Canonical
▷ @ToString + @EqualsAndHashCode +
@TupleConstructor
@Canonical
▷ @ToString + @EqualsAndHashCode +
@TupleConstructor
@groovy.transform.Canonical
class User {
String name
Integer age
}
@Canonical
▷ @ToString + @EqualsAndHashCode +
@TupleConstructor
def u1 = new User(name: 'Iván', age: 36)
assert u1.toString() == 'User(Iván, 36)' // @ToString
@groovy.transform.Canonical
class User {
String name
Integer age
}
@Canonical
▷ @ToString + @EqualsAndHashCode +
@TupleConstructor
def u2 = new User('Iván', 36) // @TupleConstructor
assert u2.toString() == 'User(Iván, 36)'
def u1 = new User(name: 'Iván', age: 36)
assert u1.toString() == 'User(Iván, 36)' // @ToString
@groovy.transform.Canonical
class User {
String name
Integer age
}
@Canonical
▷ @ToString + @EqualsAndHashCode +
@TupleConstructor
assert u1 == u2 // @EqualsAndHashCode
assert u1.hashCode() == u2.hashCode() // @EqualsAndHashCode
def u2 = new User('Iván', 36) // @TupleConstructor
assert u2.toString() == 'User(Iván, 36)'
def u1 = new User(name: 'Iván', age: 36)
assert u1.toString() == 'User(Iván, 36)' // @ToString
@groovy.transform.Canonical
class User {
String name
Integer age
}
@InheritConstructors
▷ Reduce boilerplate code when parent classes
have multiple constructors
▷ Useful when overriding exception classes
@groovy.transform.InheritConstructors
class MyException extends Exception {
}
protected MyException(String param0, Throwable param1, boolean param2, boolean param3) {
super(param0, param1, param2, param3)
}
public MyException(Throwable param0) { super(param0) }
public MyException(String param0, Throwable param1) { super(param0, param1) }
public MyException(String param0) { super(param0) }
public MyException() { super() }
@groovy.transform.InheritConstructors
class MyException extends Exception {
}
@Lazy
▷ Lazy initialization of fields
▷ Useful when creating expensive resources
▷ Effective Java item 71
class SomeBean {
@Lazy
LinkedList myField
}
class SomeBean {
@Lazy
LinkedList myField
}
public LinkedList getMyField() {
if ($myField != null) {
$myField
} else {
$myField = new LinkedList()
}
}
@Sortable
▷ Comparable interface
▷ compareTo method natural order
▷ N methods returning comparators
▷ Effective Java item 12
@groovy.transform.Sortable
class User {
String name
Integer age
Integer born
}
public int compareTo(User other) {
if (this.is(other)) return 0
Integer value = 0
value = this.name <=> other.name
if (value != 0) return value
value = this.age <=> other.age
if (value != 0) return value
value = this.born <=> other.born
if (value != 0) return value
return 0
}
private static class User$NameComparator extends AbstractComparator<User> {
public int compare(User arg0, User arg1) {
if (arg0 == arg1) return 0
if (arg0 != null && arg1 == null) return -1
if (arg0 == null && arg1 != null) return 1
return arg0.name <=> arg1.name
}
}
private static class User$AgeComparator extends AbstractComparator<User> {
...
}
@groovy.transform.Sortable
class User {
String name
Integer age
Integer born
}
@groovy.transform.Sortable
class User {
String name
Integer age
Integer born
}
def users = [
new User(name: 'Mary', age: 15, born: 2000),
new User(name: 'Peter', age: 44, born: 1970),
new User(name: 'John', age: 35, born: 1979),
]
@groovy.transform.Sortable
class User {
String name
Integer age
Integer born
}
assert users.sort(false, User.comparatorByName())*.name == ['John', 'Mary', 'Peter']
assert users.sort(false, User.comparatorByAge())*.born == [2000, 1979, 1970]
def users = [
new User(name: 'Mary', age: 15, born: 2000),
new User(name: 'Peter', age: 44, born: 1970),
new User(name: 'John', age: 35, born: 1979),
]
@groovy.transform.Sortable
class User {
String name
Integer age
Integer born
}
@Sortable
▷ includes, excludes
@groovy.transform.Sortable(excludes = 'age')
class User {
String name
Integer age
Integer born
}
def users = [
new User(name: 'Mary', age: 15, born: 2000),
new User(name: 'Peter', age: 44, born: 1970),
new User(name: 'John', age: 35, born: 1979),
]
assert users.sort(false, User.comparatorByName())*.name == ['John', 'Mary', 'Peter']
assert users.sort(false, User.comparatorByAge())*.born == [2000, 1979, 1970]
@Builder
▷ Create fluent API calls
▷ Multiple building strategies
▷ Multiple configuration options: builder name,
prefix, excludes, includes,...
▷ Effective Java item 2
@groovy.transform.builder.Builder
class User {
String name
Integer age
Integer born
}
@groovy.transform.builder.Builder
class User {
String name
Integer age
Integer born
}
def u = User.builder()
.name('Iván')
.age(36)
.born(1979)
.build()
assert u.name == 'Iván'
assert u.age == 36
assert u.born == 1979
public static class User$UserBuilder extends Object {
private String name
private Integer age
private Integer born
public User$UserBuilder() {
}
public User$UserBuilder name(String name) {
this.name = name
return this
}
public User$UserBuilder age(Integer age) {
this.age = age
return this
}
public User$UserBuilder born(Integer born) {
this.born = born
return this
}
public User build() {
User _theUser = new User()
_theUser.name = name
_theUser.age = age
_theUser.born = born
return _theUser
}
}
@groovy.transform.builder.Builder
class User {
String name
Integer age
Integer born
}
def u = User.builder()
.name('Iván')
.age(36)
.born(1979)
.build()
assert u.name == 'Iván'
assert u.age == 36
assert u.born == 1979
Class design
@Delegate
▷ Implements delegation design pattern
▷ Delegate calls on object to method on delegated
properties
▷ All public methods are delegated
import java.time.LocalDate
class Conference {
@groovy.lang.Delegate
LocalDate when
String name
}
import java.time.LocalDate
class Conference {
@groovy.lang.Delegate
LocalDate when
String name
}
def greach = new Conference(name: 'Greach', when: LocalDate.of(2017, 03, 31))
def gr8conf = new Conference(name: 'GR8Conf' when: LocalDate.of(2017, 05, 31))
def greach = new Conference(name: 'Greach', when: LocalDate.of(2017, 03, 31))
def gr8conf = new Conference(name: 'GR8Conf' when: LocalDate.of(2017, 05, 31))
assert greach.isBefore(gr8conf)
import java.time.LocalDate
class Conference {
@groovy.lang.Delegate
LocalDate when
String name
}
class Conference {
...
public boolean isAfter(ChronoLocalDate param0) {
when.isAfter(param0)
}
public boolean isBefore(ChronoLocalDate param0) {
when.isBefore(param0)
}
...
}
def greach = new Conference(name: 'Greach', when: LocalDate.of(2017, 03, 31))
def gr8conf = new Conference(name: 'GR8Conf' when: LocalDate.of(2017, 05, 31))
assert greach.isBefore(gr8conf)
import java.time.LocalDate
class Conference {
@groovy.lang.Delegate
LocalDate when
String name
}
@Immutable
▷ Create immutable classes
▷ Effective Java item 15
▷ Rules for immutability
@groovy.transform.Immutable
class User {
String name
Integer age
}
def u = new User(name: 'Iván', age: 36)
// This does not compile
// You are not allowed to overwrite
// the final class 'User'.
class Admin extends User {
}
@groovy.transform.Immutable
class User {
String name
Integer age
}
def u = new User(name: 'Iván', age: 36)
@groovy.transform.Immutable
class User {
String name
Integer age
}
def u = new User(name: 'Iván', age: 36)
try {
u.name = 'John'
} catch (ReadOnlyPropertyException e) {
println e
}
// This does not compile
// You are not allowed to overwrite
// the final class 'User'.
class Admin extends User {
}
@Memoized
▷ Cache the result of a method
@Memoized
▷ Cache the result of a method
@groovy.transform.Memoized
Long fibonacci(Integer n) {
if (n < 2) return 1
else return fibonacci(n-1) + fibonacci(n-2)
}
fibonacci(300)
@Memoized
▷ Cache the result of a method
@groovy.transform.Memoized
Long fibonacci(Integer n) {
if (n < 2) return 1
else return fibonacci(n-1) + fibonacci(n-2)
}
fibonacci(300)
@groovy.transform.Memoized
User getUserInfo(Long userId) {
// Expensive repetitive
// network operation
}
Logging
improvements
@Log, @Log4j, @Log4j2, @Slf4j
▷ Static final field for the logger
@Log, @Log4j, @Log4j2, @Slf4j
@groovy.util.logging.Log4j
class MyClass {
void method() {
log.debug "My debug message"
}
}
▷ Static final field for the logger
@Log, @Log4j, @Log4j2, @Slf4j
@groovy.util.logging.Log4j
class MyClass {
void method() {
log.debug "My debug message"
}
}
▷ Static final field for the logger
class MyClass {
private static final Logger log = Logger.getLogger(Saludador.name)
void method() {
if (log.isLoggable(Level.DEBUG)) {
log.debug "My debug message"
}
}
}
Declarative concurrency
Declarative concurrency
▷ @Synchronized
▷ @WithReadLock
▷ @WithWriteLock
Cloning and externalizing
Cloning and externalizing
▷ @AutoClone
▷ @AutoExternalize
Safe scripting
Safe scripting
▷ @ThreadInterrupt
▷ @TimedInterrupt
▷ @ConditionalInterrupt
Compiler directives
Compiler directives
▷ @TypeChecked
▷ @CompileStatic
▷ @CompileDynamic
Dependencies
handling
@Grab
▷ Grape dependency manager
@Grab
▷ Grape dependency manager
@Grab(group='org.springframework', module='spring-orm', version='3.2.5.RELEASE')
import org.springframework.jdbc.core.JdbcTemplate
// or
@Grab('org.springframework:spring-orm:3.2.5.RELEASE')
import org.springframework.jdbc.core.JdbcTemplate
@GrabResolver
▷ Grape dependency manager
@Grab(group='org.springframework', module='spring-orm', version='3.2.5.RELEASE')
import org.springframework.jdbc.core.JdbcTemplate
// or
@Grab('org.springframework:spring-orm:3.2.5.RELEASE')
import org.springframework.jdbc.core.JdbcTemplate
@GrabResolver(name='restlet', root='http://maven.restlet.org/')
@Grab(group='org.restlet', module='org.restlet', version='1.1.6')
@GrabExclude
▷ Grape dependency manager
@Grab(group='org.springframework', module='spring-orm', version='3.2.5.RELEASE')
import org.springframework.jdbc.core.JdbcTemplate
// or
@Grab('org.springframework:spring-orm:3.2.5.RELEASE')
import org.springframework.jdbc.core.JdbcTemplate
@GrabResolver(name='restlet', root='http://maven.restlet.org/')
@Grab(group='org.restlet', module='org.restlet', version='1.1.6')
@Grab('net.sourceforge.htmlunit:htmlunit:2.8')
@GrabExclude('xml-apis:xml-apis')
Bonus
@Pokemon
class Foo {
void doStuff() {
try {
// Some code that can throws
// different exceptions
} catch (e) {
// Gotta catch’em all
}
}
}
@Pokemon
class Foo {
void doStuff() {
try {
// Some code that can throws
// different exceptions
} catch (e) {
// Gotta catch’em all
}
}
}
class Foo {
@com.github.danveloper.ast.Pokemon
void doStuff() {
// code
}
}
3.
Demo
4.
Summary
“
The best code is not code at all
Thanks!
Any questions?
@ilopmar
lopez.ivan@gmail.com
https://github.com/ilopmar
Iván López
http://bit.ly/g3summit-groovy

More Related Content

What's hot

Privet Kotlin (Windy City DevFest)
Privet Kotlin (Windy City DevFest)Privet Kotlin (Windy City DevFest)
Privet Kotlin (Windy City DevFest)Cody Engel
 
DevNation'15 - Using Lambda Expressions to Query a Datastore
DevNation'15 - Using Lambda Expressions to Query a DatastoreDevNation'15 - Using Lambda Expressions to Query a Datastore
DevNation'15 - Using Lambda Expressions to Query a DatastoreXavier Coulon
 
CodeCamp Iasi 10 march 2012 - Practical Groovy
CodeCamp Iasi 10 march 2012 - Practical GroovyCodeCamp Iasi 10 march 2012 - Practical Groovy
CodeCamp Iasi 10 march 2012 - Practical GroovyCodecamp Romania
 
Scala presentation by Aleksandar Prokopec
Scala presentation by Aleksandar ProkopecScala presentation by Aleksandar Prokopec
Scala presentation by Aleksandar ProkopecLoïc Descotte
 
David Kopal - Unleash the power of the higher-order components
David Kopal - Unleash the power of the higher-order componentsDavid Kopal - Unleash the power of the higher-order components
David Kopal - Unleash the power of the higher-order componentsOdessaJS Conf
 
Feel of Kotlin (Berlin JUG 16 Apr 2015)
Feel of Kotlin (Berlin JUG 16 Apr 2015)Feel of Kotlin (Berlin JUG 16 Apr 2015)
Feel of Kotlin (Berlin JUG 16 Apr 2015)intelliyole
 
JavaScript, TypeScipt and React Native
JavaScript, TypeScipt and React NativeJavaScript, TypeScipt and React Native
JavaScript, TypeScipt and React NativeMitchell Tilbrook
 
Pragmatic Real-World Scala (short version)
Pragmatic Real-World Scala (short version)Pragmatic Real-World Scala (short version)
Pragmatic Real-World Scala (short version)Jonas Bonér
 
Kotlin Advanced - Apalon Kotlin Sprint Part 3
Kotlin Advanced - Apalon Kotlin Sprint Part 3Kotlin Advanced - Apalon Kotlin Sprint Part 3
Kotlin Advanced - Apalon Kotlin Sprint Part 3Kirill Rozov
 
Nik Graf - Get started with Reason and ReasonReact
Nik Graf - Get started with Reason and ReasonReactNik Graf - Get started with Reason and ReasonReact
Nik Graf - Get started with Reason and ReasonReactOdessaJS Conf
 
Functional JS for everyone - 4Developers
Functional JS for everyone - 4DevelopersFunctional JS for everyone - 4Developers
Functional JS for everyone - 4DevelopersBartek Witczak
 
From java to kotlin beyond alt+shift+cmd+k
From java to kotlin beyond alt+shift+cmd+kFrom java to kotlin beyond alt+shift+cmd+k
From java to kotlin beyond alt+shift+cmd+kFabio Collini
 
concurrency with GPars
concurrency with GParsconcurrency with GPars
concurrency with GParsPaul King
 

What's hot (15)

Privet Kotlin (Windy City DevFest)
Privet Kotlin (Windy City DevFest)Privet Kotlin (Windy City DevFest)
Privet Kotlin (Windy City DevFest)
 
DevNation'15 - Using Lambda Expressions to Query a Datastore
DevNation'15 - Using Lambda Expressions to Query a DatastoreDevNation'15 - Using Lambda Expressions to Query a Datastore
DevNation'15 - Using Lambda Expressions to Query a Datastore
 
CodeCamp Iasi 10 march 2012 - Practical Groovy
CodeCamp Iasi 10 march 2012 - Practical GroovyCodeCamp Iasi 10 march 2012 - Practical Groovy
CodeCamp Iasi 10 march 2012 - Practical Groovy
 
Scala presentation by Aleksandar Prokopec
Scala presentation by Aleksandar ProkopecScala presentation by Aleksandar Prokopec
Scala presentation by Aleksandar Prokopec
 
David Kopal - Unleash the power of the higher-order components
David Kopal - Unleash the power of the higher-order componentsDavid Kopal - Unleash the power of the higher-order components
David Kopal - Unleash the power of the higher-order components
 
Feel of Kotlin (Berlin JUG 16 Apr 2015)
Feel of Kotlin (Berlin JUG 16 Apr 2015)Feel of Kotlin (Berlin JUG 16 Apr 2015)
Feel of Kotlin (Berlin JUG 16 Apr 2015)
 
JavaScript, TypeScipt and React Native
JavaScript, TypeScipt and React NativeJavaScript, TypeScipt and React Native
JavaScript, TypeScipt and React Native
 
360|iDev
360|iDev360|iDev
360|iDev
 
Pragmatic Real-World Scala (short version)
Pragmatic Real-World Scala (short version)Pragmatic Real-World Scala (short version)
Pragmatic Real-World Scala (short version)
 
Kotlin Advanced - Apalon Kotlin Sprint Part 3
Kotlin Advanced - Apalon Kotlin Sprint Part 3Kotlin Advanced - Apalon Kotlin Sprint Part 3
Kotlin Advanced - Apalon Kotlin Sprint Part 3
 
Nik Graf - Get started with Reason and ReasonReact
Nik Graf - Get started with Reason and ReasonReactNik Graf - Get started with Reason and ReasonReact
Nik Graf - Get started with Reason and ReasonReact
 
Functional JS for everyone - 4Developers
Functional JS for everyone - 4DevelopersFunctional JS for everyone - 4Developers
Functional JS for everyone - 4Developers
 
Python Training
Python TrainingPython Training
Python Training
 
From java to kotlin beyond alt+shift+cmd+k
From java to kotlin beyond alt+shift+cmd+kFrom java to kotlin beyond alt+shift+cmd+k
From java to kotlin beyond alt+shift+cmd+k
 
concurrency with GPars
concurrency with GParsconcurrency with GPars
concurrency with GPars
 

Viewers also liked

G3 Summit 2016 - Dockerize your Grails!
G3 Summit 2016 - Dockerize your Grails!G3 Summit 2016 - Dockerize your Grails!
G3 Summit 2016 - Dockerize your Grails!Iván López Martín
 
Un Paseo por las Transformaciones AST de Groovy
Un Paseo por las Transformaciones AST de GroovyUn Paseo por las Transformaciones AST de Groovy
Un Paseo por las Transformaciones AST de GroovyAndres Almiray
 
101 Panel Tech Days - Spock: O por qué deberías utilizarlo para testear tu có...
101 Panel Tech Days - Spock: O por qué deberías utilizarlo para testear tu có...101 Panel Tech Days - Spock: O por qué deberías utilizarlo para testear tu có...
101 Panel Tech Days - Spock: O por qué deberías utilizarlo para testear tu có...Iván López Martín
 
JavaCro 2016 - Testing with Spock: The Logical choice
JavaCro 2016 - Testing with Spock: The Logical choiceJavaCro 2016 - Testing with Spock: The Logical choice
JavaCro 2016 - Testing with Spock: The Logical choiceIván López Martín
 
T3chFest 2017 - La Revolucion del Open Source
T3chFest 2017 - La Revolucion del Open SourceT3chFest 2017 - La Revolucion del Open Source
T3chFest 2017 - La Revolucion del Open SourceIván López Martín
 
Creating applications with Grails, Angular JS and Spring Security - G3 Summit...
Creating applications with Grails, Angular JS and Spring Security - G3 Summit...Creating applications with Grails, Angular JS and Spring Security - G3 Summit...
Creating applications with Grails, Angular JS and Spring Security - G3 Summit...Alvaro Sanchez-Mariscal
 
Spring Madrid User Group - Spring Integration in Action
Spring Madrid User Group - Spring Integration in ActionSpring Madrid User Group - Spring Integration in Action
Spring Madrid User Group - Spring Integration in ActionIván López Martín
 
Going to Mars with Groovy Domain-Specific Languages
Going to Mars with Groovy Domain-Specific LanguagesGoing to Mars with Groovy Domain-Specific Languages
Going to Mars with Groovy Domain-Specific LanguagesGuillaume Laforge
 

Viewers also liked (8)

G3 Summit 2016 - Dockerize your Grails!
G3 Summit 2016 - Dockerize your Grails!G3 Summit 2016 - Dockerize your Grails!
G3 Summit 2016 - Dockerize your Grails!
 
Un Paseo por las Transformaciones AST de Groovy
Un Paseo por las Transformaciones AST de GroovyUn Paseo por las Transformaciones AST de Groovy
Un Paseo por las Transformaciones AST de Groovy
 
101 Panel Tech Days - Spock: O por qué deberías utilizarlo para testear tu có...
101 Panel Tech Days - Spock: O por qué deberías utilizarlo para testear tu có...101 Panel Tech Days - Spock: O por qué deberías utilizarlo para testear tu có...
101 Panel Tech Days - Spock: O por qué deberías utilizarlo para testear tu có...
 
JavaCro 2016 - Testing with Spock: The Logical choice
JavaCro 2016 - Testing with Spock: The Logical choiceJavaCro 2016 - Testing with Spock: The Logical choice
JavaCro 2016 - Testing with Spock: The Logical choice
 
T3chFest 2017 - La Revolucion del Open Source
T3chFest 2017 - La Revolucion del Open SourceT3chFest 2017 - La Revolucion del Open Source
T3chFest 2017 - La Revolucion del Open Source
 
Creating applications with Grails, Angular JS and Spring Security - G3 Summit...
Creating applications with Grails, Angular JS and Spring Security - G3 Summit...Creating applications with Grails, Angular JS and Spring Security - G3 Summit...
Creating applications with Grails, Angular JS and Spring Security - G3 Summit...
 
Spring Madrid User Group - Spring Integration in Action
Spring Madrid User Group - Spring Integration in ActionSpring Madrid User Group - Spring Integration in Action
Spring Madrid User Group - Spring Integration in Action
 
Going to Mars with Groovy Domain-Specific Languages
Going to Mars with Groovy Domain-Specific LanguagesGoing to Mars with Groovy Domain-Specific Languages
Going to Mars with Groovy Domain-Specific Languages
 

Similar to G3 Summit 2016 - Taking Advantage of Groovy Annotations

Java: Nie popełniaj tych błędów!
Java: Nie popełniaj tych błędów!Java: Nie popełniaj tych błędów!
Java: Nie popełniaj tych błędów!Daniel Pokusa
 
AST Transformations at JFokus
AST Transformations at JFokusAST Transformations at JFokus
AST Transformations at JFokusHamletDRC
 
#살아있다 #자프링외길12년차 #코프링2개월생존기
#살아있다 #자프링외길12년차 #코프링2개월생존기#살아있다 #자프링외길12년차 #코프링2개월생존기
#살아있다 #자프링외길12년차 #코프링2개월생존기Arawn Park
 
Effective Java with Groovy
Effective Java with GroovyEffective Java with Groovy
Effective Java with GroovyNaresha K
 
Kotlin, smarter development for the jvm
Kotlin, smarter development for the jvmKotlin, smarter development for the jvm
Kotlin, smarter development for the jvmArnaud Giuliani
 
Meetup di GDG Italia - Leonardo Pirro - Codemotion Rome 2018
Meetup di GDG Italia - Leonardo Pirro -  Codemotion Rome 2018 Meetup di GDG Italia - Leonardo Pirro -  Codemotion Rome 2018
Meetup di GDG Italia - Leonardo Pirro - Codemotion Rome 2018 Codemotion
 
AST Transformations
AST TransformationsAST Transformations
AST TransformationsHamletDRC
 
First few months with Kotlin - Introduction through android examples
First few months with Kotlin - Introduction through android examplesFirst few months with Kotlin - Introduction through android examples
First few months with Kotlin - Introduction through android examplesNebojša Vukšić
 
Groovy grails types, operators, objects
Groovy grails types, operators, objectsGroovy grails types, operators, objects
Groovy grails types, operators, objectsHusain Dalal
 
科特林λ學
科特林λ學科特林λ學
科特林λ學彥彬 洪
 
Effective Java with Groovy & Kotlin How Languages Influence Adoption of Good ...
Effective Java with Groovy & Kotlin How Languages Influence Adoption of Good ...Effective Java with Groovy & Kotlin How Languages Influence Adoption of Good ...
Effective Java with Groovy & Kotlin How Languages Influence Adoption of Good ...Naresha K
 
GeeCON Prague 2014 - Metaprogramming with Groovy
GeeCON Prague 2014 - Metaprogramming with GroovyGeeCON Prague 2014 - Metaprogramming with Groovy
GeeCON Prague 2014 - Metaprogramming with GroovyIván López Martín
 
Scala vs Java 8 in a Java 8 World
Scala vs Java 8 in a Java 8 WorldScala vs Java 8 in a Java 8 World
Scala vs Java 8 in a Java 8 WorldBTI360
 
Protocols
ProtocolsProtocols
ProtocolsSV.CO
 

Similar to G3 Summit 2016 - Taking Advantage of Groovy Annotations (20)

Java: Nie popełniaj tych błędów!
Java: Nie popełniaj tych błędów!Java: Nie popełniaj tych błędów!
Java: Nie popełniaj tych błędów!
 
AST Transformations at JFokus
AST Transformations at JFokusAST Transformations at JFokus
AST Transformations at JFokus
 
#살아있다 #자프링외길12년차 #코프링2개월생존기
#살아있다 #자프링외길12년차 #코프링2개월생존기#살아있다 #자프링외길12년차 #코프링2개월생존기
#살아있다 #자프링외길12년차 #코프링2개월생존기
 
Effective Java with Groovy
Effective Java with GroovyEffective Java with Groovy
Effective Java with Groovy
 
Kotlin, smarter development for the jvm
Kotlin, smarter development for the jvmKotlin, smarter development for the jvm
Kotlin, smarter development for the jvm
 
Meetup di GDG Italia - Leonardo Pirro - Codemotion Rome 2018
Meetup di GDG Italia - Leonardo Pirro -  Codemotion Rome 2018 Meetup di GDG Italia - Leonardo Pirro -  Codemotion Rome 2018
Meetup di GDG Italia - Leonardo Pirro - Codemotion Rome 2018
 
AST Transformations
AST TransformationsAST Transformations
AST Transformations
 
Poly-paradigm Java
Poly-paradigm JavaPoly-paradigm Java
Poly-paradigm Java
 
First few months with Kotlin - Introduction through android examples
First few months with Kotlin - Introduction through android examplesFirst few months with Kotlin - Introduction through android examples
First few months with Kotlin - Introduction through android examples
 
Java2
Java2Java2
Java2
 
Groovy grails types, operators, objects
Groovy grails types, operators, objectsGroovy grails types, operators, objects
Groovy grails types, operators, objects
 
Lezione03
Lezione03Lezione03
Lezione03
 
Lezione03
Lezione03Lezione03
Lezione03
 
科特林λ學
科特林λ學科特林λ學
科特林λ學
 
Effective Java with Groovy & Kotlin How Languages Influence Adoption of Good ...
Effective Java with Groovy & Kotlin How Languages Influence Adoption of Good ...Effective Java with Groovy & Kotlin How Languages Influence Adoption of Good ...
Effective Java with Groovy & Kotlin How Languages Influence Adoption of Good ...
 
Pure kotlin
Pure kotlinPure kotlin
Pure kotlin
 
GeeCON Prague 2014 - Metaprogramming with Groovy
GeeCON Prague 2014 - Metaprogramming with GroovyGeeCON Prague 2014 - Metaprogramming with Groovy
GeeCON Prague 2014 - Metaprogramming with Groovy
 
Scala vs Java 8 in a Java 8 World
Scala vs Java 8 in a Java 8 WorldScala vs Java 8 in a Java 8 World
Scala vs Java 8 in a Java 8 World
 
Protocols
ProtocolsProtocols
Protocols
 
Groovy closures
Groovy closuresGroovy closures
Groovy closures
 

More from Iván López Martín

SalmorejoTech 2024 - Spring Boot <3 Testcontainers
SalmorejoTech 2024 - Spring Boot <3 TestcontainersSalmorejoTech 2024 - Spring Boot <3 Testcontainers
SalmorejoTech 2024 - Spring Boot <3 TestcontainersIván López Martín
 
CommitConf 2024 - Spring Boot <3 Testcontainers
CommitConf 2024 - Spring Boot <3 TestcontainersCommitConf 2024 - Spring Boot <3 Testcontainers
CommitConf 2024 - Spring Boot <3 TestcontainersIván López Martín
 
Voxxed Days CERN 2024 - Spring Boot <3 Testcontainers.pdf
Voxxed Days CERN 2024 - Spring Boot <3 Testcontainers.pdfVoxxed Days CERN 2024 - Spring Boot <3 Testcontainers.pdf
Voxxed Days CERN 2024 - Spring Boot <3 Testcontainers.pdfIván López Martín
 
VMware - Testcontainers y Spring Boot
VMware - Testcontainers y Spring BootVMware - Testcontainers y Spring Boot
VMware - Testcontainers y Spring BootIván López Martín
 
Spring IO 2023 - Dynamic OpenAPIs with Spring Cloud Gateway
Spring IO 2023 - Dynamic OpenAPIs with Spring Cloud GatewaySpring IO 2023 - Dynamic OpenAPIs with Spring Cloud Gateway
Spring IO 2023 - Dynamic OpenAPIs with Spring Cloud GatewayIván López Martín
 
Codemotion Madrid 2023 - Testcontainers y Spring Boot
Codemotion Madrid 2023 - Testcontainers y Spring BootCodemotion Madrid 2023 - Testcontainers y Spring Boot
Codemotion Madrid 2023 - Testcontainers y Spring BootIván López Martín
 
CommitConf 2023 - Spring Framework 6 y Spring Boot 3
CommitConf 2023 - Spring Framework 6 y Spring Boot 3CommitConf 2023 - Spring Framework 6 y Spring Boot 3
CommitConf 2023 - Spring Framework 6 y Spring Boot 3Iván López Martín
 
Construyendo un API REST con Spring Boot y GraalVM
Construyendo un API REST con Spring Boot y GraalVMConstruyendo un API REST con Spring Boot y GraalVM
Construyendo un API REST con Spring Boot y GraalVMIván López Martín
 
jLove 2020 - Micronaut and graalvm: The power of AoT
jLove 2020 - Micronaut and graalvm: The power of AoTjLove 2020 - Micronaut and graalvm: The power of AoT
jLove 2020 - Micronaut and graalvm: The power of AoTIván López Martín
 
Codemotion Madrid 2020 - Serverless con Micronaut
Codemotion Madrid 2020 - Serverless con MicronautCodemotion Madrid 2020 - Serverless con Micronaut
Codemotion Madrid 2020 - Serverless con MicronautIván López Martín
 
JConf Perú 2020 - ¡Micronaut en acción!
JConf Perú 2020 - ¡Micronaut en acción!JConf Perú 2020 - ¡Micronaut en acción!
JConf Perú 2020 - ¡Micronaut en acción!Iván López Martín
 
JConf Perú 2020 - Micronaut + GraalVM = <3
JConf Perú 2020 - Micronaut + GraalVM = <3JConf Perú 2020 - Micronaut + GraalVM = <3
JConf Perú 2020 - Micronaut + GraalVM = <3Iván López Martín
 
JConf México 2020 - Micronaut + GraalVM = <3
JConf México 2020 - Micronaut + GraalVM = <3JConf México 2020 - Micronaut + GraalVM = <3
JConf México 2020 - Micronaut + GraalVM = <3Iván López Martín
 
Developing Micronaut Applications With IntelliJ IDEA
Developing Micronaut Applications With IntelliJ IDEADeveloping Micronaut Applications With IntelliJ IDEA
Developing Micronaut Applications With IntelliJ IDEAIván López Martín
 
CommitConf 2019 - Micronaut y GraalVm: La combinación perfecta
CommitConf 2019 - Micronaut y GraalVm: La combinación perfectaCommitConf 2019 - Micronaut y GraalVm: La combinación perfecta
CommitConf 2019 - Micronaut y GraalVm: La combinación perfectaIván López Martín
 
Codemotion Madrid 2019 - ¡GraalVM y Micronaut: compañeros perfectos!
Codemotion Madrid 2019 - ¡GraalVM y Micronaut: compañeros perfectos!Codemotion Madrid 2019 - ¡GraalVM y Micronaut: compañeros perfectos!
Codemotion Madrid 2019 - ¡GraalVM y Micronaut: compañeros perfectos!Iván López Martín
 
Greach 2019 - Creating Micronaut Configurations
Greach 2019 - Creating Micronaut ConfigurationsGreach 2019 - Creating Micronaut Configurations
Greach 2019 - Creating Micronaut ConfigurationsIván López Martín
 
VoxxedDays Bucharest 2019 - Alexa, nice to meet you
VoxxedDays Bucharest 2019 - Alexa, nice to meet youVoxxedDays Bucharest 2019 - Alexa, nice to meet you
VoxxedDays Bucharest 2019 - Alexa, nice to meet youIván López Martín
 
JavaDay Lviv 2019 - Micronaut in action!
JavaDay Lviv 2019 - Micronaut in action!JavaDay Lviv 2019 - Micronaut in action!
JavaDay Lviv 2019 - Micronaut in action!Iván López Martín
 
CrossDvlup Madrid 2019 - Alexa, encantado de conocerte
CrossDvlup Madrid 2019 - Alexa, encantado de conocerteCrossDvlup Madrid 2019 - Alexa, encantado de conocerte
CrossDvlup Madrid 2019 - Alexa, encantado de conocerteIván López Martín
 

More from Iván López Martín (20)

SalmorejoTech 2024 - Spring Boot <3 Testcontainers
SalmorejoTech 2024 - Spring Boot <3 TestcontainersSalmorejoTech 2024 - Spring Boot <3 Testcontainers
SalmorejoTech 2024 - Spring Boot <3 Testcontainers
 
CommitConf 2024 - Spring Boot <3 Testcontainers
CommitConf 2024 - Spring Boot <3 TestcontainersCommitConf 2024 - Spring Boot <3 Testcontainers
CommitConf 2024 - Spring Boot <3 Testcontainers
 
Voxxed Days CERN 2024 - Spring Boot <3 Testcontainers.pdf
Voxxed Days CERN 2024 - Spring Boot <3 Testcontainers.pdfVoxxed Days CERN 2024 - Spring Boot <3 Testcontainers.pdf
Voxxed Days CERN 2024 - Spring Boot <3 Testcontainers.pdf
 
VMware - Testcontainers y Spring Boot
VMware - Testcontainers y Spring BootVMware - Testcontainers y Spring Boot
VMware - Testcontainers y Spring Boot
 
Spring IO 2023 - Dynamic OpenAPIs with Spring Cloud Gateway
Spring IO 2023 - Dynamic OpenAPIs with Spring Cloud GatewaySpring IO 2023 - Dynamic OpenAPIs with Spring Cloud Gateway
Spring IO 2023 - Dynamic OpenAPIs with Spring Cloud Gateway
 
Codemotion Madrid 2023 - Testcontainers y Spring Boot
Codemotion Madrid 2023 - Testcontainers y Spring BootCodemotion Madrid 2023 - Testcontainers y Spring Boot
Codemotion Madrid 2023 - Testcontainers y Spring Boot
 
CommitConf 2023 - Spring Framework 6 y Spring Boot 3
CommitConf 2023 - Spring Framework 6 y Spring Boot 3CommitConf 2023 - Spring Framework 6 y Spring Boot 3
CommitConf 2023 - Spring Framework 6 y Spring Boot 3
 
Construyendo un API REST con Spring Boot y GraalVM
Construyendo un API REST con Spring Boot y GraalVMConstruyendo un API REST con Spring Boot y GraalVM
Construyendo un API REST con Spring Boot y GraalVM
 
jLove 2020 - Micronaut and graalvm: The power of AoT
jLove 2020 - Micronaut and graalvm: The power of AoTjLove 2020 - Micronaut and graalvm: The power of AoT
jLove 2020 - Micronaut and graalvm: The power of AoT
 
Codemotion Madrid 2020 - Serverless con Micronaut
Codemotion Madrid 2020 - Serverless con MicronautCodemotion Madrid 2020 - Serverless con Micronaut
Codemotion Madrid 2020 - Serverless con Micronaut
 
JConf Perú 2020 - ¡Micronaut en acción!
JConf Perú 2020 - ¡Micronaut en acción!JConf Perú 2020 - ¡Micronaut en acción!
JConf Perú 2020 - ¡Micronaut en acción!
 
JConf Perú 2020 - Micronaut + GraalVM = <3
JConf Perú 2020 - Micronaut + GraalVM = <3JConf Perú 2020 - Micronaut + GraalVM = <3
JConf Perú 2020 - Micronaut + GraalVM = <3
 
JConf México 2020 - Micronaut + GraalVM = <3
JConf México 2020 - Micronaut + GraalVM = <3JConf México 2020 - Micronaut + GraalVM = <3
JConf México 2020 - Micronaut + GraalVM = <3
 
Developing Micronaut Applications With IntelliJ IDEA
Developing Micronaut Applications With IntelliJ IDEADeveloping Micronaut Applications With IntelliJ IDEA
Developing Micronaut Applications With IntelliJ IDEA
 
CommitConf 2019 - Micronaut y GraalVm: La combinación perfecta
CommitConf 2019 - Micronaut y GraalVm: La combinación perfectaCommitConf 2019 - Micronaut y GraalVm: La combinación perfecta
CommitConf 2019 - Micronaut y GraalVm: La combinación perfecta
 
Codemotion Madrid 2019 - ¡GraalVM y Micronaut: compañeros perfectos!
Codemotion Madrid 2019 - ¡GraalVM y Micronaut: compañeros perfectos!Codemotion Madrid 2019 - ¡GraalVM y Micronaut: compañeros perfectos!
Codemotion Madrid 2019 - ¡GraalVM y Micronaut: compañeros perfectos!
 
Greach 2019 - Creating Micronaut Configurations
Greach 2019 - Creating Micronaut ConfigurationsGreach 2019 - Creating Micronaut Configurations
Greach 2019 - Creating Micronaut Configurations
 
VoxxedDays Bucharest 2019 - Alexa, nice to meet you
VoxxedDays Bucharest 2019 - Alexa, nice to meet youVoxxedDays Bucharest 2019 - Alexa, nice to meet you
VoxxedDays Bucharest 2019 - Alexa, nice to meet you
 
JavaDay Lviv 2019 - Micronaut in action!
JavaDay Lviv 2019 - Micronaut in action!JavaDay Lviv 2019 - Micronaut in action!
JavaDay Lviv 2019 - Micronaut in action!
 
CrossDvlup Madrid 2019 - Alexa, encantado de conocerte
CrossDvlup Madrid 2019 - Alexa, encantado de conocerteCrossDvlup Madrid 2019 - Alexa, encantado de conocerte
CrossDvlup Madrid 2019 - Alexa, encantado de conocerte
 

Recently uploaded

Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfHyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfPrecisely
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxhariprasad279825
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):comworks
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024Stephanie Beckett
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Manik S Magar
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Mark Simos
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenHervé Boutemy
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsMark Billinghurst
 
Story boards and shot lists for my a level piece
Story boards and shot lists for my a level pieceStory boards and shot lists for my a level piece
Story boards and shot lists for my a level piececharlottematthew16
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationSlibray Presentation
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsSergiu Bodiu
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc
 
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostLeverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostZilliz
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek SchlawackFwdays
 
Search Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfSearch Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfRankYa
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyAlfredo García Lavilla
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii SoldatenkoFwdays
 

Recently uploaded (20)

Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfHyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptx
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!
 
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptxE-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache Maven
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR Systems
 
Story boards and shot lists for my a level piece
Story boards and shot lists for my a level pieceStory boards and shot lists for my a level piece
Story boards and shot lists for my a level piece
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck Presentation
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platforms
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
 
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostLeverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
 
Search Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfSearch Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdf
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easy
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko
 

G3 Summit 2016 - Taking Advantage of Groovy Annotations

  • 1. G3 Summit Taking advantage of Groovy Annotations Iván López - @ilopmar
  • 2. ➢ Iván López - @ilopmar ➢ Groovy & Grails developer Member of Grails team at OCI ➢ @MadridGUG coordinator http://www.madridgug.com ➢ Greach organizer (@greachconf) http://greachconf.com ➢ Speaker: SpringOne 2GX, GR8Conf, Codemotion, GeeCon, Spring IO, Greach, JavaCro, RigaDevDay,... About me...
  • 3. “ The best code is not code at all
  • 4. 1. A little bit of theory
  • 5. AST and compilation ▷ Abstract Syntax Tree ▷ AST modified during compilation ▷ Hook into the compiler phases
  • 8. AST transformations categories ▷ Code generation ▷ Class design ▷ Logging improvements ▷ Declarative concurrency ▷ Cloning and externalizing ▷ Safe scripting ▷ Compiler directives ▷ Dependencies handling
  • 10. @ToString ▷ Human readable toString ▷ Effective Java by Joshua Bloch (item 10)
  • 11. class User { String name Integer age } def u = new User(name: 'Iván', age: 36) println u // User@1d2a54b2
  • 12. @groovy.transform.ToString class User { String name Integer age } def u = new User(name: 'Iván', age: 36) assert u.toString() == 'User(Iván, 36)' class User { String name Integer age } def u = new User(name: 'Iván', age: 36) println u // User@1d2a54b2
  • 13. @groovy.transform.ToString class User { String name Integer age } def u = new User(name: 'Iván', age: 36) assert u.toString() == 'User(Iván, 36)' String toString() { def _result = new StringBuilder() _result.append('User(') _result.append(this.name) _result.append(', ') _result.append(this.age) _result.append(')') return _result.toString() } class User { String name Integer age } def u = new User(name: 'Iván', age: 36) println u // User@1d2a54b2
  • 14. @ToString ▷ includeNames, excludes, includes, includeSuper, includeSuperProperties, includeFields, ignoreNulls, includePackage, cache
  • 15. @ToString ▷ includeNames, excludes, includes, includeSuper, includeSuperProperties, includeFields, ignoreNulls, includePackage, cache @groovy.transform.ToString(includeNames = true, excludes = ['name']) class User { String name Integer age } def u = new User(name: 'Iván', age: 36) assert u.toString() == 'User(age:36)'
  • 16. @EqualsAndHashCode ▷ Generate equals and hashCode implementations ▷ Effective Java items 8 & 9
  • 17. @EqualsAndHashCode ▷ Generate equals and hashCode implementations ▷ Effective Java items 8 & 9 @groovy.transform.EqualsAndHashCode class User { String name Integer age } def u1 = new User(name: 'Iván', age: 36) def u2 = new User(name: 'Iván', age: 36) assert u1 == u2 assert u1.hashCode() == u2.hashCode()
  • 18. int hashCode() { def _result = HashCodeHelper.initHash() _result = HashCodeHelper.updateHash(_result, this.name) _result = HashCodeHelper.updateHash(_result, this.age) return _result } boolean canEqual(Object other) { return other instanceof User } boolean equals(Object other) { if (other == null) { return false } if (this.is(other)) { return true } if (!(other instanceof User)) { return false } User otherTyped = ((other) as User) if (!(otherTyped.canEqual(this))) { return false } if (!(this.getName().is(otherTyped.getName()))) { if (this.getName().is(this) && !(otherTyped.getName().is(otherTyped)) || !(this.getName().is(this)) && otherTyped.getName().is(otherTyped)) return false } else { if (!(this.getName().is(this) && otherTyped.getName().is(otherTyped))) { if (!(this.getName() == otherTyped.getName())) { return false } } } } if (!(this.getAge().is(otherTyped.getAge()))) { if (this.getAge().is(this) && !(otherTyped.getAge().is(otherTyped)) || !(this.getAge().is(this)) && otherTyped.getAge().is(otherTyped)) { return false } else { if (!(this.getAge().is(this) && otherTyped.getAge().is(otherTyped))) { if (!(this.getAge() == otherTyped.getAge())) { return false } } } } return true }
  • 19.
  • 20. @EqualsAndHashCode ▷ excludes, includes, callSuper, includeFields, cache, useCanEqual
  • 21. @EqualsAndHashCode ▷ excludes, includes, callSuper, includeFields, cache, useCanEqual @groovy.transform.EqualsAndHashCode(includes = 'name') class User { String name Integer age } def u1 = new User(name: 'Iván', age: 36) def u2 = new User(name: 'Iván', age: 42) assert u1 == u2 assert u1.hashCode() == u2.hashCode()
  • 24. @TupleConstructor ▷ Generate constructors @groovy.transform.TupleConstructor class User { String name Integer age } // Default map constructor def u1 = new User(name: 'Iván', age: 36)
  • 25. @TupleConstructor ▷ Generate constructors @groovy.transform.TupleConstructor class User { String name Integer age } // Default map constructor def u1 = new User(name: 'Iván', age: 36) // Generated tuple constructor def u2 = new User('Iván', 36) def u3 = new User('Iván')
  • 26. @TupleConstructor ▷ Generate constructors @groovy.transform.TupleConstructor class User { String name Integer age } // Default map constructor def u1 = new User(name: 'Iván', age: 35) // Generated tuple constructor def u2 = new User('Iván', 36) def u3 = new User('Iván') User(String name = null, Integer age = null) { this.name = name this.age = age }
  • 27. @TupleConstructor ▷ excludes, includes, includeFields, includeProperties, includeSuperFields, includeSuperProperties, callSuper, force
  • 28. @Canonical ▷ @ToString + @EqualsAndHashCode + @TupleConstructor
  • 29. @Canonical ▷ @ToString + @EqualsAndHashCode + @TupleConstructor @groovy.transform.Canonical class User { String name Integer age }
  • 30. @Canonical ▷ @ToString + @EqualsAndHashCode + @TupleConstructor def u1 = new User(name: 'Iván', age: 36) assert u1.toString() == 'User(Iván, 36)' // @ToString @groovy.transform.Canonical class User { String name Integer age }
  • 31. @Canonical ▷ @ToString + @EqualsAndHashCode + @TupleConstructor def u2 = new User('Iván', 36) // @TupleConstructor assert u2.toString() == 'User(Iván, 36)' def u1 = new User(name: 'Iván', age: 36) assert u1.toString() == 'User(Iván, 36)' // @ToString @groovy.transform.Canonical class User { String name Integer age }
  • 32. @Canonical ▷ @ToString + @EqualsAndHashCode + @TupleConstructor assert u1 == u2 // @EqualsAndHashCode assert u1.hashCode() == u2.hashCode() // @EqualsAndHashCode def u2 = new User('Iván', 36) // @TupleConstructor assert u2.toString() == 'User(Iván, 36)' def u1 = new User(name: 'Iván', age: 36) assert u1.toString() == 'User(Iván, 36)' // @ToString @groovy.transform.Canonical class User { String name Integer age }
  • 33. @InheritConstructors ▷ Reduce boilerplate code when parent classes have multiple constructors ▷ Useful when overriding exception classes
  • 35. protected MyException(String param0, Throwable param1, boolean param2, boolean param3) { super(param0, param1, param2, param3) } public MyException(Throwable param0) { super(param0) } public MyException(String param0, Throwable param1) { super(param0, param1) } public MyException(String param0) { super(param0) } public MyException() { super() } @groovy.transform.InheritConstructors class MyException extends Exception { }
  • 36. @Lazy ▷ Lazy initialization of fields ▷ Useful when creating expensive resources ▷ Effective Java item 71
  • 38. class SomeBean { @Lazy LinkedList myField } public LinkedList getMyField() { if ($myField != null) { $myField } else { $myField = new LinkedList() } }
  • 39. @Sortable ▷ Comparable interface ▷ compareTo method natural order ▷ N methods returning comparators ▷ Effective Java item 12
  • 40. @groovy.transform.Sortable class User { String name Integer age Integer born }
  • 41. public int compareTo(User other) { if (this.is(other)) return 0 Integer value = 0 value = this.name <=> other.name if (value != 0) return value value = this.age <=> other.age if (value != 0) return value value = this.born <=> other.born if (value != 0) return value return 0 } private static class User$NameComparator extends AbstractComparator<User> { public int compare(User arg0, User arg1) { if (arg0 == arg1) return 0 if (arg0 != null && arg1 == null) return -1 if (arg0 == null && arg1 != null) return 1 return arg0.name <=> arg1.name } } private static class User$AgeComparator extends AbstractComparator<User> { ... } @groovy.transform.Sortable class User { String name Integer age Integer born }
  • 42. @groovy.transform.Sortable class User { String name Integer age Integer born }
  • 43. def users = [ new User(name: 'Mary', age: 15, born: 2000), new User(name: 'Peter', age: 44, born: 1970), new User(name: 'John', age: 35, born: 1979), ] @groovy.transform.Sortable class User { String name Integer age Integer born }
  • 44. assert users.sort(false, User.comparatorByName())*.name == ['John', 'Mary', 'Peter'] assert users.sort(false, User.comparatorByAge())*.born == [2000, 1979, 1970] def users = [ new User(name: 'Mary', age: 15, born: 2000), new User(name: 'Peter', age: 44, born: 1970), new User(name: 'John', age: 35, born: 1979), ] @groovy.transform.Sortable class User { String name Integer age Integer born }
  • 45. @Sortable ▷ includes, excludes @groovy.transform.Sortable(excludes = 'age') class User { String name Integer age Integer born } def users = [ new User(name: 'Mary', age: 15, born: 2000), new User(name: 'Peter', age: 44, born: 1970), new User(name: 'John', age: 35, born: 1979), ] assert users.sort(false, User.comparatorByName())*.name == ['John', 'Mary', 'Peter'] assert users.sort(false, User.comparatorByAge())*.born == [2000, 1979, 1970]
  • 46. @Builder ▷ Create fluent API calls ▷ Multiple building strategies ▷ Multiple configuration options: builder name, prefix, excludes, includes,... ▷ Effective Java item 2
  • 47. @groovy.transform.builder.Builder class User { String name Integer age Integer born }
  • 48. @groovy.transform.builder.Builder class User { String name Integer age Integer born } def u = User.builder() .name('Iván') .age(36) .born(1979) .build() assert u.name == 'Iván' assert u.age == 36 assert u.born == 1979
  • 49. public static class User$UserBuilder extends Object { private String name private Integer age private Integer born public User$UserBuilder() { } public User$UserBuilder name(String name) { this.name = name return this } public User$UserBuilder age(Integer age) { this.age = age return this } public User$UserBuilder born(Integer born) { this.born = born return this } public User build() { User _theUser = new User() _theUser.name = name _theUser.age = age _theUser.born = born return _theUser } } @groovy.transform.builder.Builder class User { String name Integer age Integer born } def u = User.builder() .name('Iván') .age(36) .born(1979) .build() assert u.name == 'Iván' assert u.age == 36 assert u.born == 1979
  • 51. @Delegate ▷ Implements delegation design pattern ▷ Delegate calls on object to method on delegated properties ▷ All public methods are delegated
  • 52. import java.time.LocalDate class Conference { @groovy.lang.Delegate LocalDate when String name }
  • 53. import java.time.LocalDate class Conference { @groovy.lang.Delegate LocalDate when String name } def greach = new Conference(name: 'Greach', when: LocalDate.of(2017, 03, 31)) def gr8conf = new Conference(name: 'GR8Conf' when: LocalDate.of(2017, 05, 31))
  • 54. def greach = new Conference(name: 'Greach', when: LocalDate.of(2017, 03, 31)) def gr8conf = new Conference(name: 'GR8Conf' when: LocalDate.of(2017, 05, 31)) assert greach.isBefore(gr8conf) import java.time.LocalDate class Conference { @groovy.lang.Delegate LocalDate when String name }
  • 55. class Conference { ... public boolean isAfter(ChronoLocalDate param0) { when.isAfter(param0) } public boolean isBefore(ChronoLocalDate param0) { when.isBefore(param0) } ... } def greach = new Conference(name: 'Greach', when: LocalDate.of(2017, 03, 31)) def gr8conf = new Conference(name: 'GR8Conf' when: LocalDate.of(2017, 05, 31)) assert greach.isBefore(gr8conf) import java.time.LocalDate class Conference { @groovy.lang.Delegate LocalDate when String name }
  • 56. @Immutable ▷ Create immutable classes ▷ Effective Java item 15 ▷ Rules for immutability
  • 57. @groovy.transform.Immutable class User { String name Integer age } def u = new User(name: 'Iván', age: 36)
  • 58. // This does not compile // You are not allowed to overwrite // the final class 'User'. class Admin extends User { } @groovy.transform.Immutable class User { String name Integer age } def u = new User(name: 'Iván', age: 36)
  • 59. @groovy.transform.Immutable class User { String name Integer age } def u = new User(name: 'Iván', age: 36) try { u.name = 'John' } catch (ReadOnlyPropertyException e) { println e } // This does not compile // You are not allowed to overwrite // the final class 'User'. class Admin extends User { }
  • 60. @Memoized ▷ Cache the result of a method
  • 61. @Memoized ▷ Cache the result of a method @groovy.transform.Memoized Long fibonacci(Integer n) { if (n < 2) return 1 else return fibonacci(n-1) + fibonacci(n-2) } fibonacci(300)
  • 62. @Memoized ▷ Cache the result of a method @groovy.transform.Memoized Long fibonacci(Integer n) { if (n < 2) return 1 else return fibonacci(n-1) + fibonacci(n-2) } fibonacci(300) @groovy.transform.Memoized User getUserInfo(Long userId) { // Expensive repetitive // network operation }
  • 64. @Log, @Log4j, @Log4j2, @Slf4j ▷ Static final field for the logger
  • 65. @Log, @Log4j, @Log4j2, @Slf4j @groovy.util.logging.Log4j class MyClass { void method() { log.debug "My debug message" } } ▷ Static final field for the logger
  • 66. @Log, @Log4j, @Log4j2, @Slf4j @groovy.util.logging.Log4j class MyClass { void method() { log.debug "My debug message" } } ▷ Static final field for the logger class MyClass { private static final Logger log = Logger.getLogger(Saludador.name) void method() { if (log.isLoggable(Level.DEBUG)) { log.debug "My debug message" } } }
  • 68. Declarative concurrency ▷ @Synchronized ▷ @WithReadLock ▷ @WithWriteLock
  • 70. Cloning and externalizing ▷ @AutoClone ▷ @AutoExternalize
  • 72. Safe scripting ▷ @ThreadInterrupt ▷ @TimedInterrupt ▷ @ConditionalInterrupt
  • 74. Compiler directives ▷ @TypeChecked ▷ @CompileStatic ▷ @CompileDynamic
  • 77. @Grab ▷ Grape dependency manager @Grab(group='org.springframework', module='spring-orm', version='3.2.5.RELEASE') import org.springframework.jdbc.core.JdbcTemplate // or @Grab('org.springframework:spring-orm:3.2.5.RELEASE') import org.springframework.jdbc.core.JdbcTemplate
  • 78. @GrabResolver ▷ Grape dependency manager @Grab(group='org.springframework', module='spring-orm', version='3.2.5.RELEASE') import org.springframework.jdbc.core.JdbcTemplate // or @Grab('org.springframework:spring-orm:3.2.5.RELEASE') import org.springframework.jdbc.core.JdbcTemplate @GrabResolver(name='restlet', root='http://maven.restlet.org/') @Grab(group='org.restlet', module='org.restlet', version='1.1.6')
  • 79. @GrabExclude ▷ Grape dependency manager @Grab(group='org.springframework', module='spring-orm', version='3.2.5.RELEASE') import org.springframework.jdbc.core.JdbcTemplate // or @Grab('org.springframework:spring-orm:3.2.5.RELEASE') import org.springframework.jdbc.core.JdbcTemplate @GrabResolver(name='restlet', root='http://maven.restlet.org/') @Grab(group='org.restlet', module='org.restlet', version='1.1.6') @Grab('net.sourceforge.htmlunit:htmlunit:2.8') @GrabExclude('xml-apis:xml-apis')
  • 80. Bonus
  • 81. @Pokemon class Foo { void doStuff() { try { // Some code that can throws // different exceptions } catch (e) { // Gotta catch’em all } } }
  • 82. @Pokemon class Foo { void doStuff() { try { // Some code that can throws // different exceptions } catch (e) { // Gotta catch’em all } } } class Foo { @com.github.danveloper.ast.Pokemon void doStuff() { // code } }
  • 85. “ The best code is not code at all