SlideShare a Scribd company logo
Apache Groovy's Metaprogramming Options and You
@aalmiray | andresalmiray.com
Andres
Almiray
Seasoned Sourceror

@ Oracle

Apache Groovy PMC

Java Champion

Hackergarten

github.com/aalmiray
Hot Releases!
3.0.6
4.0.0-alpha-1
@aalmiray | andresalmiray.com
https://en.wikipedia.org/wiki/Metaprogramming
Metaprogramming is a programming technique in which
computer programs have the ability to treat other programs
as their data. 

It means that a program can be designed to read, generate,
analyze or transform other programs, and even modify itself
while running. 

In some cases, this allows programmers to minimize the
number of lines of code to express a solution, in turn
reducing development time. It also allows programs greater
flexibility to efficiently handle new situations without
recompilation.
Apache Groovy's Metaprogramming Options and You
Apache Groovy's Metaprogramming Options and You
M.O.P.
@aalmiray | andresalmiray.com
Meta Object Protocol
• Every Class has a companion Metaclass 

• Metaclasses provide additional behavior such as

• Properties

• Methods

• Modifications are visible only to Groovy.
Enhancing a Groovy class
1 class Person {
2 String name
3 }
4
5 Person.metaClass.greet = { s ->
6 "Hello $s, my name is $name"
7 }
8
9 p = new Person(name: 'Andres')
10 p.greet('Groovy')
11
12 // Hello Groovy, my name is Andres
Enhancing a Java class
1 String.metaClass.spongeBob = {
2 int i = 0
3 delegate.toCharArray()collect { c ->
4 (i++ % 2 != 0) ? c : c.toUpperCase()
5 }.join('')
6 }
7
8 'Metaprogramming is fun'.spongeBob()
9
10 // MeTaPrOgRaMmInG Is fUn
DOES NOT UNDERSTAND
A catch-all option
1 class Foo {
2 Object methodMissing(String name, Object args) {
3 "What do you mean by ${name}(${args})?"
4 }
5 }
6
7 def foo = new Foo()
8 foo.say('Groovy')
9
10 // What do you mean by say([Groovy])?
A catch-all option
1 class Foo {
2 void propertyMissing(String name, Object arg) {
3 println "Can't assign a '$name' property to you!"
4 }
5
6 Object propertyMissing(String name) {
7 "You don't have a property named '$name'!"
8 }
9 }
10
11 def foo = new Foo()
12 println foo.id
13 foo.lang = 'Groovy'
14
15 // You don't have a property named 'id'!
16 // Can't assign a 'lang' property to you!
@aalmiray | andresalmiray.com
Does not Understand
• Method signatures must match the convention

• Object methodMissing(String, Object)

• void propertyMissing(String, Object)

• Object propertyMissing(String)

• May be implemented by both Groovy and Java classes
Categories
1 class Greeter {
2 static String greet(String self) {
3 "Hello ${self}!"
4 }
5 }
6
7 use(Greeter) {
8 'Groovy'.greet()
9 }
10
11 // Hello Groovy!
Categories
1 @Grab('org.apache.commons:commons-lang3:3.11')
2 import org.apache.commons.lang3.StringUtils
3
4 use(StringUtils) {
5 'Groovy'.chop() == 'Groov'
6 }
@aalmiray | andresalmiray.com
Categories
• Affect classes inside a specific scope.

• Methods must be static.

• Type of first argument becomes the receiver.
Mixins
1 @Grab('org.apache.commons:commons-lang3:3.11')
2 import org.apache.commons.lang3.StringUtils
3
4 class Greeter {
5 static String greet(String self) {
6 "Hello ${self}!"
7 }
8 }
9
10 String.mixin Greeter, StringUtils
11
12 'Groovy'.greet()
13 'Groovy'.chop()
14
15 // Hello Groovy!
16 // Groov
@aalmiray | andresalmiray.com
Mixins
• Like categories but their scope is not limited.

• Applies to both Groovy and Java classes.
Traits
1 interface NameProvider {
2 String getName()
3 }
4
5 trait WithName implements NameProvider {
6 String name
7 }
8
9 class Person implements WithName { }
10
11 String greet(NameProvider np) {
12 "Hello $np.name"
13 }
14
15 p = new Person(name: 'Groovy')
16 greet(p)
17
18 // Hello Groovy
@aalmiray | andresalmiray.com
Traits
• Java 8 gave us default methods on interfaces

