1. Groovy vs Java
SIMILITUDES
- Palabras reservadas y sentencias
- try / catch / finally para la gestión de excepciones
- Definiciones de clase, interface, campos y métodos
- Instanciación de objetos mediante el operador new
- Empaquetado e importación
- Operadores, expresiones y asignaciones
- Estructuras de control
- Comentarios
- Comparten en mismo modelo de datos y nivel de ejecución de Java: JVM
OPCIONAL
- Paréntesis
- Sentencias return
- Punto y coma al final de las sentencias
- Algunas sentencias import Groovy ya las incluye automáticamente
groovy.lang.*, groovy.util.*, java.lang.*, java.util.*, java.util.regex.*, java.net.*, java.io.*, java.math.BigDecimal, java.math.BigInteger
DIFERENCIAS
- Closures (bloques de código)
- Soporte avanzado para cadenas de caracteres (GString), expresiones regulares y generación de plantillas
- Orientación a objetos real
- Sobrecarga de operadores y estructuras sintácticas de apoyo a las clases de Java existentes
- Sintaxis mejorada para los tipos existentes y nuevos tipos
- Librería extendida para las clases de Java existentes
- Groovy no soporta la construcción del bucle FOR mediante for(init;test;inc) pero lo hace con un rango
EL LENGUAJE
- Tipos y números
Tipos dinámicos con def
Groovy soporta tipos estáticos por compatibilidad con Java
Todo es un objeto
Autoboxing: int -> Integer e Integer -> int
Duck typing
- Tipos de colecciones
Simplicidad de conceptos
Tres tipos importantes: rangos, listas y mapas
Correspondencia con la semántica de Java salvo en el caso de los rangos
Link de ejemplos -> http://groovy.codehaus.org/JN1015-Collections
Link de ejemplos -> http://groovy.codehaus.org/JN1025-Arrays
Link de ejemplos -> http://groovy.codehaus.org/JN1035-Maps
- String vs GString
Comillas simples -> String ej. 'Hello world' Comillas dobles -> GString ej. "Hello $variable" Comillas simples triples -> String ej. ''' cadena de caracteres multilinea ''' Comillas dobles triples -> GString ej. """ cadena de caracteres con $variable multilinea """
- Estructuras de control
Las estructuras de control se basan Test Booleanos
Las expresiones de los Test Booleanos pueden ser de cualquier tipo no nulo
Reglas para verdadero:
1) Boolean: si el valor es true
2) Matcher: si el matcher tiene una coincidencia
3) Collection: si la colección no está vacía
4) Map: si el mapa no está vacío
5) String, GString: si la cadena no esta vacía
6) Number, Character: si el valor no es cero
7) Ninguno de los anteriores: si la referencia al objeto no es nula
- Closures
Son bloques de código reutilizables
Son objetos sin estado visible desde el exterior, sólo tienen comportamiento
Tienen dos propósitos principales: Ejecución en iteraciones y Manejo de recursos
- GroovyBeans
Son los clásicos JavaBeans
Tienen getters y setters
Es serializable para poder ser persistido
Groovy crea los accesors (getters y setters) y los constructores automáticamente
- Expando
Objeto dinámico: se le pueden añadir métodos y atributos en tiempo de ejecución
Muy parecido a un Map
Orientado al uso en pruebas
- Builders
Es un objeto que implementa el patrón Builder: construir objetos complejos a partir de otros objetos
Su propósito es el de construir estructuras jerárquicas
Se basa en la versatilidad de Groovy
Groovy incorpora BuilderSupport con:
1) DOMBuilder: para construir árboles DOM W3C
2) MarkupBuilder: para construir estrucuturas de marcas como XML
3) AntBuilder: para construir scripts de Apache Ant
4) SwingBuilder, SWTBuilder: para construir GUIs
* Guía para empezar
http://groovy.codehaus.org/Getting+Started+Guide
* Ejemplos
http://groovy.codehaus.org/Cookbook+Examples
* Una clase maravillosa
http://groovy.codehaus.org/ExpandoMetaClass
* Operadores en Groovy
http://groovy.codehaus.org/Operators
* Lo nuevo de Groovy 2.0 (@TypeChecked y @CompileStatic)
Artículo de Guillaume Laforge
Presentación de Guillaume Laforge en SpringOne2GX (2012)
* Adelanto de Groovy 2.1 y su roadmap
Presentación de Guillaume Laforge en Groovy/Grails eXchange conference (2012)
GROOVY TRICKS
- Ordenar Mapa por valor
//sort by map values def map = [a:3, b:2, c:1] map = map.sort {it.value} assert map == [c:1, b:2, a:3] //sort by map values in reverse map = [a:1, b:2, c:3] map = map.sort {a, b -> b.value <=> a.value} assert map == [c:3, b:2, a:1]
- Ordenar Mapa por clave
//sort by map keys def map = [a:3, b:2, c:1] map = map.sort {it.key} assert map == [a:3, b:2, c:1] //sort by map keys in reverse map = [a:1, b:2, c:3] map = map.sort {a, b -> b.key <=> a.key} assert map == [c:3,b:2,a:1]
- Ordenar Lista por un campo
List list = [ [id:0, firstName: 'Sachin', lastName: 'Tendulkar', age: 40 ], [id:1, firstName: 'Sachin', lastName: 'Tendulkar', age: 103 ], [id:2, firstName: 'Ajay', lastName: 'Tendulkar', age: 48 ], [id:3, firstName: 'Virendra', lastName: 'Sehwag', age: 5 ], [id:4, firstName: 'Virendra', lastName: 'Sehwag', age: 50 ], [id:5, firstName: 'Sachin', lastName: 'Nayyar', age: 15 ] ] list.sort{it.age} //In reverse list.sort{a, b -> b.age <=> a.age}
- Ordenar Lista por más de un campo
List list = [ [id:0, firstName: 'Sachin', lastName: 'Tendulkar', age: 40 ], [id:1, firstName: 'Sachin', lastName: 'Tendulkar', age: 103 ], [id:2, firstName: 'Ajay', lastName: 'Tendulkar', age: 48 ], [id:3, firstName: 'Virendra', lastName: 'Sehwag', age: 5 ], [id:4, firstName: 'Virendra', lastName: 'Sehwag', age: 50 ], [id:5, firstName: 'Sachin', lastName: 'Nayyar', age: 15 ] ] list.sort { a,b -> a.firstName <=> b.firstName ?: a.lastName <=> b.lastName ?: a.age <=> b.age }*.id * Output ids-> [2, 5, 0, 1, 3, 4]
- Añadiendo o sobreescribiendo métodos
class Book { String title } Book.metaClass.titleInUpperCase << {-> title.toUpperCase() } def b = new Book(title:"The Stand") assert "THE STAND" == b.titleInUpperCase()* El operador << es usado para añadir un método nuevo. Si hay que sobreescribir un método que ya existe sería con el operador =
Book.metaClass.toString = {-> title.toUpperCase() }
- Métodos take() y drop() de una Lista
def list = ['Simple', 'list', 'with', 5, 'items'] assert list.take(1) == ['Simple'] assert list.take(2) == ['Simple', 'list'] assert list.take(0) == [] // Whole list, because we take more items then the size of list assert list.take(6) == ['Simple', 'list', 'with', 5, 'items'] assert list.drop(1) == ['list', 'with', 5, 'items'] assert list.drop(3) == [5, 'items'] assert list.drop(5) == [] assert list.drop(0) == ['Simple', 'list', 'with', 5, 'items'] assert list == ['Simple', 'list', 'with', 5, 'items'] // After reading Tim Yates' comment I have added // more samples showing drop() and take() also work on // Maps, Iterators, CharSequences and arrays. def array = ['Rock on!', 'Groovy baby!'] as String[] assert array.take(1) == ['Rock on!'] as String[] assert array.drop(1) == ['Groovy baby!'] as String[] def range = 0..10 assert range.take(2) == [0,1] assert range.take(4) == 0..3 assert range.drop(5) == 5..10 def map = [1: 'one', 2: 'two', 3: 'three'] assert map.take(2) == [1: 'one', 2: 'two'] assert map.drop(2) == [3: 'three'] assert map.drop(3) == [:] def s = 'Hello Groovy world!' assert s.take(5) == 'Hello' assert s.drop(6) == 'Groovy world!'
- Extensiones de ficheros para scripts en Groovy
Por defecto las extensiones pueden ser: .groovy .gvy .gy .gsh Se ejecuta en la consola con el comando
$ groovy sample.gsh $ groovy sample
- Ejecutar un script via URL
En la consola ejecutar el comando
$ groovy http://www.edusama.com/samples/remotesample.groovy
- Ejecutar un script en tiempo de ejecución
Script ya creado Area.groovy
// Area.groovy Float r = "${radius}".toFloat() //radius will be passed as an argument to this script. return "Area of the circle : " + Math.PI*r*r;
Para ejecutar Area.groovy
import groovy.lang.Binding; import groovy.util.GroovyScriptEngine; GroovyScriptEngine gse = new GroovyScriptEngine("/home/divya/Desktop"); Binding binding = new Binding(); binding.setVariable("radius", 5); // Argument to be passed is "radius" with value 5 String areaOfCircle = gse.run("Area.groovy", binding); println areaOfCircle // Output: Area of the circle : 78.53981633974483
GRAILS TRICKS
- Patrón para capturar excepciones en acciones Grails
def myService def myAction = { try{ myService.doSomeTask() }catch(BusinessException ex ){ flash.message = ex.message }catch(Exception ex){ flash.message = "Internal Error" log.error("Unknown Exception:", ex); } }
- Lista de objetos accesibles desde los CONTROLLERS
request, response, session, servletContext, grailsApplication, params, flash
- Lista de objetos accesibles desde las GSPs
request, response, session, applicationContext, grailsApplication, params, flash
- Renderizar vistas o templates fuera de los Controladores
import grails.gsp.PageRenderer class RenderService { PageRenderer groovyPageRenderer String createConfirmMessage() { groovyPageRenderer.render view: '/email/confirm', model: [username: findUsername()] } String createWelcomeMessage() { groovyPageRenderer.render template: '/email/welcome', model: [username: findUsername()] } private String findUsername() { // Lookup username, for this example we return a // simple String value. 'edu' } }- Generando links fuera de los Controladores y las TagLibs
import org.codehaus.groovy.grails.web.mapping.LinkGenerator class LinkService { // Inject link generator LinkGenerator grailsLinkGenerator String generate() { // Generate: http://localhost:8080/link-generator/sample/show/100 grailsLinkGenerator.link(controller: 'sample', action: 'show', id: 100, absolute: true) } String resource() { // Generate: /link-generator/css/main.css grailsLinkGenerator.resource(dir: 'css', file: 'main.css') } String contextPath() { // Generate: /link-generator grailsLinkGenerator.contextPath } String serverUrl() { // Generate: http://localhost:8080/link-generator grailsLinkGenerator.serverBaseURL } }
- Conseguir la session en una Servicio
import org.springframework.web.context.request.RequestContextHolder def user = RequestContextHolder.currentRequestAttributes().getSession()
- Dependencias circulares de servicios de Grails
A veces cuando tenemos muchos servicios en una aplicación y estamos continuamente inyectándolos unos con otros, se puede producir este error:
Error creating bean with name '(inner bean)': Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'queueService': org.springframework.beans.factory.FactoryBeanNotInitializedException: FactoryBean is not fully initialized yet at java.security.AccessController.doPrivileged(Native Method) at RunApp_groovy$_run_closure2_closure7.doCall(RunApp_groovy:69)Para solucionarlo se debería de inyectar los servicios de la siguiente manera:
import org.springframework.context.* class QueueService implements ApplicationContextAware { ApplicationContext applicationContext def feedServiceBean // note the change of name to stop injection def slurpOffQueue() { feedServiceBean = applicationContext.getBean("feedService") feedServiceBean.doStuff() } }
- Evento onload en etiqueta body
En Grails, si pones un evento onload en una GSP cualquiera, no se lanzará el evento.
<body onload="someJSFunction()"> ... </body>
Y esto es se debe a que Grails sólo coge el body del layout y no el de la GSP. Para poder lanzar este tipo de eventos se tendrá que modificar el body del layout de Sitemesh de la siguiente manera,
<body onload="${pageProperty(name:'body.onload')}"> ... </body>
No hay comentarios:
Publicar un comentario