![Page 1: Introduction to Groovy runtime metaprogramming and AST transforms](https://reader033.vdocuments.us/reader033/viewer/2022052411/55630a06d8b42a62598b57f1/html5/thumbnails/1.jpg)
Introduction to Groovy runtime metaprogramming and AST
transformsby Marcin GrzejszczakTooMuchCoding blog
![Page 2: Introduction to Groovy runtime metaprogramming and AST transforms](https://reader033.vdocuments.us/reader033/viewer/2022052411/55630a06d8b42a62598b57f1/html5/thumbnails/2.jpg)
Question
Integer getTimesTenOf(Integer number) {
return 10 * number;
}
assert 40 == getTimesTenOf(4)
How to calculate ten times a number?
![Page 3: Introduction to Groovy runtime metaprogramming and AST transforms](https://reader033.vdocuments.us/reader033/viewer/2022052411/55630a06d8b42a62598b57f1/html5/thumbnails/3.jpg)
Let’s invert the concept!
assert 40 == 4.tens
![Page 4: Introduction to Groovy runtime metaprogramming and AST transforms](https://reader033.vdocuments.us/reader033/viewer/2022052411/55630a06d8b42a62598b57f1/html5/thumbnails/4.jpg)
It can’t be done… Can it? public final class Integer ... {
// ...
}
![Page 5: Introduction to Groovy runtime metaprogramming and AST transforms](https://reader033.vdocuments.us/reader033/viewer/2022052411/55630a06d8b42a62598b57f1/html5/thumbnails/5.jpg)
Add that method!Integer.metaClass.getTimesTens = {
return 10 * delegate
}
assert 40 == 4.timesTen
![Page 6: Introduction to Groovy runtime metaprogramming and AST transforms](https://reader033.vdocuments.us/reader033/viewer/2022052411/55630a06d8b42a62598b57f1/html5/thumbnails/6.jpg)
Monkey patch
● Extend or modify the run-time code ● Do not alter the original source code ● Also known as duck punching and shaking
the bag
![Page 7: Introduction to Groovy runtime metaprogramming and AST transforms](https://reader033.vdocuments.us/reader033/viewer/2022052411/55630a06d8b42a62598b57f1/html5/thumbnails/7.jpg)
Classes with Groovypublic class Foo implements groovy.lang.GroovyObject
extends java.lang.Object {
}
![Page 8: Introduction to Groovy runtime metaprogramming and AST transforms](https://reader033.vdocuments.us/reader033/viewer/2022052411/55630a06d8b42a62598b57f1/html5/thumbnails/8.jpg)
GroovyObjectpublic interface GroovyObject {
Object invokeMethod(String name, Object args);
Object getProperty(String propertyName);
void setProperty(String propertyName, Object newValue);
MetaClass getMetaClass();
void setMetaClass(MetaClass metaClass);
}
![Page 9: Introduction to Groovy runtime metaprogramming and AST transforms](https://reader033.vdocuments.us/reader033/viewer/2022052411/55630a06d8b42a62598b57f1/html5/thumbnails/9.jpg)
Meta Object Protocol
● MetaObject is an object that manipulates, creates, describes, or implements other objects (including itself).
● Stored info includes base object's type, interface, class, methods etc. ● MetaObjects are examples of reflection concept● The Meta-Object-Protocol (MOP) is the collection of rules of how a request
for a method call is handled by the Groovy runtime system
![Page 10: Introduction to Groovy runtime metaprogramming and AST transforms](https://reader033.vdocuments.us/reader033/viewer/2022052411/55630a06d8b42a62598b57f1/html5/thumbnails/10.jpg)
MetaClass
MetaClass defines the behaviour of any given Groovy or Java class - ● The MetaClass interface has two parts:
○ Client API - via the extend MetaObjectProtocol interface ○ Contract with the Groovy runtime system.
● In general the compiler and Groovy runtime engine interact with methods on MetaClass class
● In general the MetaClass clients interact with the method defined by the MetaObjectProtocol interface
![Page 11: Introduction to Groovy runtime metaprogramming and AST transforms](https://reader033.vdocuments.us/reader033/viewer/2022052411/55630a06d8b42a62598b57f1/html5/thumbnails/11.jpg)
Expando● Kind of a dynamic bean. ● It will memorize
○ added properties○ added methods (from closures)
● Useful for ○ mocking○ when you don’t want to create a new class (you just want to record
behaviour)
![Page 12: Introduction to Groovy runtime metaprogramming and AST transforms](https://reader033.vdocuments.us/reader033/viewer/2022052411/55630a06d8b42a62598b57f1/html5/thumbnails/12.jpg)
Expandodef player = new Expando(name: 'Robert')
assert 'Robert' == player.name
player.surname = 'Lewandowski'
assert 'Lewandowski' == player.surname
player.presentYourself = {
return "Name: $name, Surname: $surname"
}
String result = player.presentYourself()
assert 'Name: Robert, Surname: Lewandowski' == result
![Page 13: Introduction to Groovy runtime metaprogramming and AST transforms](https://reader033.vdocuments.us/reader033/viewer/2022052411/55630a06d8b42a62598b57f1/html5/thumbnails/13.jpg)
ExpandoMetaClassA special implementation of a MetaClass that allows you to (using closures):
● dynamically add methods, ● constructors, ● properties and static methods
![Page 14: Introduction to Groovy runtime metaprogramming and AST transforms](https://reader033.vdocuments.us/reader033/viewer/2022052411/55630a06d8b42a62598b57f1/html5/thumbnails/14.jpg)
ExpandoMetaClass● ExpandoMetaClass - Borrowing Methods — Borrowing methods from other classes● ExpandoMetaClass - Constructors — Adding or overriding constructors● ExpandoMetaClass Domain-Specific Language● ExpandoMetaClass - Dynamic Method Names — Dynamically creating method names● ExpandoMetaClass - GroovyObject Methods — Overriding invokeMethod, getProperty and setProperty● ExpandoMetaClass - Interfaces — Adding methods on interfaces● ExpandoMetaClass - Methods — Adding or overriding instance methods● ExpandoMetaClass - Overriding static invokeMethod — Overriding invokeMethod for static methods● ExpandoMetaClass - Properties — Adding or overriding properties● ExpandoMetaClass - Runtime Discovery — Overriding invokeMethod for static methods● ExpandoMetaClass - Static Methods — Adding or overriding static methods
![Page 15: Introduction to Groovy runtime metaprogramming and AST transforms](https://reader033.vdocuments.us/reader033/viewer/2022052411/55630a06d8b42a62598b57f1/html5/thumbnails/15.jpg)
Add that method! - reminderInteger.metaClass.getTimesTen = {
return 10 * delegate
}
assert 40 == 4.timesTen
![Page 16: Introduction to Groovy runtime metaprogramming and AST transforms](https://reader033.vdocuments.us/reader033/viewer/2022052411/55630a06d8b42a62598b57f1/html5/thumbnails/16.jpg)
Add that method! - watch out!Integer.metaClass.getTimesTens = {
return 10 * delegate
}
Remember that :● You are mixing here a method to a class not to an object● In the same JVM all objects of that class will have that method added
to MetaClass! (You can image the downsides of this)● It’s safer to use categories - only a block of code will have those
methods mixed in
![Page 17: Introduction to Groovy runtime metaprogramming and AST transforms](https://reader033.vdocuments.us/reader033/viewer/2022052411/55630a06d8b42a62598b57f1/html5/thumbnails/17.jpg)
MOP - find that missing method!
Taken from Venkat's Programming Groovy 2
![Page 18: Introduction to Groovy runtime metaprogramming and AST transforms](https://reader033.vdocuments.us/reader033/viewer/2022052411/55630a06d8b42a62598b57f1/html5/thumbnails/18.jpg)
Metaprogramming in Groovy● Runtime
○ Categories○ Expando / MetaClass / ExpandoMetaClass
● Compile Time○ AST Transformations○ Extension Module
![Page 19: Introduction to Groovy runtime metaprogramming and AST transforms](https://reader033.vdocuments.us/reader033/viewer/2022052411/55630a06d8b42a62598b57f1/html5/thumbnails/19.jpg)
Runtime - drawbacks
● efficiency - finding if method exists● method / property missing - people start
asking questions how can that even compile● no IDE support
![Page 20: Introduction to Groovy runtime metaprogramming and AST transforms](https://reader033.vdocuments.us/reader033/viewer/2022052411/55630a06d8b42a62598b57f1/html5/thumbnails/20.jpg)
Abstract Syntax Tree● Representation of the abstract syntactic structure of
source code● Each node of the tree denotes a construct occurring in
the source code. ● The syntax is "abstract" in not representing every detail
appearing in the real syntax.
![Page 21: Introduction to Groovy runtime metaprogramming and AST transforms](https://reader033.vdocuments.us/reader033/viewer/2022052411/55630a06d8b42a62598b57f1/html5/thumbnails/21.jpg)
An abstract syntax tree for the following code for the Euclidean algorithm:
while b ≠ 0
if a > b
a = a − b
else
b = b − a
return a
![Page 22: Introduction to Groovy runtime metaprogramming and AST transforms](https://reader033.vdocuments.us/reader033/viewer/2022052411/55630a06d8b42a62598b57f1/html5/thumbnails/22.jpg)
![Page 23: Introduction to Groovy runtime metaprogramming and AST transforms](https://reader033.vdocuments.us/reader033/viewer/2022052411/55630a06d8b42a62598b57f1/html5/thumbnails/23.jpg)
AST Transformation
● Compile-time metaprogramming● Bytecode manipulation● Either global or local
○ Global in any compiler phase○ Local in a semantic analysis phase
or later
![Page 24: Introduction to Groovy runtime metaprogramming and AST transforms](https://reader033.vdocuments.us/reader033/viewer/2022052411/55630a06d8b42a62598b57f1/html5/thumbnails/24.jpg)
Did you know that…?Groovy compiler has 9 phases?
● Initialization● Parsing● Conversion● Semantic Analysis (important for Local AST transforms)● Canonicalization● Instruction Selection● Class Generation● Output● Finalization
![Page 25: Introduction to Groovy runtime metaprogramming and AST transforms](https://reader033.vdocuments.us/reader033/viewer/2022052411/55630a06d8b42a62598b57f1/html5/thumbnails/25.jpg)
AST Transformation annotations● @AnnotationCollector● @Externalize● @BaseScript● @Canonical● @CompileStatic● @TypeChecked● @ConditionalInterrupt● @EqualsAndHashcode● @Mixin● @Category● @Immutable● @Field● @IndexedProperty● @InheritConstructors● @Memoized● @PackageScope● @Synchronized
● @ThreadInterrupt● @TimedInterrupt● @ToString● @TupleConstructor● @WithReadLock● @WithWriteLock● @Delegate● @DelegatesTo● @Lazy● @Newify● @Singleton● @ASTTest● @AutoClone● @Commons● @Log● @Slf4j● @NotYetImplemented● @Grab● @GrabResolver
![Page 26: Introduction to Groovy runtime metaprogramming and AST transforms](https://reader033.vdocuments.us/reader033/viewer/2022052411/55630a06d8b42a62598b57f1/html5/thumbnails/26.jpg)
TooMuchCoding Git Github repository
TooMuchCoding Mercurial Bitbucket repository
![Page 27: Introduction to Groovy runtime metaprogramming and AST transforms](https://reader033.vdocuments.us/reader033/viewer/2022052411/55630a06d8b42a62598b57f1/html5/thumbnails/27.jpg)
Local AST transforms for dummies
● Check the Guidebook● Define an annotation● Create an AST transform for the annotation● Build the transform
![Page 28: Introduction to Groovy runtime metaprogramming and AST transforms](https://reader033.vdocuments.us/reader033/viewer/2022052411/55630a06d8b42a62598b57f1/html5/thumbnails/28.jpg)
![Page 29: Introduction to Groovy runtime metaprogramming and AST transforms](https://reader033.vdocuments.us/reader033/viewer/2022052411/55630a06d8b42a62598b57f1/html5/thumbnails/29.jpg)
AST transforms - not that easy :(
● Creating implementation is not trivial○ Verify node○ Verify preconditions○ Make the implementation
● Use tools○ AstBuilder from string○ AstBuilder from code○ AstBuilder from spec
● The code might get really messy
![Page 30: Introduction to Groovy runtime metaprogramming and AST transforms](https://reader033.vdocuments.us/reader033/viewer/2022052411/55630a06d8b42a62598b57f1/html5/thumbnails/30.jpg)
![Page 31: Introduction to Groovy runtime metaprogramming and AST transforms](https://reader033.vdocuments.us/reader033/viewer/2022052411/55630a06d8b42a62598b57f1/html5/thumbnails/31.jpg)
Sources and recommended readings
● Wikipedia (MonkeyPatch, MOP)● http://groovy.codehaus.org/● Groovy AST Demisitified● Groovy AST tutorials● Project Lombok for Java