• Groovy gives you that plus a stateful option
@aalmiray | andresalmiray.com
Extension Modules
• Like mixins but they are globally available.

• Can modify Groovy and Java classes.

• Provide instance and static methods.

• Can be type checked by the compiler.

• Require an additional resource (module descriptor).
Extension
1 package griffon.plugins.bcrypt;
2
3 public class BCryptExtension {
4 public static String encodeAsBcrypt(String self) {
5 return BCrypt.hashpw(self, BCrypt.gensalt());
6 }
7
8 public static String encodeAsBcrypt(String self, int
9 genSaltRound) {
10 return BCrypt.hashpw(self, BCrypt.gensalt(genSaltRound));
11 }
12 }
/META-INF/groovy/
org.codehaus.groovy.runtime.ExtensionModule
1 moduleName=griffon-bcrypt
2 moduleVersion=0.1
3 extensionClasses=griffon.plugins.bcrypt.BCryptExtension
4 staticExtensionClasses=
Using the Extension
1 String password = "my password"
2 // should give you a nice bcrypt hash
3 println password.encodeAsBcrypt()
Apache Groovy's Metaprogramming Options and You
@aalmiray | andresalmiray.com
Compile Time
• Modify the generated byte code.

• Modifications are visible to Groovy and Java classes.

• Modifications can be type checked by the compiler.
Apache Groovy's Metaprogramming Options and You
Apache Groovy's Metaprogramming Options and You
@aalmiray | andresalmiray.com
AST Xforms
• Two flavors:

• Local

• Global

• Writing your own requires knowledge of compiler APIs,
AST type hierarchy, Groovy internals, your standard dark
magic ;-)
@aalmiray | andresalmiray.com
Local AST Xforms
• Require two types:

• An interface that defines the entry point.

