Groovy is a great language with extremely powerful capabilities about compile time meta-programming. Do you know that provides more than 40 AST transformations out-of-the box just to make your life as a developer easier?
In this talk you will learn the most important transformations provided by Groovy. I'll use a lot of code examples to explain all the concepts.
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
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
}
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
}
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]
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
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 {
}
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
}
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"
}
}
}