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 TagLibsimport 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