• An AST forms that’s linked to the interface.
@ToString
1 @groovy.transform.ToString
2 class Person {
3 String firstName
4 String lastName
5 }
6
7 p = new Person(firstName: 'Jack', lastName: 'Nicholson')
8
9 // Person(Jack, Nicholson)
@ToString
1 @java.lang.annotation.Documented
2 @Retention(RetentionPolicy.RUNTIME)
3 @Target({ElementType.TYPE})
4 @GroovyASTTransformationClass("org.codehaus.groovy.transform.
5 ToStringASTTransformation")
6 public @interface ToString {
7 ...
8 }
@ToString
1 @GroovyASTTransformation(phase = CompilePhase.CANONICALIZATION)
2 public class ToStringASTTransformation
3 extends AbstractASTTransformation {
4 public void visit(ASTNode[] nodes, SourceUnit source) {
5 // magic goes here
6 }
7 }
@Canonical
1 @groovy.transform.Canonical
2 class Person {
3 String firstName
4 String lastName
5 }
6 def p1 = new Person(firstName: 'Jack', lastName: 'Nicholson')
7 // Effect of @ToString
8 assert p1.toString() == 'Person(Jack, Nicholson)'
9
10 // Effect of @TupleConstructor
11 def p2 = new Person('Jack','Nicholson')
12 assert p2.toString() == 'Person(Jack, Nicholson)'
13
14 // Effect of @EqualsAndHashCode
15 assert p1==p2
16 // Effect of @EqualsAndHashCode
17 assert p1.hashCode()==p2.hashCode()
@Category
1 @groovy.lang.Category(String)
2 class Greeter {
3 String greet() {
4 "Hello ${this}!"
5 }
6 }
7
8 use(Greeter) {
9 'Groovy'.greet()
10 }
11
12 // Hello Groovy!
@Immutable
1 @groovy.transform.Immutable
2 class Point {
3 int x, y
4 }
5
6 p1 = new Point(10, 10)
7 p2 = new Point(x: 10, y: 10)
8 p3 = new Point(10, 20)
9
10 assert p1 == p2
11 assert p1 != p3
@Sortable
1 @groovy.transform.Sortable
2 class Thing {
3 String id
4 }
5
6 t1 = new Thing(id: '123')
7 t2 = new Thing(id: '456')
8
9 assert t1 < t2
@aalmiray | andresalmiray.com
70+ xforms available
@ASTTest @AnnotationCollector @AnnotationCollectorMode @AutoClone
@AutoCloneStyle @AutoExternalize @AutoFinal @AutoImplement @BaseScript
@Bindable @Canonical @Categoy @Commons @CompilationUnitAware
@CompileDynamic @CompileStatic @ConditionalInterrupt @Delegate
@EqualsAndHashCode @ExternalizeMethods @ExternalizeVerifier @Field
@Generated @Grab @GrabConfig @GrabExclude @GrabResolver @Grapes
@Immutable @ImmutableBase @ImmutableOptions @IndexedProperty
@InheritConstructors @Internal @KnownImmutable @Lazy @ListenerList @Log
@Log4j @Log4j2 @Macro @MapConstructor @Memoized @Mixin @NamedDelegate
@NamedParam @NamedParams @NamedVariant @Newify @NullCheck
@PackageScope @PackageScopeTarget @PlatformLog @PropertyOptions
@RecordBase @RecordType @SelfType @Singleton @Slf4j @Sortable @SourceURI
@Synchronized @TailRecursive @ThreadInterrupt @TimedInterrupt @ToString @Trait
@TupleConstructor @TypeChecked @TypeCheckingMode @Undefined @Vetoable
@VisibilityOptions @WithReadLock @WithWriteLock
@aalmiray | andresalmiray.com
Global AST Xforms
• They only require the AST xform implementation.

• They are always available to all classes during the
compilation step.
http://spockframework.org/
@aalmiray | andresalmiray.com
Implementing AST Xforms
• Use of compiler APIs such as Expression, Statement,
ClassNode, etc.

• May use ASTBuilder to create expressions and
statements from text, code, builder nodes.

• May use macro methods to simplify expressions.

• Refer to core AST forms for hints and tricks.
@aalmiray | andresalmiray.com
Resources
• https://groovy-lang.org/metaprogramming.html

• https://www.slideshare.net/paulk_asert/groovy-transforms

• A History of the Groovy Programming Language

• (https://dl.acm.org/doi/pdf/10.1145/3386326)
Apache Groovy's Metaprogramming Options and You
@aalmiray | andresalmiray.com

More Related Content

PDF
Building modular applications with JPMS and Layrry
PDF
Building modular applications with the Java Platform Module System and Layrry
PDF
Creating Better Builds with Gradle
PDF
What I wish I knew about maven years ago
PDF
Taking Micronaut out for a spin
PPTX
Play! Framework for JavaEE Developers
PPTX
Laravel introduction
PDF
Web a Quebec - JS Debugging
Building modular applications with JPMS and Layrry
Building modular applications with the Java Platform Module System and Layrry
Creating Better Builds with Gradle
What I wish I knew about maven years ago
Taking Micronaut out for a spin
Play! Framework for JavaEE Developers
Laravel introduction
Web a Quebec - JS Debugging

What's hot (20)

PDF
Web application development using Play Framework (with Java)
PDF
All the Laravel things: up and running to making $$
PDF
FITC - Here Be Dragons: Advanced JavaScript Debugging
PDF
An Introduction to the Laravel Framework (AFUP Forum PHP 2014)
PDF
Play Framework and Activator
PPTX
Intro to Laravel
PDF
What's New In Laravel 5
PDF
Laravel Introduction
PPTX
CollabSphere 2018 - Java in Domino After XPages
PPTX
Preparing for java 9 modules upload
PDF
Laravel
PDF
Introduction in the play framework
PPTX
Learning Maven by Example
PDF
Develop realtime web with Scala and Xitrum
PDF
Play Framework: The Basics
ODP
Projects In Laravel : Learn Laravel Building 10 Projects
PPTX
Maven tutorial
PPTX
What's New in Laravel 5 (Laravel Meetup - 23th Apr 15, Yogyakarta, ID)
PPT
Play framework
PPTX
Faster java ee builds with gradle [con4921]
Web application development using Play Framework (with Java)
All the Laravel things: up and running to making $$
FITC - Here Be Dragons: Advanced JavaScript Debugging
An Introduction to the Laravel Framework (AFUP Forum PHP 2014)
Play Framework and Activator
Intro to Laravel
What's New In Laravel 5
Laravel Introduction
CollabSphere 2018 - Java in Domino After XPages
Preparing for java 9 modules upload
Laravel
Introduction in the play framework
Learning Maven by Example
Develop realtime web with Scala and Xitrum
Play Framework: The Basics
Projects In Laravel : Learn Laravel Building 10 Projects
Maven tutorial
What's New in Laravel 5 (Laravel Meetup - 23th Apr 15, Yogyakarta, ID)
Play framework
Faster java ee builds with gradle [con4921]
Ad

Similar to Apache Groovy's Metaprogramming Options and You (20)

PDF
Oscon Java Testing on the Fast Lane
PDF
Apache Groovy: the language and the ecosystem
PDF
Atlassian Groovy Plugins
ZIP
Groovy and Grails in Action - Devoxx 2008 - University - Guillaume Laforge
PPT
JavaOne 2008 - TS-5793 - Groovy and Grails, changing the landscape of Java EE...
PDF
Introduction to Groovy runtime metaprogramming and AST transforms
PPT
2007 09 10 Fzi Training Groovy Grails V Ws
PPT
What's New in Groovy 1.6?
PDF
An Introduction to Groovy for Java Developers
PDF
Infinum android talks_10_getting groovy on android
PPTX
MetaProgramming with Groovy
PPTX
Metaprogramming with Groovy
PDF
Groovy 2 and beyond
PDF
Grooscript greach 2015
PDF
Grooscript gr8conf
PDF
Groovy On Trading Desk (2010)
PDF
Groovy Metaprogramming for Dummies
PPTX
Introducing PHP Latest Updates
PPT
Groovy & Grails: Scripting for Modern Web Applications
KEY
Groovy DSLs, from Beginner to Expert - Guillaume Laforge and Paul King - Spri...
Oscon Java Testing on the Fast Lane
Apache Groovy: the language and the ecosystem
Atlassian Groovy Plugins
Groovy and Grails in Action - Devoxx 2008 - University - Guillaume Laforge
JavaOne 2008 - TS-5793 - Groovy and Grails, changing the landscape of Java EE...
Introduction to Groovy runtime metaprogramming and AST transforms
2007 09 10 Fzi Training Groovy Grails V Ws
What's New in Groovy 1.6?
An Introduction to Groovy for Java Developers
Infinum android talks_10_getting groovy on android
MetaProgramming with Groovy
Metaprogramming with Groovy
Groovy 2 and beyond
Grooscript greach 2015
Grooscript gr8conf
Groovy On Trading Desk (2010)
Groovy Metaprogramming for Dummies
Introducing PHP Latest Updates
Groovy & Grails: Scripting for Modern Web Applications
Groovy DSLs, from Beginner to Expert - Guillaume Laforge and Paul King - Spri...
Ad

More from Andres Almiray (20)

PDF
Dealing with JSON in the relational world
PDF
Deploying to production with confidence 🚀
PDF
Going beyond ORMs with JSON Relational Duality Views
PDF
Setting up data driven tests with Java tools
PDF
Creando, creciendo, y manteniendo una comunidad de codigo abierto
PDF
Liberando a produccion con confianza
PDF
Liberando a produccion con confidencia
PDF
OracleDB Ecosystem for Java Developers
PDF
Softcon.ph - Maven Puzzlers
PDF
Maven Puzzlers
PDF
Oracle Database Ecosystem for Java Developers
PDF
JReleaser - Releasing at the speed of light
PDF
Going Reactive with g rpc
PDF
What I wish I knew about Maven years ago
PDF
The impact of sci fi in tech
PDF
Gradle Ex Machina - Devoxx 2019
PDF
Interacting with the Oracle Cloud Java SDK with Gradle
PDF
Gradle ex-machina
PPTX
Go Java, Go!
PDF
Going Reactive with gRPC
Dealing with JSON in the relational world
Deploying to production with confidence 🚀
Going beyond ORMs with JSON Relational Duality Views
Setting up data driven tests with Java tools
Creando, creciendo, y manteniendo una comunidad de codigo abierto
Liberando a produccion con confianza
Liberando a produccion con confidencia
OracleDB Ecosystem for Java Developers
Softcon.ph - Maven Puzzlers
Maven Puzzlers
Oracle Database Ecosystem for Java Developers
JReleaser - Releasing at the speed of light
Going Reactive with g rpc
What I wish I knew about Maven years ago
The impact of sci fi in tech
Gradle Ex Machina - Devoxx 2019
Interacting with the Oracle Cloud Java SDK with Gradle
Gradle ex-machina
Go Java, Go!
Going Reactive with gRPC

Recently uploaded (20)

PDF
Per capita expenditure prediction using model stacking based on satellite ima...
PDF
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
PDF
NewMind AI Monthly Chronicles - July 2025
PDF
KodekX | Application Modernization Development
PPTX
PA Analog/Digital System: The Backbone of Modern Surveillance and Communication
PPTX
Big Data Technologies - Introduction.pptx
PDF
Network Security Unit 5.pdf for BCA BBA.
PDF
Machine learning based COVID-19 study performance prediction
PPTX
Understanding_Digital_Forensics_Presentation.pptx
PDF
Modernizing your data center with Dell and AMD
PDF
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
PDF
Reach Out and Touch Someone: Haptics and Empathic Computing
PDF
Shreyas Phanse Resume: Experienced Backend Engineer | Java • Spring Boot • Ka...
PDF
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
PDF
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
PDF
Electronic commerce courselecture one. Pdf
PDF
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
PDF
Dropbox Q2 2025 Financial Results & Investor Presentation
PDF
Building Integrated photovoltaic BIPV_UPV.pdf
PDF
NewMind AI Weekly Chronicles - August'25 Week I
Per capita expenditure prediction using model stacking based on satellite ima...
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
NewMind AI Monthly Chronicles - July 2025
KodekX | Application Modernization Development
PA Analog/Digital System: The Backbone of Modern Surveillance and Communication
Big Data Technologies - Introduction.pptx
Network Security Unit 5.pdf for BCA BBA.
Machine learning based COVID-19 study performance prediction
Understanding_Digital_Forensics_Presentation.pptx
Modernizing your data center with Dell and AMD
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
Reach Out and Touch Someone: Haptics and Empathic Computing
Shreyas Phanse Resume: Experienced Backend Engineer | Java • Spring Boot • Ka...
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
Electronic commerce courselecture one. Pdf
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
Dropbox Q2 2025 Financial Results & Investor Presentation
Building Integrated photovoltaic BIPV_UPV.pdf
NewMind AI Weekly Chronicles - August'25 Week I

Apache Groovy's Metaprogramming Options and You

  • 2. @aalmiray | andresalmiray.com Andres Almiray Seasoned Sourceror @ Oracle Apache Groovy PMC Java Champion Hackergarten github.com/aalmiray
  • 4. @aalmiray | andresalmiray.com https://en.wikipedia.org/wiki/Metaprogramming Metaprogramming is a programming technique in which computer programs have the ability to treat other programs as their data. It means that a program can be designed to read, generate, analyze or transform other programs, and even modify itself while running. In some cases, this allows programmers to minimize the number of lines of code to express a solution, in turn reducing development time. It also allows programs greater flexibility to efficiently handle new situations without recompilation.
  • 8. @aalmiray | andresalmiray.com Meta Object Protocol • Every Class has a companion Metaclass • Metaclasses provide additional behavior such as • Properties • Methods • Modifications are visible only to Groovy.
  • 9. Enhancing a Groovy class 1 class Person { 2 String name 3 } 4 5 Person.metaClass.greet = { s -> 6 "Hello $s, my name is $name" 7 } 8 9 p = new Person(name: 'Andres') 10 p.greet('Groovy') 11 12 // Hello Groovy, my name is Andres
  • 10. Enhancing a Java class 1 String.metaClass.spongeBob = { 2 int i = 0 3 delegate.toCharArray()collect { c -> 4 (i++ % 2 != 0) ? c : c.toUpperCase() 5 }.join('') 6 } 7 8 'Metaprogramming is fun'.spongeBob() 9 10 // MeTaPrOgRaMmInG Is fUn
  • 12. A catch-all option 1 class Foo { 2 Object methodMissing(String name, Object args) { 3 "What do you mean by ${name}(${args})?" 4 } 5 } 6 7 def foo = new Foo() 8 foo.say('Groovy') 9 10 // What do you mean by say([Groovy])?
  • 13. A catch-all option 1 class Foo { 2 void propertyMissing(String name, Object arg) { 3 println "Can't assign a '$name' property to you!" 4 } 5 6 Object propertyMissing(String name) { 7 "You don't have a property named '$name'!" 8 } 9 } 10 11 def foo = new Foo() 12 println foo.id 13 foo.lang = 'Groovy' 14 15 // You don't have a property named 'id'! 16 // Can't assign a 'lang' property to you!
  • 14. @aalmiray | andresalmiray.com Does not Understand • Method signatures must match the convention • Object methodMissing(String, Object) • void propertyMissing(String, Object) • Object propertyMissing(String) • May be implemented by both Groovy and Java classes
  • 15. Categories 1 class Greeter { 2 static String greet(String self) { 3 "Hello ${self}!" 4 } 5 } 6 7 use(Greeter) { 8 'Groovy'.greet() 9 } 10 11 // Hello Groovy!
  • 16. Categories 1 @Grab('org.apache.commons:commons-lang3:3.11') 2 import org.apache.commons.lang3.StringUtils 3 4 use(StringUtils) { 5 'Groovy'.chop() == 'Groov' 6 }
  • 17. @aalmiray | andresalmiray.com Categories • Affect classes inside a specific scope. • Methods must be static. • Type of first argument becomes the receiver.
  • 18. Mixins 1 @Grab('org.apache.commons:commons-lang3:3.11') 2 import org.apache.commons.lang3.StringUtils 3 4 class Greeter { 5 static String greet(String self) { 6 "Hello ${self}!" 7 } 8 } 9 10 String.mixin Greeter, StringUtils 11 12 'Groovy'.greet() 13 'Groovy'.chop() 14 15 // Hello Groovy! 16 // Groov
  • 19. @aalmiray | andresalmiray.com Mixins • Like categories but their scope is not limited. • Applies to both Groovy and Java classes.
  • 20. Traits 1 interface NameProvider { 2 String getName() 3 } 4 5 trait WithName implements NameProvider { 6 String name 7 } 8 9 class Person implements WithName { } 10 11 String greet(NameProvider np) { 12 "Hello $np.name" 13 } 14 15 p = new Person(name: 'Groovy') 16 greet(p) 17 18 // Hello Groovy
  • 21. @aalmiray | andresalmiray.com Traits • Java 8 gave us default methods on interfaces • Groovy gives you that plus a stateful option
  • 22. @aalmiray | andresalmiray.com Extension Modules • Like mixins but they are globally available. • Can modify Groovy and Java classes. • Provide instance and static methods. • Can be type checked by the compiler. • Require an additional resource (module descriptor).
  • 23. Extension 1 package griffon.plugins.bcrypt; 2 3 public class BCryptExtension { 4 public static String encodeAsBcrypt(String self) { 5 return BCrypt.hashpw(self, BCrypt.gensalt()); 6 } 7 8 public static String encodeAsBcrypt(String self, int 9 genSaltRound) { 10 return BCrypt.hashpw(self, BCrypt.gensalt(genSaltRound)); 11 } 12 }
  • 24. /META-INF/groovy/ org.codehaus.groovy.runtime.ExtensionModule 1 moduleName=griffon-bcrypt 2 moduleVersion=0.1 3 extensionClasses=griffon.plugins.bcrypt.BCryptExtension 4 staticExtensionClasses=
  • 25. Using the Extension 1 String password = "my password" 2 // should give you a nice bcrypt hash 3 println password.encodeAsBcrypt()
  • 27. @aalmiray | andresalmiray.com Compile Time • Modify the generated byte code. • Modifications are visible to Groovy and Java classes. • Modifications can be type checked by the compiler.
  • 30. @aalmiray | andresalmiray.com AST Xforms • Two flavors: • Local • Global • Writing your own requires knowledge of compiler APIs, AST type hierarchy, Groovy internals, your standard dark magic ;-)
  • 31. @aalmiray | andresalmiray.com Local AST Xforms • Require two types: • An interface that defines the entry point. • An AST forms that’s linked to the interface.
  • 32. @ToString 1 @groovy.transform.ToString 2 class Person { 3 String firstName 4 String lastName 5 } 6 7 p = new Person(firstName: 'Jack', lastName: 'Nicholson') 8 9 // Person(Jack, Nicholson)
  • 33. @ToString 1 @java.lang.annotation.Documented 2 @Retention(RetentionPolicy.RUNTIME) 3 @Target({ElementType.TYPE}) 4 @GroovyASTTransformationClass("org.codehaus.groovy.transform. 5 ToStringASTTransformation") 6 public @interface ToString { 7 ... 8 }
  • 34. @ToString 1 @GroovyASTTransformation(phase = CompilePhase.CANONICALIZATION) 2 public class ToStringASTTransformation 3 extends AbstractASTTransformation { 4 public void visit(ASTNode[] nodes, SourceUnit source) { 5 // magic goes here 6 } 7 }
  • 35. @Canonical 1 @groovy.transform.Canonical 2 class Person { 3 String firstName 4 String lastName 5 } 6 def p1 = new Person(firstName: 'Jack', lastName: 'Nicholson') 7 // Effect of @ToString 8 assert p1.toString() == 'Person(Jack, Nicholson)' 9 10 // Effect of @TupleConstructor 11 def p2 = new Person('Jack','Nicholson') 12 assert p2.toString() == 'Person(Jack, Nicholson)' 13 14 // Effect of @EqualsAndHashCode 15 assert p1==p2 16 // Effect of @EqualsAndHashCode 17 assert p1.hashCode()==p2.hashCode()
  • 36. @Category 1 @groovy.lang.Category(String) 2 class Greeter { 3 String greet() { 4 "Hello ${this}!" 5 } 6 } 7 8 use(Greeter) { 9 'Groovy'.greet() 10 } 11 12 // Hello Groovy!
  • 37. @Immutable 1 @groovy.transform.Immutable 2 class Point { 3 int x, y 4 } 5 6 p1 = new Point(10, 10) 7 p2 = new Point(x: 10, y: 10) 8 p3 = new Point(10, 20) 9 10 assert p1 == p2 11 assert p1 != p3
  • 38. @Sortable 1 @groovy.transform.Sortable 2 class Thing { 3 String id 4 } 5 6 t1 = new Thing(id: '123') 7 t2 = new Thing(id: '456') 8 9 assert t1 < t2
  • 39. @aalmiray | andresalmiray.com 70+ xforms available @ASTTest @AnnotationCollector @AnnotationCollectorMode @AutoClone @AutoCloneStyle @AutoExternalize @AutoFinal @AutoImplement @BaseScript @Bindable @Canonical @Categoy @Commons @CompilationUnitAware @CompileDynamic @CompileStatic @ConditionalInterrupt @Delegate @EqualsAndHashCode @ExternalizeMethods @ExternalizeVerifier @Field @Generated @Grab @GrabConfig @GrabExclude @GrabResolver @Grapes @Immutable @ImmutableBase @ImmutableOptions @IndexedProperty @InheritConstructors @Internal @KnownImmutable @Lazy @ListenerList @Log @Log4j @Log4j2 @Macro @MapConstructor @Memoized @Mixin @NamedDelegate @NamedParam @NamedParams @NamedVariant @Newify @NullCheck @PackageScope @PackageScopeTarget @PlatformLog @PropertyOptions @RecordBase @RecordType @SelfType @Singleton @Slf4j @Sortable @SourceURI @Synchronized @TailRecursive @ThreadInterrupt @TimedInterrupt @ToString @Trait @TupleConstructor @TypeChecked @TypeCheckingMode @Undefined @Vetoable @VisibilityOptions @WithReadLock @WithWriteLock
  • 40. @aalmiray | andresalmiray.com Global AST Xforms • They only require the AST xform implementation. • They are always available to all classes during the compilation step.
  • 42. @aalmiray | andresalmiray.com Implementing AST Xforms • Use of compiler APIs such as Expression, Statement, ClassNode, etc. • May use ASTBuilder to create expressions and statements from text, code, builder nodes. • May use macro methods to simplify expressions. • Refer to core AST forms for hints and tricks.
  • 43. @aalmiray | andresalmiray.com Resources • https://groovy-lang.org/metaprogramming.html • https://www.slideshare.net/paulk_asert/groovy-transforms • A History of the Groovy Programming Language • (https://dl.acm.org/doi/pdf/10.1145/3386326)