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 classCreació 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
Bookamb les propietatstitleiauthor. - 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
toStringa qualsevol classe anotada amb@ToString. - El mètode
toStringha 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 classSolució 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=30Conclusió
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
