Nueve anotaciones de Groovy que te harán la vida más fácil al desarrollar

Los desarrolladores somos vagos. Es un hecho. Si podemos solventar un inconveniente escribiendo menos código y la solución es eficaz, mantenible, inteligible,… vamos a optar por ella sin pensarlo. Redactar menos código significa menos bugs, menos código que manterner y menos código que testar.

Tras haber aprendido en el artículo precedente la teoría sobre la metaprogramación en compile-time con Groovy esta vez veremos qué transformaciones nos ofrece Groovy out-of-the-box para hacernos la vida más simple en el momento de desarrollar.

Categorías de transformaciones

Todas y cada una de las transformaciones que ofrece Groovy por defecto son transformaciones AST locales y se pueden dividir en diferentes categorías dependiendo del aspecto que cubren.

Generación de código

Se incluyen transformaciones que nos asisten a suprimir código redundante y también superfluo. Es código que típicamente escribimos mas que no aporta información de utilidad. Probablemente la mayor parte de las anotaciones más empleadas pertenecen a esta categoría.

@ToString

¿Recordais el libro Effective Java de Joshua Bloch? Es una de las biblias que todo desarrollador Java debería leer por lo menos una vez en la vida. En él hay un capítulo entero dedicado al procedimiento toString() en el que se explica con detalle por qué razón deberíamos incorporar dicho procedimiento en nuestras clases. Veámoslo con un ejemplo:

class Usuario undefined

def o bien = new User(name: 'Iván', age: treinta y seis)
println o bien // User@1d2a54b2

@groovy.transform.ToString
class Usuario undefined

def o bien = new User(name: 'Iván', age: treinta y seis)
println o bien // User(Iván, treinta y seis)'

¿Considerablemente más inteligible verdad? Además de esto la anotación se puede configurar con múltiples factores para incluir o bien no el nombre de las propiedades, el bulto, excluir las propiedades con valor nulo,…

@EqualsAndHashCode

¿Cuántas veces habeis incorporado los métodos equals y hashCode en una clase? Y de esas, ¿cuántas veces lo habeis hecho mal? Seguramente más de las que os imaginais. Nuevamente, si leeis Effective Java, la explicación de de qué forma han de ser las implementaciones de equals y hashCode ocupa veinte páginas en el libro. ¿Quereis saber de qué manera redactar bien la implementación de equals y hashCode? No escribiéndola , dejando que el compilador se encargue de ella:

@groovy.transform.EqualsAndHashCode
class Usuario undefined

def u1 = new User(name: 'Iván', age: treinta y seis)
def u2 = new User(name: 'Iván', age: treinta y seis)

assert u1 == u2
assert u1.hashCode() == u2.hashCode()

@TuppleConstructor

Esta anotación sirve para producir diferentes constructores en función de las propiedades de la clase:

@groovy.transform.TupleConstructor
class Usuario undefined

// Constructor de mapa por defecto
def u1 = new User(name: 'Iván', age: treinta y seis)

// Constructores generador por @TupleConstructor
def u2 = new User('Iván', treinta y seis)
def u3 = new User('Iván')

Seguro que ahora os estais acordando de esa clase que tenía diez propiedades y una vez debisteis crear un montón de constructores para diferentes casos de empleo…

@Canonical

Es bastante común apreciar incorporar los métodos toString, equals y hashCode y además de esto estimar tener constructores en función de las propiedades. Esto implicaría anotar una clase con las 3 anotaciones que hemos visto previamente. Es por esta razón que existe la anotación @Canonical que es la suma de las tres:

@groovy.transform.Canonical
class Usuario undefined

def u1 = new User(name: 'Iván', age: treinta y seis)
def u2 = new User('Iván', treinta y seis) // @TupleConstructor
assert u2.toString() == 'User(Iván, treinta y seis)' // @ToString

assert u1 == u2 // @EqualsAndHashCode
assert u1.hashCode() == u2.hashCode() // @EqualsAndHashCode

@Builder

La última anotación que comentaremos de esta categoría nos deja crear builders para edificar objetos con un API fluida.

@groovy.transform.builder.Builder
class Usuario undefined

def o bien = Usuario.builder()
.name('Iván')
.age(treinta y seis)
.born(mil novecientos setenta y nueve)
.build()

assert o bien.name == 'Iván'
assert o bien.age == treinta y seis
assert o bien.born == mil novecientos setenta y nueve

Podemos configurar el nombre del builder, los prefijos, incluir y excluir propiedades e inclusive podemos delimitar nuestra estrategia de build.

Diseño de clases

Facilitan la implementación de patrones de diseño conocidos: delegate, singleton, immutable…

@Immutable

Ahora que está muy de tendencia el término de imperturbabilidad y lenguajes funcionales tenemos una forma sencillísima de redactar una clase inalterable. Si alguna vez lo habeis intentado sabreis que hay unas reglas (no tan triviales) que debemos cumplir para asegurar la imperturbabilidad. Con esa anotación no debemos preocuparnos de nada, la aplicamos y listo.

