Apache Groovy - A powerful multi-faceted programming language for the JVM platform with comprehensive module support
—
Groovy's AST (Abstract Syntax Tree) transformations provide compile-time code generation and modification through annotations, enabling powerful metaprogramming capabilities without runtime overhead.
Automatically generates toString() method implementation.
@interface ToString {
String[] excludes() default {}
String[] includes() default {}
boolean includeNames() default false
boolean includeFields() default false
boolean includeSuper() default false
boolean includeSuperProperties() default false
boolean ignoreNulls() default false
boolean includePackage() default false
boolean cache() default false
boolean allProperties() default false
}Usage examples:
import groovy.transform.ToString
@ToString
class Person {
String name
int age
String email
}
@ToString(includeNames=true, excludes=['email'])
class Employee {
String name
int age
String email
String department
}
def person = new Person(name: 'John', age: 30, email: 'john@example.com')
println person.toString() // Person(John, 30, john@example.com)
def employee = new Employee(name: 'Jane', age: 25, email: 'jane@company.com', department: 'IT')
println employee.toString() // Employee(name:Jane, age:25, department:IT)Generates equals() and hashCode() methods with proper implementations.
@interface EqualsAndHashCode {
String[] excludes() default {}
String[] includes() default {}
boolean callSuper() default false
boolean includeFields() default false
boolean cache() default false
boolean useCanEqual() default true
boolean allProperties() default false
}Usage example:
import groovy.transform.EqualsAndHashCode
@EqualsAndHashCode
class Point {
int x
int y
}
@EqualsAndHashCode(excludes=['id'])
class User {
String id
String name
String email
}
def p1 = new Point(x: 10, y: 20)
def p2 = new Point(x: 10, y: 20)
assert p1 == p2
assert p1.hashCode() == p2.hashCode()Generates constructor accepting parameters for specified properties.
@interface TupleConstructor {
String[] excludes() default {}
String[] includes() default {}
boolean includeFields() default false
boolean includeProperties() default true
boolean includeSuperFields() default false
boolean includeSuperProperties() default false
boolean callSuper() default false
boolean force() default false
boolean defaults() default true
boolean useSetters() default false
boolean allNames() default false
boolean allProperties() default false
}Usage example:
import groovy.transform.TupleConstructor
@TupleConstructor
class Book {
String title
String author
int year
}
@TupleConstructor(includes=['name', 'age'])
class Person {
String name
int age
String email = 'unknown@example.com'
}
def book = new Book('1984', 'George Orwell', 1949)
def person = new Person('John', 30)Implements the Singleton design pattern with various strategies.
@interface Singleton {
String property() default 'instance'
boolean lazy() default true
boolean strict() default true
}Usage examples:
import groovy.transform.Singleton
@Singleton
class DatabaseConnection {
String url = 'jdbc:h2:mem:testdb'
void connect() {
println "Connecting to $url"
}
}
@Singleton(lazy=false, strict=false)
class Logger {
void log(String message) {
println "[${new Date()}] $message"
}
}
// Usage
DatabaseConnection.instance.connect()
Logger.instance.log('Application started')Creates immutable classes with defensive copying and validation.
@interface Immutable {
String[] excludes() default {}
String[] includes() default {}
boolean copyWith() default false
boolean knownImmutableClasses() default false
String[] knownImmutables() default {}
}Usage example:
import groovy.transform.Immutable
@Immutable
class Point3D {
double x, y, z
}
@Immutable(copyWith=true)
class Person {
String name
int age
List<String> hobbies
}
def point = new Point3D(1.0, 2.0, 3.0)
def person = new Person('John', 30, ['reading', 'swimming'])
// Create modified copies
def olderPerson = person.copyWith(age: 31)Implements the Builder pattern for object construction.
@interface Builder {
String builderClassName() default ''
String builderMethodName() default 'builder'
String buildMethodName() default 'build'
String prefix() default ''
boolean includeSuperProperties() default false
boolean useSetters() default false
String[] excludes() default {}
String[] includes() default {}
boolean allNames() default false
boolean allProperties() default false
}Usage example:
import groovy.transform.builder.Builder
import groovy.transform.builder.ExternalStrategy
@Builder
class Computer {
String cpu
String memory
String storage
String graphics
}
@Builder(builderStrategy=ExternalStrategy, forClass=Person)
class PersonBuilder {}
// Usage
def computer = Computer.builder()
.cpu('Intel i7')
.memory('16GB')
.storage('1TB SSD')
.graphics('NVIDIA RTX')
.build()Enables static compilation for improved performance and type safety.
@interface CompileStatic {
TypeCheckingMode value() default TypeCheckingMode.PASS
String[] extensions() default {}
}Usage example:
import groovy.transform.CompileStatic
@CompileStatic
class Calculator {
int add(int a, int b) {
return a + b // Statically compiled
}
double multiply(double x, double y) {
return x * y // Type-safe operations
}
}Enables static type checking without full static compilation.
@interface TypeChecked {
TypeCheckingMode value() default TypeCheckingMode.PASS
String[] extensions() default {}
}Usage example:
import groovy.transform.TypeChecked
@TypeChecked
class StringProcessor {
String process(String input) {
return input.toUpperCase().trim() // Type-checked at compile time
}
}Caches method results for improved performance with repeated calls.
@interface Memoized {
int protectedCacheSize() default 0
int maxCacheSize() default 0
}Usage example:
import groovy.transform.Memoized
import groovy.transform.CompileStatic
@CompileStatic
class FibonacciCalculator {
@Memoized
long fibonacci(int n) {
if (n <= 1) return n
return fibonacci(n - 1) + fibonacci(n - 2)
}
@Memoized(maxCacheSize=100)
double expensiveCalculation(double input) {
// Simulate expensive computation
Thread.sleep(1000)
return Math.pow(input, 3) + Math.sin(input)
}
}Provides method-level synchronization with configurable lock objects.
@interface Synchronized {
String value() default ''
}Usage example:
import groovy.transform.Synchronized
class Counter {
private int count = 0
private final Object lockA = new Object()
private final Object lockB = new Object()
@Synchronized
void increment() {
count++
}
@Synchronized('lockA')
void methodA() {
// Uses lockA for synchronization
}
@Synchronized('lockB')
void methodB() {
// Uses lockB for synchronization
}
@Synchronized
int getCount() {
return count
}
}Implements the Delegation pattern by forwarding method calls.
@interface Delegate {
Class[] excludeTypes() default {}
String[] excludes() default {}
String[] includes() default {}
boolean deprecated() default false
boolean allNames() default false
boolean methodAnnotations() default false
boolean parameterAnnotations() default false
boolean interfaces() default true
}Usage example:
import groovy.transform.Delegate
class EventManager {
@Delegate List<String> events = []
@Delegate(excludes=['clear']) Map<String, Object> properties = [:]
void logEvent(String event) {
println "Event logged: $event"
events.add(event)
}
}
def manager = new EventManager()
manager.add('startup') // Delegated to List
manager.put('version', '1.0') // Delegated to Map
// manager.clear() // Not available due to excludesCreates category classes for adding methods to existing types.
@interface Category {
Class value()
}Usage example:
import groovy.transform.Category
@Category(String)
class StringExtensions {
boolean isPalindrome() {
return this == this.reverse()
}
String toCamelCase() {
return this.tokenize('_').collect {
it.toLowerCase().capitalize()
}.join('')
}
}
// Usage
use(StringExtensions) {
assert 'racecar'.isPalindrome()
assert 'hello_world'.toCamelCase() == 'HelloWorld'
}Adds mixin capabilities to classes.
@interface Mixin {
Class[] value()
}Defines and uses traits for multiple inheritance of behavior.
@interface Trait {}Usage example:
trait Flyable {
void fly() {
println "${this.class.simpleName} is flying"
}
}
trait Swimmable {
void swim() {
println "${this.class.simpleName} is swimming"
}
}
class Duck implements Flyable, Swimmable {
String name
}
class Fish implements Swimmable {
String species
}
def duck = new Duck(name: 'Donald')
duck.fly() // Duck is flying
duck.swim() // Duck is swimming
def fish = new Fish(species: 'Goldfish')
fish.swim() // Fish is swimmingCombines @ToString, @EqualsAndHashCode, and @TupleConstructor.
@interface Canonical {
String[] excludes() default {}
String[] includes() default {}
boolean includeFields() default false
boolean includeProperties() default true
boolean includeSuperFields() default false
boolean includeSuperProperties() default false
boolean callSuper() default false
boolean force() default false
boolean useSetters() default false
boolean allNames() default false
boolean allProperties() default false
}Usage example:
import groovy.transform.Canonical
@Canonical
class Product {
String name
BigDecimal price
String category
}
def product1 = new Product('Laptop', 999.99, 'Electronics')
def product2 = new Product('Laptop', 999.99, 'Electronics')
assert product1 == product2
println product1.toString()Inherits constructors from the superclass.
@interface InheritConstructors {
boolean constructorAnnotations() default false
boolean parameterAnnotations() default false
}Usage example:
import groovy.transform.InheritConstructors
class CustomException extends RuntimeException {
// Inherits all RuntimeException constructors
}
@InheritConstructors
class MyList extends ArrayList {
// Inherits all ArrayList constructors
void customMethod() {
println "Custom functionality"
}
}import org.codehaus.groovy.transform.GroovyASTTransformation
import org.codehaus.groovy.transform.ASTTransformation
import org.codehaus.groovy.control.CompilePhase
import org.codehaus.groovy.control.SourceUnit
import org.codehaus.groovy.ast.ASTNode
import org.codehaus.groovy.ast.ClassNode
import org.codehaus.groovy.ast.MethodNode
@GroovyASTTransformation(phase = CompilePhase.SEMANTIC_ANALYSIS)
class LogMethodCallsTransformation implements ASTTransformation {
void visit(ASTNode[] nodes, SourceUnit source) {
// Custom transformation logic
nodes.each { node ->
if (node instanceof ClassNode) {
addLoggingToMethods(node)
}
}
}
private void addLoggingToMethods(ClassNode classNode) {
classNode.methods.each { MethodNode method ->
// Add logging statements to method bodies
// Implementation details...
}
}
}
// Usage annotation
@interface LogMethodCalls {}import org.codehaus.groovy.transform.GroovyASTTransformationClass
import java.lang.annotation.ElementType
import java.lang.annotation.Target
import java.lang.annotation.Retention
import java.lang.annotation.RetentionPolicy
@Retention(RetentionPolicy.SOURCE)
@Target([ElementType.TYPE])
@GroovyASTTransformationClass(["com.example.LogMethodCallsTransformation"])
@interface LogMethodCalls {}
// Apply to classes
@LogMethodCalls
class MyService {
void processData() {
// Method calls will be logged automatically
}
}// Common AST transformation errors and solutions
// 1. Conflicting transformations
@ToString
@CompileStatic
class Example {
// Some combinations may cause issues
}
// 2. Missing dependencies
@Builder // Requires specific dependencies
class MyClass {
String property
}
// 3. Incorrect annotation usage
@Singleton(property="wrongType") // Should be String
class BadSingleton {}// Enable AST transformation debugging
System.setProperty("groovy.ast.debug", "true")
// Use AST viewer tools to inspect generated code
import org.codehaus.groovy.ast.ClassNode
import org.codehaus.groovy.control.CompilerConfiguration
def config = new CompilerConfiguration()
config.debug = true
config.verbose = true
// Examine generated bytecode
import groovy.transform.ToString
@ToString
class DebugExample {
String name
int value
}
// The generated toString method can be inspected
def example = new DebugExample(name: 'test', value: 42)
println example.toString()Install with Tessl CLI
npx tessl i tessl/maven-org-codehaus-groovy--groovy-all