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

From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptxHampshireHUG
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Scriptwesley chun
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024The Digital Insurer
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoffsammart93
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century educationjfdjdjcjdnsjd
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdflior mazor
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024The Digital Insurer
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...Martijn de Jong
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdfhans926745
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUK Journal
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsJoaquim Jorge
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Enterprise Knowledge
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...Neo4j
 
Evaluating the top large language models.pdf
Evaluating the top large language models.pdfEvaluating the top large language models.pdf
Evaluating the top large language models.pdfChristopherTHyatt
 

Recently uploaded (20)

From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
Evaluating the top large language models.pdf
Evaluating the top large language models.pdfEvaluating the top large language models.pdf
Evaluating the top large language models.pdf
 

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