Introducció
Les Transformacions AST (Abstract Syntax Tree) són una característica avançada de Groovy que permet modificar el codi durant la compilació. Això permet als desenvolupadors afegir comportaments personalitzats, optimitzar el codi i aplicar patrons de disseny de manera automàtica.
Què és un AST?
Un AST és una representació en forma d'arbre de l'estructura sintàctica del codi font. Cada node de l'arbre representa una construcció del llenguatge de programació, com ara expressions, declaracions i blocs de codi.
Tipus de Transformacions AST
Groovy proporciona diversos tipus de transformacions AST que es poden aplicar al codi:
- Transformacions AST Estàtiques: S'apliquen durant la compilació i no tenen accés a la informació d'execució.
- Transformacions AST Dinàmiques: S'apliquen durant l'execució i poden modificar el comportament del codi en temps real.
Transformacions AST Estàndard
Groovy inclou diverses transformacions AST estàndard que es poden utilitzar directament. Algunes de les més comunes són:
@Immutable
: Fa que una classe sigui immutable.@Singleton
: Converteix una classe en un singleton.@Delegate
: Afegeix delegació a una classe.@Lazy
: Crea propietats que es calculen només quan es necessiten.
Exemple: Utilitzant @Immutable
import groovy.transform.Immutable @Immutable class Person { String name int age } def person = new Person(name: 'John', age: 30) println person.name // John println person.age // 30 // Intentar modificar una propietat llançarà una excepció // person.name = 'Jane' // Error: Cannot set the property 'name' on an immutable class
Creació de Transformacions AST Personalitzades
A més de les transformacions estàndard, Groovy permet crear transformacions AST personalitzades. Això es fa mitjançant l'ús d'anotacions i classes que implementen la interfície ASTTransformation
.
Exemple: Creant una Transformació AST Personalitzada
- Definir l'Anotació
import java.lang.annotation.ElementType import java.lang.annotation.Retention import java.lang.annotation.RetentionPolicy import java.lang.annotation.Target @Retention(RetentionPolicy.SOURCE) @Target([ElementType.METHOD]) @interface LogExecutionTime {}
- Implementar la Transformació
import org.codehaus.groovy.ast.* import org.codehaus.groovy.ast.expr.* import org.codehaus.groovy.ast.stmt.* import org.codehaus.groovy.control.* import org.codehaus.groovy.transform.* @GroovyASTTransformation(phase = CompilePhase.CANONICALIZATION) class LogExecutionTimeASTTransformation implements ASTTransformation { void visit(ASTNode[] nodes, SourceUnit source) { MethodNode methodNode = nodes[1] as MethodNode BlockStatement methodBody = methodNode.code as BlockStatement // Crear el codi per registrar el temps d'execució Statement startTime = new ExpressionStatement( new DeclarationExpression( new VariableExpression("startTime"), Token.newSymbol("=", -1, -1), new MethodCallExpression( new ClassExpression(ClassHelper.make(System)), "currentTimeMillis", ArgumentListExpression.EMPTY_ARGUMENTS ) ) ) Statement endTime = new ExpressionStatement( new MethodCallExpression( new ClassExpression(ClassHelper.make(System)), "out.println", new ArgumentListExpression( new BinaryExpression( new ConstantExpression("Execution time: "), Token.newSymbol("+", -1, -1), new BinaryExpression( new MethodCallExpression( new ClassExpression(ClassHelper.make(System)), "currentTimeMillis", ArgumentListExpression.EMPTY_ARGUMENTS ), Token.newSymbol("-", -1, -1), new VariableExpression("startTime") ) ) ) ) ) // Afegir el codi al cos del mètode methodBody.statements.add(0, startTime) methodBody.statements.add(endTime) } }
- Utilitzar l'Anotació
class Example { @LogExecutionTime void longRunningMethod() { Thread.sleep(1000) } } def example = new Example() example.longRunningMethod() // Output: Execution time: 1000 (aproximadament)
Exercicis Pràctics
Exercici 1: Utilitzar Transformacions AST Estàndard
- Crea una classe
Book
amb les propietatstitle
iauthor
. - Fes que la classe sigui immutable utilitzant l'anotació
@Immutable
. - Intenta modificar una propietat després de crear una instància i observa el resultat.
Exercici 2: Crear una Transformació AST Personalitzada
- Defineix una anotació
@ToString
. - Implementa una transformació AST que afegeixi un mètode
toString
a qualsevol classe anotada amb@ToString
. - El mètode
toString
ha de retornar una cadena amb els noms i valors de totes les propietats de la classe.
Solucions
Solució Exercici 1
import groovy.transform.Immutable @Immutable class Book { String title String author } def book = new Book(title: 'Groovy in Action', author: 'Dierk König') println book.title // Groovy in Action println book.author // Dierk König // Intentar modificar una propietat llançarà una excepció // book.title = 'New Title' // Error: Cannot set the property 'title' on an immutable class
Solució Exercici 2
- Definir l'Anotació
import java.lang.annotation.ElementType import java.lang.annotation.Retention import java.lang.annotation.RetentionPolicy import java.lang.annotation.Target @Retention(RetentionPolicy.SOURCE) @Target([ElementType.TYPE]) @interface ToString {}
- Implementar la Transformació
import org.codehaus.groovy.ast.* import org.codehaus.groovy.ast.expr.* import org.codehaus.groovy.ast.stmt.* import org.codehaus.groovy.control.* import org.codehaus.groovy.transform.* @GroovyASTTransformation(phase = CompilePhase.CANONICALIZATION) class ToStringASTTransformation implements ASTTransformation { void visit(ASTNode[] nodes, SourceUnit source) { ClassNode classNode = nodes[1] as ClassNode // Crear el mètode toString MethodNode toStringMethod = new MethodNode( "toString", Modifier.PUBLIC, ClassHelper.STRING_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, new BlockStatement( [new ReturnStatement( new ConstantExpression( classNode.properties.collect { prop -> "${prop.name}=${prop.name}" }.join(", ") ) )], new VariableScope() ) ) // Afegir el mètode a la classe classNode.addMethod(toStringMethod) } }
- Utilitzar l'Anotació
@ToString class Person { String name int age } def person = new Person(name: 'John', age: 30) println person.toString() // name=John, age=30
Conclusió
Les transformacions AST són una eina poderosa en Groovy que permeten modificar el codi durant la compilació per afegir funcionalitats, optimitzar el rendiment i aplicar patrons de disseny de manera automàtica. Amb les transformacions AST, els desenvolupadors poden crear codi més net, mantenible i eficient.
Curs de Programació Groovy
Mòdul 1: Introducció a Groovy
Mòdul 2: Sintaxi i Característiques del Llenguatge Groovy
Mòdul 3: Programació Orientada a Objectes en Groovy
Mòdul 4: Característiques Avançades de Groovy
Mòdul 5: Groovy en la Pràctica
- Entrada/Sortida de Fitxers
- Treballant amb XML i JSON
- Accés a Bases de Dades
- Desenvolupament Web amb Groovy
Mòdul 6: Proves i Depuració
Mòdul 7: Ecosistema i Eines de Groovy
- Eina de Construcció Gradle
- Framework de Proves Spock
- Framework Grails
- Altres Llibreries i Eines de Groovy
Mòdul 8: Millors Pràctiques i Temes Avançats
- Estil de Codi i Convencions
- Optimització del Rendiment
- Consideracions de Seguretat
- Concurrència en Groovy