@groovy.transform.Immutable
class Usuario undefined

def o bien = new User(name: 'Iván', age: treinta y seis)

// Esto no compila por el hecho de que no podemos
// extender de una clase final
class Admin extends Usuario undefined

// Si procuramos alterar el nombre se lanzará una
// salvedad pues la propiedad es de solo-lectura
try undefined catch (ReadOnlyPropertyException y también) undefined

Mejoras en logging

Integran de una forma fácil la mayor parte de los frameworks de logging más usados.

@Log, @Log4j, @Log4j2, @Slfj4

Si bien verdaderamente son 4 anotaciones las he agrupado todas y cada una juntas (y las cuento como una) pues el funcionamiento es exactamente el mismo. La única diferencia es la biblioteca de logging que usan.

@groovy.util.logging.Log
class Saludador undefined

Si anotamos una clase con una de las anotaciones de logging, el compilador producirá un código equivalente al siguiente. Como vemos las diferencias son esenciales pues no debemos preocuparnos por instanciar el logger ni tampoco por revisar si el log level que estamos utilizando está activado para no perder el tiempo en procurar logar mensajes que van a ser descartados.

import java.util.logging.Level
import java.util.logging.Logger

class Saludador undefined

Concurrencia declarativa

Facilitan patrones comunes de concurrencia de una forma declarativa.

Clonado y externalización

Anotaciones para facilitar la implementación de los interfaces Clonable y Externalizable.

Scripting seguro

Producen código que dejará, por poner un ejemplo, interrumpir la ejecución de un script.

Directivas del compilador

Este conjunto incluye anotaciones que afectarán de forma directa en la semántica del código generado.

@CompileStatic

Es seguramente una de las anotaciones más usadas en la actualidad. Con ella estamos señalando al compilador que deseamos que compruebe y produzca nuestro código tal y como si fuera Java. O sea, una clase o bien procedimiento anotados con @CompileStatic van a ser verificados en tiempo de colección y vamos a perder las posibilidades de metaprogramación en runtime de Groovy. Con esta anotación el byte code generado es muy afín al que produciría el programa Java equivalente con lo que logramos que el desempeño mejore.
Generalmente, en nuestros días se considera una buena práctica anotar nuestro código no-activo con @CompileStatic.

Patrones de Swing

Incorporan determinados patrones realmente útiles si estamos desarrollando una aplicación Swing.

Ayuda en los tests

Se incluyen dos anotaciones utiles a lo largo de los test, incluyendo una para asistir a depurar otras transformaciones AST y el propio compilador de Groovy.

Manejo de dependencias

Manejo de las dependencias usando Grape.

@Grab

Creo que esta es una de esas anotaciones que no es bien conocida mas que una vez la descubres piensas todos y cada uno de los inconvenientes que te habría solucionado. Imaginad que estais escribiendo un script o bien pequeño código mas necesitais una dependencia externa. Utilizando @Grab declaramos la dependencia, importamos las clases que precisemos y la empleamos. La anotación se hace cargo de descargar la dependencia y incorporarla al classpath en el instante de ejecutar el script.

@Grab(group='org.springframework', module='spring-orm', version='3.2.5.RELEASE')
import org.springframework.jdbc.core.JdbcTemplate

// Equivalente
@Grab('org.springframework:spring-orm:3.2.5.RELEASE')
import org.springframework.jdbc.core.JdbcTemplate

Conclusiones

Hemos visto solo unas pocas anotaciones de las más de cuarenta y cinco que incluye Groovy y que están concebidas para asistirnos en nuestro día tras día como desarrolladores. Ciertas incorporan algunos métodos por nosotros, otras nos asisten a redactar builders o bien producir clases inalterables y otras hacen que nuestro código se compile estáticamente y se compruebe en colección en vez de ejecución. Si somos desarrolladores Groovy debemos conocer todo cuanto nos ofrece el lenguaje para asistirnos a ser más productivos y eficaces en el momento de desarrollar. Además de esto, como comentaba al comienzo del artículo, somo vagos, conque ¿por qué razón desearíamos redactar todo ese código pudiendo delegarlo en el compilador?

Si deseas conocer todas y cada una de las transformaciones libres o bien ahondar más en el empleo de las que he explicado, la documentación oficial es la mejor manera de hacerlo.

hljs.initHighlightingOnLoad();

code.hljs undefined
@media only screen and (min-width: 768px) undefined
@media only screen and (min-width: 1024px) undefined

Asimismo te invitamos a

Kotlin desde la perspectiva de un desarrollador Groovy

Mejora tu código Java utilizando Groovy

Las siete aplicaciones cloud que más están triunfando y que como desarrollador debes conocer

– La nueva

9 anotaciones de Groovy que te van a hacer la vida más simple al desarrollar

fue publicada originalmente en

turincon.net

por
Iván López