Documentos de Académico
Documentos de Profesional
Documentos de Cultura
com
Tenga en cuenta que con este estilo de procesamiento, tenemos más trabajo por hacer. Cuando nuestro
elemento de iniciose llama al método, se nos proporciona información del evento SAX, incluido el nombre
del elemento (junto con un espacio de nombres, si se proporciona) y todos los atributos. Depende de
nosotros determinar si necesitamos esta información y procesarla o almacenarla según sea necesario
durante esta llamada de método. El analizador no hará más almacenamiento por nosotros. Esto minimiza
la sobrecarga de memoria del analizador, pero la implicación es que no podremos realizar un
procesamiento de estilo GPath y no estamos en condiciones de manipular una estructura de datos en
forma de árbol. Tendremos más que decir sobre la información del evento SAX cuando exploremos
XmlSlurpercon más detalle en la sección 14.2.
4
Elliotte Rusty Harold, “Una introducción a StAX”, O'Reilly XML.com, 2003, www.xml.com/pub/a/2003/09/17/
stax.html.
5
Este es el principal estilo basado en eventos compatible con .NET e incluido con Java 6.
www.it-ebooks.info
520 CPASADO14Trabajando con XML y JSON
importar javax.xml.stream.*
uso (XMLStreamCategory) {
eachStartElement(entrada.openStream()) { elemento ->
if (elemento.nombre.toString() != 'tarea') return switch
(elemento.hecho) {
caso '0':
próximo << elemento.rotura de Usos
título categoría
case { it != elemento.total } :
en marcha << elemento.título
}
}
}
afirmar en marcha == [
'usar en el proyecto actual'
]
afirmar próximo == [
'volver a leer DB capítulo',
'usar base de datos/XML combinación'
]
Tenga en cuenta que este estilo de análisis es similar al análisis de estilo SAX, excepto que estamos
ejecutando el ciclo de control principal nosotros mismos en lugar de que el analizador lo haga. Este estilo
tiene ventajas para ciertos tipos de procesamiento donde el código se vuelve más simple de escribir y
comprender.
Suponga que tiene que responder a muchas partes del documento de manera diferente. Con los
modelos push, su código debe mantener un estado adicional para saber dónde se encuentra y cómo
www.it-ebooks.info
Procesamiento de XML 521
reaccionar. Con un modelo de extracción, puede decidir qué partes del documento procesar en
cualquier punto dentro de su lógica comercial. El flujo a través del documento es más fácil de
seguir y el código se siente más natural.
Ahora hemos explorado la variedad de opciones de análisis disponibles en Groovy. A continuación,
exploramos las ventajas de las opciones de análisis específicas de Groovy con más detalle.
Figura 14.2 Comparación de las estrategias de ebullición versus calentamiento de flujo continuo
www.it-ebooks.info
522 CPASADO14Trabajando con XML y JSON
1 Convierta todos los valores de atributo de cadena en números cuando sea adecuado.
<html>
<cabeza>
<título>Actual maravilloso progreso</título>
<cuerpo>
<h1>Semana nº 0: en curso</h1> <dl>
www.it-ebooks.info
Procesamiento de XML 523
</dl>
</cuerpo>
</html>
donde la hoja de estilo style.css contiene la decisión de cómo se muestra finalmente una
tarea según su estado. Puede, por ejemplo, usar las siguientes líneas para ese propósito:
dt {fuente-peso:negrita}
dt.finished { font-weight:normal; decoración de texto: línea a través }
El listado 14.8 contiene la solución completa. losnumerarEl método implementa la conversión de cadena a
número para aquellos atributos que esperamos que sean de contenido entero. También muestra cómo
trabajar recursivamente a través del árbol de nodos.
Los métodosestado de la semanayestado de la tareahacer lo nuevoestadoatributo disponible en el nodo
correspondiente, dondeestado de la semanallamadasestado de la tareapara todas sus tareas contenidas
para asegurarse de que pueda trabajar en su estado dentro de las expresiones GPath.
El finalhtmlReportarEl método es la forma convencional de construir HTML. Gracias al
trabajo previo de "calentamiento", no se necesita lógica en el informe. El informe utiliza la
estadoatributo para asignar una hoja de estiloclasedel mismo valor.
importar Groovy.xml.MarkupBuilder
Convierte cadenas
a números
void numberfy(nodo nodo) {
def atts = node.attributes() atts.keySet().grep(['capacidad', 'total',
'hecho']).each {
atts[it] = atts[it].toInteger()
}
node.each { if (instancia de Nodo) numberfy(it) }
}
void taskStatus(tarea) {
Calcula y
def atts = task.attributes() switch asigna el estado de la tarea
(atts.done) {
caso 0: atts.status = 'programado'; descanso
caso 1..<atts.total: atts.status = 'en progreso'; romper por defecto:
atts.status = 'terminado';
}
}
Calcula y
estado de semana vacío (semana) { asigna semana
semana.atributos() atts.status =
'programado'
if (semana.tarea.cada { it.@status == 'terminado'})
atts.status = 'terminado'
if (semana.tarea.cualquiera { it.@status == 'en progreso'})
atts.status = 'en curso'
}
www.it-ebooks.info
524 CPASADO14Trabajando con XML y JSON
}
cuerpo {
plan.week.eachWithIndex { semana, i ->
h1("Número de semana $i: ${ semana.@estado }")
dl {
semana.tarea.cada { tarea ->
dt(clase: tarea.@estado , tarea.@título ) dd("(${ tarea.@hecho }/$
{ tarea.@total }): ${ tarea.@estado }")
}}}}}}
Después del cuidadoso trabajo previo, el código no sorprende. Lo que es un poco poco
convencional es tener muchas llaves de cierre en una línea al final dehtmlInforme.Esto no es solo
para la composición tipográfica compacta en el libro. A veces también usamos este estilo en
nuestro código cotidiano. Encontramos que revela muy bien qué niveles de sangría se deben cerrar
y aún nos permite verificar la coincidencia de llaves por columna. Sería genial tener soporte IDE
para alternar entre este y el diseño de código convencional.
Ahora que ha visto cómo usar la "caldera" en memoria, investiguemos el escenario
de transmisión.
Para demostrar el uso de la transmisión, comencemos con el tipo de procesamiento más simple
que se nos ocurra: bombear lo que entra sin ninguna modificación. Incluso este simple ejemplo
puede ser difícil de entender mientras el enfoque no sea familiar. Te recomendamos que si te
resulta confuso, sigas leyendo, pero no te preocupes demasiado por los detalles. Definitivamente
vale la pena volver más tarde para un segundo intento, aunque, en muchas situaciones, los
beneficios del procesamiento basado en secuencias bien valen el modelo conceptual más difícil.
www.it-ebooks.info
Procesamiento de XML 525
tuTUBERÍAS NO MODIFICADAS
Tu usasXmlSlurperpara analizar el XML original. Debido a que el formato de salida final es XML
nuevamente, necesita algún dispositivo que pueda generar XML en forma de transmisión. los
Groovy.xml.StreamingMarkupBuilderLa clase está especializada para generar marcado bajo
demanda, en otras palabras, cuando unsumidero de informaciónlo solicita Tal sumidero es una
operación que solicita unEscribible (por ejemplo, la llamada del operador de desplazamiento a la
izquierda en flujos o la evaluación de GStrings). el truco queStreamingMarkupBuilderutiliza para
lograr este efecto es similar al enfoque de los motores de plantilla.StreamingMarkupBuilder
provee ununirmétodo que devuelve unCierre Escribible.Este objeto es unescribible
y un cierre al mismo tiempo. porque es unescribible,puede usarlo donde se solicite el marcado final.
Debido a que es un cierre, la generación de este marcado se puede realizar de forma perezosa
sobre la marcha, sin almacenar resultados intermedios.
El listado 14.9 muestra esto en acción. losunirEl método también necesita la información
sobre qué lógica se va a aplicar para producir el marcado final. Donde sea que se necesite
lógica, los cierres son el primer candidato, y así es conunir.Pasamos un cierre a la
unirmétodo que describe la lógica de marcado.
Para nuestro ejemplo inicial de bombear elsenderoa través de, utilizamos una función especial de
StreamingMarkupBuilderque nos permite ceder la lógica de generación de marcado a un
construible,un objeto que sabe construirse a sí mismo. Sucede que unGPathResult
(y por lo tantosendero)es edificable. Para darle la lógica de construcción, usamos elrendir
método. Pero no podemos usarlo sin calificar porque produciríamos un <rendimiento/>marcado si lo hicimos. El
símbolo especialmkpmarca nuestra llamada de método como perteneciente al espacio de nombres de las
palabras clave de marcado.
importar Groovy.xml.StreamingMarkupBuilder
Están sucediendo muchas cosas aquí en solo unas pocas líneas de código. losresultadovariable, por
ejemplo, se refiere a un GString con un valor: una referencia acopiador.Tenga en cuenta que no lo
llamamos "copia" porque no es una cosa sino un actor.
Cuando llamamos a lacomienza conmétodo enresultado,se solicita la representación
de cadena de GString, y debido a que el valor de GStringcopiadores unescribible,su
escribir ase llama el método. loscopiadorfue construido por elconstructorde modo queescribir a
relés aruta.construir().
www.it-ebooks.info
526 CPASADO14Trabajando con XML y JSON
:Guion
XMLSlurper.parse(1) <<Construible>>
sendero:
GPathResult
crear constructor:
StreamingMarkup
Constructor
unir
crear <<Escribible>>
copiador
copiadora: Cierre
crear
resultado:GString
comienza con
escribir a
construir
www.it-ebooks.info
Procesamiento de XML 527
Para este ejemplo simple, podríamos haber usado los enfoques SAX o StAX que vio
anteriormente. Serían soluciones aún más simplificadas. No solo no necesitarían procesar y
almacenar las estructuras de datos en forma de árbol queXmlParsercrea para usted, pero
tampoco necesitarían almacenar la información del evento SAX. No ocurre lo mismo con los
escenarios más complicados que siguen. Como es común en muchos escenarios de
procesamiento de XML, los ejemplos restantes tienen requisitos de procesamiento que
abarcan varios elementos. Dichos escenarios se benefician enormemente de la capacidad de
utilizar expresiones GPathstyle.
HCOMER HASTAHTML
Hasta ahora, copiamos solo la entrada "fría". Es hora de encender nuestro calefactor. El objetivo es
producir la misma GUI que en la figura 14.3.
Comenzamos con los conceptos básicos del listado 14.9, pero mejoramos el cierre de marcado
que se une al constructor. En el listado 14.10, el edificio se ve casi igual que en el ejemplo
“hirviendo” del listado 14.7; sólo la evaluación de lasemanaytareahay que adaptar el estado. No
calculamos el estado por adelantado y lo almacenamos para referencia posterior, sino que
hacemos la clasificación sobre la marcha cuando el constructor lo solicita con pereza.
importar Groovy.xml.StreamingMarkupBuilder
Calcula
def taskStatus(tarea) { estado de la tarea
switch ( tarea.@done.toInteger ()) {
caso 0: devuelve 'programado'
caso 1..< tarea.@total.toInteger (): devuelve 'en progreso'
predeterminado: devuelve
'acabado'
}
}
Calcula
{
estado de la semana
semanaEstado(semana)
definitivamente
Marcado de cierre = {
Expresa el
html { procesamiento como
cabeza { un cierre
titulo('Actual maravilloso Progreso')
}
cuerpo {
plan.week.eachWithIndex { semana, i ->
h1("Semana No. $i: ${propietario.weekStatus(week)}")
www.it-ebooks.info
528 CPASADO14Trabajando con XML y JSON
dl{
semana.tarea.cada { tarea ->
def status = propietario.taskStatus(tarea)
Enlaces analizados
dt(clase: status, task.@title ) dd("($
XML a
{ task.@done }/${ task.@total }): $estado")
lógica de procesamiento
}}}}}}
Lo bueno aquí es que a primera vista parece similar a la lista 14.8, pero funciona de manera
muy diferente:
- Toda evaluación se hace con pereza.
Esto le permite producir una gran cantidad de resultados, ya que no se ensamblan en la memoria, sino
que se transmiten directamente a la salida según lo exige la lógica de construcción. Pero debido al
almacenamiento de información de eventos SAX en la entrada, este enfoque no permitirá documentos de
entrada tan grandes como sería posible con SAX o StAX.
La figura 14.5 esboza las diferencias entre ambos enfoques de procesamiento con
respecto a los requisitos de procesamiento y el uso de la memoria. El proceso va de izquierda
a derecha, ya sea en la fila superior (para "hervir") o en la fila inferior (para transmisión).
Ambos procesos abarcananalizando,evaluando,edificio, yserializandoa HTML, donde
evaluandoyedificiono están necesariamente en secuencia estricta. Aquí también es donde
están las diferencias: trabajar sobre estructuras de datos intermedias (árboles de listas y
nodos) o sobre objetos ligeros que encapsulan lógica (iteradores y cierres).
Liza Nodos
Hirviendo
iteradores
Lógica
Transmisión
Figura 14.5 Características del uso de la memoria para las estrategias de "ebullición" versus transmisión
www.it-ebooks.info
Procesamiento de XML 529
Eso es todo lo básico para leer XML y transformar XML en estructuras de datos
completamente nuevas. Pero a veces desea actualizar solo una parte de un documento XML.
Groovy también tiene soporte para ese tipo de operación.
Suponga que ahora desea actualizar su almacén de datos XML mediante programación. Ha
llegado al final de la primera semana en sus actividades planificadas. Desea actualizar la
primera semana para registrar su progreso total en la tercera tarea y proporcionar un
pequeño comentario. Para la segunda semana has revisado tus prioridades. Ya no desea
realizar la segunda tarea actual y, en su lugar, desea realizar dos alternativas.
Consideremos esto como una oportunidad para ejercitar el desarrollo de prueba primero y
escribir un asistente de prueba primero para reflejar cómo espera que se vea el XML al finalizar la
actualización.
Durante la primera semana (recuerde que es índice0)esperas que las horas hechas sean
iguales a las horas en total (es decir, siete horas) y esperas que el comentario 'ahorrador de
tiempo'aparecerá para una de las tareas (la última, pero no prescribiremos en exceso el orden
entre las tareas).
Para la segunda semana (índice1)esperas que la semana tenga tres tareas. Espera que la
tarea anterior se haya ido (sin @títulocoincidirá con el valor anterior) y se deben encontrar
dos tareas nuevas: verificaremos el @títulode uno y el @totaldel otro. Nuestro código de
prueba podría verse así:
clase UpdateChecker {
control estático (texto) {
def actualizado = nuevo XmlParser().parseText(texto)
actualizado.semana[0].with { w0 ->
afirmar w0.tarea.@hecho *.toInteger().sum() == 7 afirmar
w0.find{ it.text() == 'ahorro de tiempo' }
}
actualizado.semana[1].con { w1 ->
afirmar w1.niños().tamaño() == 3 afirmar
w1.buscar{ it.@total == "4" }
afirmar w1.find{ it.@title == "construir cliente de servicio web" } afirmar !
w1.find{ it.@title == "usar combinación DB/XML" }
}
}
}
estas usandoXmlParseren su cheque, pero como ha visto anteriormente, podría haber elegido
XmlSlurpero usadoDOMCategoríasi lo prefieres Algo más que vale la pena señalar aquí es que su
verificación supone que su XML actualizado se vuelve a escribir como texto listo para ser analizado
por su código de prueba. ParaXmlParseryDOMCategoría,podría haber hecho fácilmente algunas
afirmaciones en el árbol de nodos en memoria, pero siga con su enfoque anterior, ya que también
funciona paraXmlSlurper (hace actualizaciones perezosas) y también muestra el proceso de extremo
a extremo para escribir XML después de una actualización.
Ahora considere la siguiente lista, que muestra laDOMCategoríacódigo necesario para
actualizar el XML.
www.it-ebooks.info
530 CPASADO14Trabajando con XML y JSON
importar maravilloso.xml.DOMBuilder
importar maravilloso.xml.XmlUtil
importar Groovy.xml.dom.DOMCategory
UpdateChecker.check(XmlUtil.serialize(plan))
Establecemos el nuevo valor del atributo usando Groovy'sponlo enAtajo de sintaxis de GPathB. El valor de
texto del nodo se establece mediante elvalorpropiedadC. Entonces usamosreemplazarNodoy
más (usando la abreviatura +) para modificar los nodos de la tarea.
Hay varias otras formas en que podría haber actualizado el XML. Elegimos un
enfoque que ilustraba dos de las operaciones más comunes que se usan típicamente
(reemplazarNodoymás)pero, si hubiéramos querido, podríamos tener:
- UsóreemplazarNodouna vez pero con dos entradas de nodo de tarea dentro
- UsóappendNodeen lugar de más, proporcionándole el nuevo nombre de nodo y atributos
como un mapa
- Eliminó el nodo original usando elremoveChildmétodo y luego tuvo unmás
cierre con dos nudos o dosappendNodellamadas a métodos
importar Groovy.xml.XmlUtil
plan.semana[1].tarea[1].replaceNode {
tarea (hecho: '0', total: '4', título: 'construir servicio web')
}
plan.semana[1].tarea[1] + {
tarea (hecho: '0', total: '1', título: 'construir cliente de servicio web')
}
UpdateChecker.check(XmlUtil.serialize(plan))
www.it-ebooks.info
Procesamiento de XML 531
importar Groovy.xml.XmlUtil
plan.semana[1].tarea[1].replaceNode {
tarea (hecho: '0', total: '4', título: 'construir servicio web')
}
plan.semana[1].tarea[1] + {
tarea (hecho: '0', total: '1', título: 'construir cliente de servicio web')
}
UpdateChecker.check(XmlUtil.serialize(plan))
Lo primero que debe tener en cuenta es que se requieren nuevamente expresiones GPath idénticas para
las operaciones de actualización. También podrías haber usadoagregar nodo (aunqueXmlSlurper's
sintaxis paraappendNodevaría ligeramente, tomando unCierreparámetro comomáslo hace). También
podrías haber usado elShift izquierdo (atajo de sintaxis <<) para agregar nodos al nodo principal,
ahorrando solo un poco de escritura.
Otra cosa a tener en cuenta es que con elXmlSlurper,el comportamiento de transmisión
adicional está en juego. Cuando llamas alreemplazarNodoymásmétodos,XmlSlurperen realidad
no altera las estructuras de datos subyacentes que representan el árbol original; en su lugar,
guarda los cambios deseados que se aplicarán cuando envíe el documento XML a alguna
secuencia. En este caso, es cuando serializas el plan para su posterior verificación con tu
verificador.
En la sección 14.1.1, vio que los analizadores DOM clásicos de Java devuelven objetos de tipo
org.w3c.dom.Nodo,que difiere de lo que devuelven los analizadores Groovy. Al usar Java para
procesar tales nodos, las API de bajo nivel que ha visto hasta ahora pueden ser un poco
engorrosas. Si bien Java no tiene nada parecido a las expresiones GPath que ha visto para
Groovy, permite usar un enfoque de nivel ligeramente superior con la ayuda de XPath. La
siguiente sección muestra cómo se puede usar el procesamiento Java XPath y Groovy XML en
combinación.
www.it-ebooks.info
532 CPASADO14Trabajando con XML y JSON
tuENTENDERXPATH
Un XPath es una expresión que aparece en Java o Groovy como una cadena (exactamente como lo hacen los
patrones regex o las declaraciones SQL). Una introducción completa a XPath está más allá del alcance de este
libro, pero aquí hay una breve introducción desde el punto de vista de un programador de Groovy.6
Al igual que un GPath, un XPath selecciona nodos. Donde GPath usa puntos, XPath usa barras.
Por ejemplo,
/plan/semana/tarea
selecciona todotareanodos de todossemanas abajoplan.La barra diagonal inicial indica que la selección
comienza en el elemento raíz. En esta expresión,plan de semana,ytareacada uno se llama unprueba de
nodo. Cada prueba de nodo puede ir precedida de unaespecificador de ejede la tabla 14.7 y dos puntos
dobles.
/descendiente-o-yo::tarea
Con la sintaxis de acceso directo, puede seleccionar todototalnodos de atributos de todostareas vía
//tarea/@total
6
Para obtener una descripción completa del estándar, consulte www.w3.org/TR/xpath; y para un tutorial, visite
www.w3schools.com/xpath/. Para un buen libro, verXSLT 2.0 y XPath 2.0, 4ª edición, por Michael Kay (Wiley, 2008).
www.it-ebooks.info
Procesamiento de XML 533
Una prueba de nodo puede tener un finalpredicadoentre corchetes para restringir el resultado. Un
predicado es una expresión formada por expresiones de ruta, funciones y operadores para los
tipos de datosconjunto de nodos, cadena, número,ybooleanoLa tabla 14.8 enumera lo que es posible.
7 La tabla 14.9 muestra ejemplos.
Funciones de cadena concat(), substring(), contains(), substring- Consulte los documentos para conocer
7Estos operadores están disponibles en XPath 1.0 y XPath 2.0 a menos que se indique lo contrario.
www.it-ebooks.info
534 CPASADO14Trabajando con XML y JSON
La siguiente pregunta obvia es cómo usar tales expresiones XPath en código Groovy.
tuCANTA ELXPATHAPI
Groovy viene con todo el soporte que necesita para usar expresiones XPath en su código,
basándose en Java.fábricamétodo para acceder a la biblioteca XPath de forma independiente de la
plataforma. Utilizar eljavax.xml.xpath.XPathFactoryclase para crear una instancia de unxpathobjeto.
Luego, este objeto tiene métodos disponibles para evaluar expresiones XPath en su XML analizado
(o cuando la eficiencia es una preocupación importante, podemos compilar expresiones XPath para
una evaluación posterior).
En la práctica, es posible que desee hacer algo con todossemanas. Usted seleccionará la apro-
lista privada de nodos a través dexpath.evaluate('//week', plan, NODESET).El último parámetro
ter indica el tipo de retorno esperado. En su caso, desea un agregado de nodos. Porque esto
devuelve unlista de nodos,puede usar los métodos de iteración de objetos para obtener cada
semana:
Para cada semana, imprima la suma de lostotalyhechoatributos con la ayuda de XPath. Cada
semananode se convierte en el nuevo nodo de contexto para la evaluación de XPath y el tipo de
retorno esperado esNÚMERO:
La siguiente lista reúne todo esto con una pequeña funcionalidad de informes que produce un
informe de texto para cada semana, indicando la capacidad, el total de horas planificadas y el
progreso en horas realizadas.
importar maravilloso.xml.DOMBuilder
importar Groovy.xml.dom.DOMCategory
importar javax.xml.xpath.XPathFactory
www.it-ebooks.info
Procesamiento de XML 535
recuperando
int total = xpath.evaluate('sum(tarea/@total)', wk, NUMBER) int done =
índice y xpath.evaluate('sum(tarea/@done)', wk, NUMBER) out << " planeado $total de $ utilizando XPath
valorC {sem.'@capacidad'}\n"
out << " hecho $hecho de $total"
Evaluación usando
}
Atributos DOM
}
directamente
afirmar out.toString() == ''' Semana
No. 0
planeado 7 de 8
hecho 6 de 7
Semana No. 1
planeado 4 de 8
hecho 0 de 4''''
XPath se usa de dos maneras aquí: la capacidad de consulta se usa para seleccionar todos lossemana
elementosBy luego los atributostotalyhechose extraen con laevaluar
métodoC. Mezclará y combinará formas de acceder a los atributos, utilizandoDOMCategoría
para acceder a lacapacidadatributo con elnodo.@nombreAtributo sintaxisd.
Un informe de texto de este tipo está bien para empezar, pero sin duda sería mejor mostrar el
progreso en un gráfico. La figura 14.6 sugiere una solución HTML. En una situación normal,
usaríamos colores en dicho informe, pero no serían visibles en la impresión de este libro. Por lo
tanto, usamos solo una representación de caja simple de los números.
Cada cuadro está hecho del borde de un estilodivisiónelemento. El estilo también
determina el ancho de cada cuadro.
Este tipo de tarea de producción de HTML
requiere un enfoque de plantillas, porque hay varios
patrones recurrentes para los fragmentos de HTML:
para los cuadros, para cada fila de atributos y para
cada semana. Usaremos motores de plantilla, GPath
y XPath en combinación para que esto suceda.
El listado 14.15 presenta la plantilla que
vamos a utilizar. Es una plantilla simple como
se presentó en la sección 12.4.2. Asume la
presencia de dos variables en el enlace: una
escala,que se necesita para hacer visibles los tamaños
de las cajas a partir de los valores de los atributos, y
semanas, que es una lista de mapas semanales. Cada
semana el mapa contiene las claves 'capacidad', 'total',y
'hecho'con valores enteros.
La plantilla reside en un archivo separado. Nos
gusta nombrar estos archivos con la palabramodeloen
el nombre y terminando en la extensión de archivo Figura 14.6 Captura de pantalla de un informe
habitual para el formato que producen. Por ejemplo, basado en HTML
www.it-ebooks.info
536 CPASADO14Trabajando con XML y JSON
<html>
<cabeza>
<título>Actual maravilloso progreso</título>
</cabeza>
<cuerpo>
<% semanas.eachWithIndex{ semana, i -> %>
<h1>Semana No.psi</h1> <espacio entre celdas de la
tabla="5" >
<tbody>
<% ['capacidad','total','hecho'].each{ attr -> %> <tr>
<td>$atributo</td>
<td>${semana[atributo]}</td>
<td>
<estilo div=
"borde: delgado sólido #000000; ancho:pssemana[atributo]*escala}píxeles">
</div>
</td>
</tr>
<% } // fin del atributo %> </tbody>
</tabla>
<% } // fin de semana %> </
body>
</html>
Esta plantilla parece un archivo JSP, pero no lo es. La lógica contenida se expresa en Groovy,
no en Java simple. En lugar de ser procesado por un motor JSP, será evaluado por Groovy's
SimpleTemplateEnginecomo se muestra en el listado 14.16. Usamos expresiones XPath para
preparar los valores para el enlace. Una aplicación especial de GPath entra en juego al
calcular el factor de escala.
Se requiere escalar para que la barra de capacidad más larga tenga una longitud de 200, por lo que
debemos encontrar la capacidad máxima para el cálculo. Debido a que ya hemos puesto estos valores en
el enlace, podemos usar un GPath para obtener una lista de ellos y jugar nuestros trucos GDK con él
(llamandomáx.).
Listado 14.16 Uso de XPath, GPath y plantillas en combinación para informes HTML
importar maravilloso.xml.DOMBuilder
importar Groovy.xml.dom.DOMCategory
importar groovy.text.SimpleTemplateEngine como STE
www.it-ebooks.info
Procesamiento de XML 537
El código no cambió drásticamente entre el informe de texto del listado 14.14 y el informe
HTML del listado 14.16. Pero el listado 14.16 proporciona una solución más general, porque
también podemos obtener un informe de texto simplemente cambiando la plantilla.
El tipo de transformación de XML a HTML que logramos con el listado 14.16 se aborda
clásicamente con XMLTransformación de hoja de estilo(XSLT), que es una tecnología
poderosa. Utiliza hojas de estilo en formato XML para describir un mapeo de transformación,
también usando XPath y plantillas. Sus medios lógicos son equivalentes a los de un lenguaje
de programación funcional.
Aunque XSLT es adecuado para mapear estructuras de árbol, a menudo nos resulta más fácil
usar el enfoque Groovy cuando la lógica es mínimamente compleja. XPath, plantillas, constructores
y el lenguaje Groovy forman una combinación única que permite soluciones elegantes y concisas.
Puede haber personas que puedan mirar cantidades significativas de XSLT durante más de unos
pocos minutos a la vez sin arriesgar su estabilidad mental, pero son pocos y distantes entre sí.
Usando las tecnologías que ha encontrado, puede aprovechar sus fortalezas para comprender
Groovy en lugar de usar un lenguaje diferente con un paradigma fundamentalmente diferente.
www.it-ebooks.info
538 CPASADO14Trabajando con XML y JSON
para que lo consideres. Ya hemos mencionado StAX y Jaxen. Aquí hay algunos más de
nuestros favoritos:8
- A pesar de queXmlParser, XmlSlurper,y, por supuesto, Java DOM y SAX deberían satisfacer la
mayoría de sus necesidades, siempre puede considerar JDOM, dom4j o XOM.
- Si necesita comparar dos fragmentos XML en busca de diferencias, considere XMLUnit.
- Si desea procesar XML usando XQuery, considere Saxon.
- Si necesita conservar su XML, considere JAXB o Stream.
- Si necesita hacer una transmisión de alto rendimiento, considere Nux.
Nuestra introducción a Groovy XML podría terminar en este punto, porque ha visto todos los
conceptos básicos de la manipulación de XML. Ahora debería poder escribir programas Groovy que
lean, procesen y escriban XML de forma básica. Necesitará documentación más detallada cuando
surja la necesidad de tratar problemas más avanzados, como espacios de nombres, entidades de
resolución y manejo de DTD de forma personalizada.
La sección final de este capítulo trata sobre una de las alternativas más
extendidas a XML: JSON.
{ "semanas": [
{
"capacidad": 8,
"Tareas": [
{"hecho": 2,"total": 2,
"título":"leer capítulo XML", {" "estado":"fácil"},
hecho": 3,"total": 3,
"título":"intente algunos informes","estado":"divertida"}, {"
hecho": 1,"total": 2,
"título":"usar en el proyecto actual"}
]
},
8
Hay más información disponible en http://xmlbeans.apache.org, http://saxon.sourceforge.net, http://dsd.lbl.gov,
http://xmlunit.sourceforge.net, http://xstream .codehaus.org y https://jaxb.java.net.
www.it-ebooks.info
Analizando y construyendo JSON 539
{
"capacidad": 8,
"Tareas": [
{"hecho": 0,"total": 1,"título":"volver a leer el capítulo de DB"}, {"hecho": 0,"
total": 3,"título":"usar combinación DB/XML"}
]
}
]}
Para este ejemplo, supondremos que nuestro archivo se llama plan.json en una carpeta de datos. Ahora echemos
un vistazo a la siguiente lista para ver cómo podemos analizarla.
importar groovy.json.JsonSlurper
Eso es tan fácil como podríamos esperar y sigue de cerca (pero no exactamente) lo que vimos
para XML. Notará que falta el concepto de atributos para JSON. Almacenamos dicha
información como una lista de propiedades.
La buena noticia es que, si bien los ejemplos fáciles como los que acabamos de ver son realmente fáciles, los casos
complicados también se manejan, principalmente cambiando entre implementaciones de análisis con características
ligeramente diferentes. La Tabla 14.10 muestra las implementaciones del analizador proporcionadas.
Implementación Descripción
Puede cambiar a uno de los otros analizadores al llamar al constructor de esta manera:
Consulte la documentación en línea de Groovy para obtener más detalles.9Eso es todo para analizar. ¿Qué pasa si
quiere ir por el otro lado y realmente crear algo de contenido JSON? Veamos eso a continuación.
www.it-ebooks.info
540 CPASADO14Trabajando con XML y JSON
importar groovy.json.JsonBuilder
def constructor = new JsonBuilder()
constructor.semanas {
capacidad '8'
Tareas(
[{
hecho '0'
total '4'
title 'construir servicio web' }, {
hecho '0'
suma '1'
título 'construir cliente de servicio web'
}]
)
}
afirmar constructor.toString() == '{"semanas":{"capacidad":"8","tareas":[' +
'{"hecho":"0","total":"4","title":"construir servicio web"},' + '{"hecho":"0","total":"1","
title":"construir cliente de servicio web"}' + ']}}'
Como ha visto antes con otros constructores, también podemos usar la lógica de codificación
entremezclada con nuestros métodos sintéticos cuando usamosJsonBuilder.Veamos de nuevo nuestro
ejemplo de factura de capítulos anteriores.10Puede generar JSON correspondiente a nuestra información
de factura anidada como se muestra en la siguiente lista.
importar groovy.json.JsonBuilder
bmétodo fingido
def constructor = nuevo JsonBuilder() puede tomar colección
constructor { y cierre
facturas(1..3) { día ->
fecha de la factura: "2015-01-0$día") {
recuento de elementos: día) { CEl cierre define
producto (nombre: 'ULC', dólar: 1499) JSON para cada
} artículo en colección
}
}
}
10Consulte la sección 7.5.1 para ver ejemplos de GPath y la sección 11.4 para ver ejemplos de constructores.
www.it-ebooks.info
Analizando y construyendo JSON 541
Hay soporte especial para el manejo de listas de estructuras similares a mapas. por ejemplo, nuestro
facturascontendrá una lista de tresfacturamapas, por lo que pasamos una colección (en este
caso, el rango1..3)afacturasBy también proporcionar un cierre para procesar cada artículo en
la colecciónC. En lugar de usar el normalEncadenar()método como el que usamos en el
listado 14.18, usaremos untoPrettyString()variantedque realiza sangrías y saltos de línea
apropiados para aclarar las relaciones de anidamiento en el resultado.
También hay un generador JSON de transmisión llamado (como puede suponer)StreamingJSON-
Builder.Consulte la documentación de la API de GroovyDoc para obtener más detalles.
La última clase JSON útil que veremos esSalida Json.Se utiliza para serializar objetos Groovy en
JSON. Maneja los tipos de datos más comunes y, lo que es más importante, también estructuras
anidadas de objetos y sus propias clases de dominio. Es una clase auxiliar con métodos de utilidad
estáticos. Contiene numerosostoJsonmétodos correspondientes a los diversos tipos de datos que
convierte y unbonitaImprimirmétodo. Usarlos es bastante sencillo, como se muestra para una
estructura de datos de atleta simple en la siguiente lista.
"baloncesto": {
"primero": "Miguel",
"ultimo": "Jordán"
},
"maratón": {
"primero": "Pablo",
"último": "Tergat"
}
}
'''.recortar()
www.it-ebooks.info
542 CPASADO14Trabajando con XML y JSON
nuevo JsonBuilder(atletas).toPrettyString()
14.4 Resumen
XML y JSON son temas tan importantes que no podemos tocar todas las bases en un libro
sobre Groovy. Hemos cubierto los aspectos más importantes con suficiente detalle para
proporcionar una buena base para la experimentación y la lectura adicional. Al superar los
límites con Groovy XML y JSON, probablemente encontrará temas que no se tratan en este
capítulo. No dude en consultar los recursos en línea.
En este punto, tiene una base sólida para comprender las diferentes formas de trabajar
con XML y JSON en Groovy.
El uso de los analizadores Java DOM familiares en Groovy le permite trabajar en el estándar
org.w3c.com.Nodoobjetos siempre que la situación lo requiera. Dichos nodos se pueden recuperar
de laDOMBuilder,convenientemente accesible con la ayuda deDOMCategoría, e investigado con
expresiones XPath. Groovy hace la vida más fácil con el DOM, pero no puede rectificar algunas de
las decisiones de diseño que dan sorpresas o implican trabajo extra sin ningún beneficio.
www.it-ebooks.info
interactuando
con servicios web
El servicio a los demás es el alquiler que pagas por tu habitación aquí en la tierra.
— Muhammad Alí
Desde los primeros días de las redes informáticas, hemos utilizado una gran cantidad de protocolos y
formatos de datos para permitir que las computadoras interactúen e intercambien información. Con la
popularidad y la ubicuidad de la World Wide Web, la gama de protocolos y formatos de datos se ha
consolidado para centrarse principalmente en HTTP, que implementa el modelo de solicitud y
respuesta que conoce de sus actividades de navegación diarias, y una pequeña cantidad de
notaciones de marcado (principalmente HTML, XML y JSON) como formato de intercambio de datos.
Estos son los comúnmente llamadosservicio webtecnologías y son el tema de este capítulo.
En un nivel simple, el intercambio de datos ocurre cada vez que navega por la web. Con la ayuda
de su navegador, Ud.solicituduna dirección URL El servidorrespondecon un documento HTML
543
www.it-ebooks.info
544 CPASADO15Interactuar con servicios web
Las soluciones de servicios web cubren un espectro de enfoques que van desde lo simple hasta lo que
algunos consideran extremadamente complejo. Quizás el enfoque más simple es usar el protocolo HTTP
sin estado para solicitar un recurso a través de una URL. Esta es la base de laTransferencia de estado
representacional(RESTO) arquitectura. Los términos REST y RESTful se utilizan a veces en
www.it-ebooks.info
Lectura de RSS y ATOM 545
un sentido muy estricto para los servicios web que siguen todos los principios propugnados en el Ph.D.
original. tesis1por Roy Fielding sobre el tema, pero los términos también se han utilizado más
ampliamente para referirse a cualquier mecanismo para exponer contenido en la web a través de simples
XML o JSON.
Uno de los primeros usos populares de la arquitectura REST en su forma más básica fue hacer que el
contenido de los blogs web estuviera disponible. Dos de los formatos más utilizados en esta área son
Sindicación Realmente Simple2(RSS) y ÁTOMO (RFC-4287).Comenzaremos nuestra exploración de los
servicios web observando estos formatos.
La siguiente extensión lógica del uso de una URL para solicitar un recurso es usar XML simple
incorporado dentro de una solicitud HTTP POST normal. Esto también se puede considerar como
una solución REST. Examinaremos varias API XML y JSON de esta naturaleza como parte de nuestro
recorrido REST.
Cuando el foco no está en el recurso remoto sino en desencadenar una operación en el sistema
remoto, elLlamada de procedimiento remoto XML(XML-RPC) se puede utilizar. XML-RPC usa HTTP pero
agrega contexto, lo que lo convierte en un protocolo con estado (a diferencia de REST).
El jabon3El protocolo amplía el concepto de XML-RPC para admitir no solo operaciones remotas, sino
incluso operaciones remotas.objetos. Las funciones empresariales de servicios web que se basan en SOAP
brindan otras funciones, como seguridad, transacciones y mensajería confiable, por nombrar algunas de
las muchas funciones avanzadas disponibles.
Ahora que se ha orientado, veamos cómo Groovy puede acceder a dos de los formatos de servicios
web más populares que se utilizan en la actualidad.
1
“Estilos arquitectónicos y diseño de arquitecturas de software basadas en red”, disponible en www.ics.uci.edu/
~fielding/pubs/dissertation/top.htm.
2
También llamadoResumen del sitio enriquecido(RSS 0.9x) oMarco de descripción de recursos(CDR)Resumen del sitio(RSS 1.0).
3
SOAP solía significarSimple Object Access Protocol, pero este significado se eliminó desde la versión 1.2, porque SOAP
hace más que acceder a objetos, y la palabrasimplefue cuestionable desde el principio.
www.it-ebooks.info
546 CPASADO15Interactuar con servicios web
La siguiente lista implementa este lector de noticias. Solicita el recurso web que contiene la noticia
en formato XML. Encuentra el recurso por su URL. Pasar la URL a laanalizar gramaticalmente
El método lo obtiene implícitamente de la web. El resto del código puede funcionar directamente
en el árbol de nodos usando expresiones GPath.
Por supuesto, para escribir dicho código, necesitamos saber qué elementos y atributos están
disponibles en el formato RSS. En el listado 15.1, asumimos que al menos la siguiente estructura
está disponible:
<rss...>
<canal>
...
<elemento>
<título>…</título>
<descripción>...</descripción>
<enlace>...</enlace>
...
www.it-ebooks.info
Uso de una API basada en REST 547
Una cosa nueva en el listado 15.2 es el uso de espacios de nombres XML. El formato ATOM hace uso de
espacios de nombres como este:
<feed xmlns="http://www.w3.org/2005/Átomo">
...
<entrada>
<title>Java.next: Los lenguajes de Java.next</title> . . .
Para atravesar nodos que están vinculados a espacios de nombres con expresiones GPath, nombres
calificados (QNombreobjetos) se utilizan.4AQNombreEl objeto se puede recuperar de unespacio de nombres
objeto solicitando la propiedad del nombre del elemento correspondiente. Para recopilar las
entradas que nos interesan utilizamosátomo.entrada.Para cada entrada buscamos posteriormente
suátomo.publicadofecha (truncando la información de tiempo), suátomo.resumen (imprimiendo una
estrella para cualquiera que mencione Groovy), y suátomo.título.
}
println resúmenes.join("\n")
Todo eso fue bastante fácil, ¿verdad? El próximo tema, REST, será más elaborado pero cubre un
área más amplia de aplicabilidad, porque es un enfoque más general.
4
XmlParseryXmlSlurperson conscientes del espacio de nombres de forma predeterminada, pero se pueden configurar para que no manejen
espacios de nombres si lo prefiere, aunque normalmente tendría más trabajo que hacer manualmente en ese caso.
5
Podríamos profundizar aquí y hablar sobre restricciones adicionales, pero lo mantendremos simple por ahora.
www.it-ebooks.info
548 CPASADO15Interactuar con servicios web
Ningún estándar vinculante describe la estructura del XML o JSON que se envía. Debe
consultar la documentación de cada servicio REST para averiguar qué información se
solicita y se proporciona. La documentación describirá los recursos disponibles, los
verbos admitidos, la estructura XML o JSON que esperan recibir (para operaciones que
consumen una carga útil) y el resultado que devuelven.
Como primer ejemplo, examinaremos los servicios REST para interactuar con los servicios de
The Apache Software Foundation.6JIRA7utilizado por Groovy para el seguimiento de problemas. La
documentación de estos servicios se puede encontrar en el sitio web de Atlassian en http://
docs.atlassian.com/jira/REST/latest/. Tiene alrededor de 40 recursos diferentes enumerados en la
API (algunos con subrecursos). Para cada recurso, se proporcionan los métodos admitidos. Para
nuestros propósitos, estamos interesados en el siguiente recurso (que nos permitirá consultar los
detalles sobre un tema de interés particular de JIRA8):
/rest/api/latest/issue/{issueIdOrKey}
Proporcionaremos una clase contenedora compatible con Groovy (clasejiraen el listado 15.3) en
torno a estas llamadas. De esa forma, si necesitamos cambiar el analizador JSON por uno XML, o
los detalles cambian sobre qué métodos y recursos debemos llamar, no afectará el código que usa
nuestra clase contenedora. Poner esto junto se puede ver en la siguiente lista.
6
El proyecto Groovy actualmente está alojado en la incubadora de Apache como parte del traslado a Apache Software Foundation.
Ver www.apache.org para más detalles.
7
El sistema de seguimiento de proyectos de Atlassian. Consulte www.atlassian.com/software/jira/overview para obtener más
8
información. Un buen aspecto de este recurso en particular es que para consultas simples, no se requiere autenticación.
www.it-ebooks.info
Uso de una API basada en REST 549
importar groovy.json.JsonSlurper
clase Jira {
def base = 'https://issues.apache.org/jira/rest/api/latest/issue/' def slurper = new
JsonSlurper()
def consulta(clave) {
def httpConnection = nueva URL (base + clave).openConnection() afirmar
httpConnection.responseCode == httpConnection.HTTP_OK
slurper.parse(httpConnection.inputStream.newReader())
}
}
Para este ejemplo simple, usando el JDKURLLa clase era relativamente simple e indolora, pero a medida
que crece la complejidad, este enfoque tiende a involucrar un poco de lógica repetitiva en la solución.
Podemos simplificar las cosas mediante el uso de una API de cliente REST dedicada. Usaremos
HTTPBuilder,9que proporciona unRESTClienteclase. Esta clase hace que elOBTENER, PUBLICAR,
y otros métodos HTTP fácilmente disponibles para nosotros y oculta los detalles subyacentes del
manejo de la conexión. Puede determinar automáticamente si se devuelve una respuesta JSON o
XML utilizando información MIME-TYPE en la respuesta y nos proporciona el slurper necesario sin
que tengamos que preocuparnos por los detalles. El resultado final es un código más limpio, como
se muestra en la siguiente lista.
@Grab('org.codehaus.groovy.modules.http-builder:http-builder:0.7.2') import
groovyx.net.http.RESTClient
9 Consulte https://github.com/jgritman/httpbuilder/wiki.
www.it-ebooks.info
550 CPASADO15Interactuar con servicios web
Veamos otro servicio web utilizado para encontrar la tasa de conversión entre dos monedas
monetarias. Está alojado en el popular portal de servicios web en www.webservicex.net/. Es muy
similar a nuestro ejemplo anterior, pero requiere parámetros de consulta y devuelve XML en lugar
de JSON. La URL base para este servicio es:
http://www.webservicex.net/CurrencyConvertor.asmx
La ruta y los parámetros de consulta para la conversión de dólares estadounidenses a euros son:
<url base>/ConversionRate?FromCurrency=USD&ToCurrency=EUR
<doble xmlns="http://www.webserviceX.NET/">0,882</doble>
El código HTTPBuilder para acceder a este servicio web se muestra en el siguiente listado.
@Grab('org.codehaus.groovy.modules.http-builder:http-builder:0.7.2') import
groovyx.net.http.RESTClient
0.882
@Grab('org.codehaus.groovy.modules.http-builder:http-builder:0.7.2') importar
groovyx.net.http.RESTClient
importar estático groovyx.net.http.ContentType.URLENC
www.it-ebooks.info
Uso de una API basada en REST 551
Los ejemplos hasta ahora son muy simples, pero un ejemplo más típico podría diferir en una de dos
formas:
1 Puede implicar una mayor complejidad. Puede tener muchos más parámetros de URL, involucrar
autenticación, involucrar JSON o XMLCORREOcargas útiles, etc. La biblioteca HTTP-Builder
proporciona generadores de marcado para admitir estos escenarios más complejos. Consulte la
documentación de la API para obtener más detalles.10
2 Puede ser una combinación que combine muchos otros servicios para brindar un
servicio más atractivo.
Habiendo dicho eso, ahora debería tener el conocimiento para abordar aplicaciones REST tan complejas,
incluso con solo las pocas herramientas pequeñas que le mostramos en esta sección.
Antes de dejar esta sección, debemos analizar brevemente el último estándar JAX-RS 2.0
(también conocido como JSR-339).11Las versiones anteriores de este estándar han sido parte del
mundo Java EE durante algún tiempo. Anotaciones JAX-RS como @OBTENER, @PONER, @Ruta,y
@QueryParamse agregan al código de implementación del lado del servidor. La biblioteca JAX-
RS se encarga de la asignación entre el punto final del protocolo HTTP y el código de
implementación. Parte del mapeo puede implicar la serialización entre los objetos de dominio
utilizados en el código de implementación y su representación como parámetros o como una
carga JSON o XML.
Obviamente, esta API libera al desarrollador de muchos detalles de bajo nivel, por lo que
definitivamente es de interés para los escritores de servicios de punto final, pero este es un capítulo que
se enfoca en escribir código de cliente de servicio web. ¿Por qué JAX-RS debería ser de interés? La buena
noticia es que a partir de la versión 2.0 de este estándar, ahora hay unAPI de cliente unificado. Además,
algunas de las implementaciones no requieren un contenedor Java EE y se pueden usar de forma
independiente con Java SE. Eso lo hace ideal para nuestras necesidades. Usaremos el cliente RESTEasy
(www.jboss.org/resteasy) de JBoss.
Cuando usa JAX-RS como cliente, usa una API fluida proporcionada por unConstructor de clientes
class para definir los detalles necesarios para que el constructor realice la solicitud HTTP adecuada
a su punto final de interés y comprenda la respuesta de retorno. La API tiene numerosos puntos de
extensión que le permiten atender tipos MIME personalizados o necesidades especiales de
serialización. Evitaremos usar esas partes de la API. Para nuestro ejemplo, es suficiente especificar
la URL de destino y nuestros parámetros de consulta y luego declarar que
10Consulte https://github.com/jgritman/httpbuilder/wiki.
11Consulte www.jcp.org/en/jsr/detail?id=339 para ver la especificación final.
www.it-ebooks.info
552 CPASADO15Interactuar con servicios web
quiere una cadena sin formato como tipo de respuesta. Procesaremos la respuesta nosotros
mismos con Groovy'sXmlSlurper.El código resultante se puede ver en el siguiente listado.
@Grab('org.jboss.resteasy:resteasy-client:3.0.10.Final') importar
javax.ws.rs.client.ClientBuilder
respuesta
. solicitud().get(Cadena)
def rate = new XmlSlurper().parseText(respuesta) asertar
rate.name() == 'doble'
println rate.text()
Especificar que queríamos una cadena sin procesar fue tan fácil como proporcionar laCuerdaclase al
método getB. Alternativamente, podríamos recuperar el objeto de respuesta HTTP o un objeto de
dominio que hayamos definido previamente usando anotaciones JAX-RS. Dicha clase estaría disponible si
hubiéramos utilizado JAX-RS para definir nuestro servicio.
También debemos señalar una buena característica de RESTEasy que actualmente no forma
parte del estándar JSR-339. Proporciona un método proxy que toma una clase de interfaz. La clase
de interfaz se anota de la misma manera que lo haría un punto final de servicio con las
convenciones JAX-RS normales, pero con esta técnica solo se atiende el mapeo del lado del cliente.
Esto es exactamente lo que queremos y el código resultante se muestra en la siguiente lista.
@Grab('org.jboss.resteasy:resteasy-client:3.0.10.Final') importar
javax.ws.rs.GET
importar javax.ws.rs.Path
importar javax.ws.rs.Produce
importar javax.ws.rs.QueryParam
importar javax.ws.rs.client.ClientBuilder
@Ruta("Tasa de conversión")
@Produce("aplicación/xml")
Cadena convert(@QueryParam("FromCurrency") Cadena de,
@QueryParam("ADivisa") Cadena a)
}
def cliente = ClientBuilder.nuevoCliente()
def base = "http://www.webservicex.net/CurrencyConvertor.asmx" def proxy =
client.target(base).proxy(CurrencyConvertor)
def respuesta = proxy.convert("USD", "EUR") def root = new
XmlSlurper().parseText(respuesta) afirmar root.name() == 'doble'
println root.text()
www.it-ebooks.info
Usando XML-RPC 553
Instalar un servidor que implemente elecola operación es igualmente fácil. Cree una instancia
de servidor y asigne un cierre a suecopropiedad:
servidor.eco= {devolverlo }
@Grab('org.codehaus.groovy:groovy-xmlrpc:0.8') importar
groovy.net.xmlrpc.XMLRPCServerProxy como proxy importar
groovy.net.xmlrpc.XMLRPCServer como servidor
www.it-ebooks.info
554 CPASADO15Interactuar con servicios web
servidor.pararServidor()
Tener el cliente y el servidor juntos es útil para fines de prueba, pero en producción, estas dos
partes generalmente se ejecutan en diferentes sistemas.
XML-RPC también define el manejo de errores, que en Groovy XML-RPC está disponible a través de
laXMLRPCCallFailureExceptioncon las propiedadescadena de fallasycódigo de fallo.
Las áreas de aplicación de XML-RPC son tan amplias que cualquier lista que pudiéramos hacer
estaría necesariamente incompleta. Se utiliza para leer y publicar en blogs, conectarse a sistemas
de mensajería instantánea (a través del protocolo Jabber para sistemas como GoogleTalk12),
fuentes de noticias, motores de búsqueda, servidores de integración continua, sistemas de
seguimiento de errores, etc.
Es atractivo porque es poderoso y simple al mismo tiempo. Veamos, por ejemplo,
información sobre los proyectos gestionados en Apache Software Foundation (ASF).13La ASF
proporciona la JIRA14sistema de seguimiento de errores para sus proyectos alojados.
La impresión de todos los nombres de proyectos se puede hacer fácilmente con el siguiente código:
Es convencional que las operaciones expuestas a través de XML-RPC tengan una notación de puntos como
jira1.login.El soporte XML-RPC de Groovy puede solucionarlo.
Pero si llama a muchos métodos, usando elremoto.jira1.prefijo se interpone en el camino de la
legibilidad. Sería mejor evitar eso. El listado 15.10 tiene una solución. Las llamadas a los métodos de proxy
siempre pueden cerrarse opcionalmente. Dentro de ese cierre, los nombres de los métodos se resuelven
contra el proxy. Extendemos este comportamiento con un especialistaJiraProxyque prefija las llamadas a
métodos conjira1.
12Vea el excelente artículo de Guillaume sobre cómo usar GoogleTalk a través de Groovy en http://glaforge.free.fr/
blog/index.php?itemid=142.
13El proyecto Groovy está alojado actualmente en la incubadora de Apache como parte del cambio al software Apache.
Base.
14Encuentre información sobre los métodos JIRA XML-RPC en http://confluence.atlassian.com/display/JIRA/
JIRA+XML-RPC+Resumen.
www.it-ebooks.info
Aplicación de SOAP 555
Para hacer las cosas un poco más interesantes esta vez, publicamos información sobre el
proyecto Groovy en el JIRA de ASF.
@Grab('org.codehaus.groovy:groovy-xmlrpc:0.8') importar
groovy.net.xmlrpc.XMLRPCServerProxy como proxy
esto imprime
Tenga en cuenta la simplicidad del código. A diferencia de REST, no necesita trabajar en nodos XML
o JSON, ni en la solicitud ni en la respuesta. Simplemente puede usar tipos de datos Groovy como
cadenas (usuario), listas (proyectos) y mapas (maravilloso). ¿Quién puede pedir más?
Valdría más la pena escribir un libro sobre XML-RPC y su módulo Groovy, especialmente
sobre la implementación del lado del servidor. Pero este libro tiene pocas páginas y debe
consultar la documentación en línea para obtener más detalles y escenarios de uso.
Ahora tiene la información básica para comenzar a trabajar con XML-RPC. ¡Por qué no
intentarlo ahora mismo! O bien, continúe con nuestro recorrido por todas las opciones de
procesamiento distribuido con una solución integral: SOAP.
www.it-ebooks.info
556 CPASADO15Interactuar con servicios web
proporciona medios para definir nuevos tipos de datos específicos del servicio. Otros marcos,
incluidos CORBA, DCOM y Java RMI, brindan una funcionalidad similar a la de SOAP, pero los
mensajes SOAP están escritos completamente en XML y, por lo tanto, son independientes de la
plataforma y el idioma. El enfoque general de SOAP es permitir que un servicio web describa su API
pública: dónde se encuentra, qué operaciones están disponibles y los formatos de solicitud y
respuesta (llamados mensajes). Un servicio SOAP hace que esta información esté disponible a
través del Lenguaje de definición de servicios web (WSDL).
SOAP ha sido ampliamente adoptado por la industria y hay numerosos servicios gratuitos disponibles, que
van desde tiendas en línea hasta datos financieros, mapas, música, sistemas de pago, subastas en línea,
seguimiento de pedidos, blogs, noticias, galerías de imágenes, servicios meteorológicos, validación de tarjetas de
crédito. -la lista es interminable.
Numerosos lenguajes de programación y plataformas brindan un excelente soporte para
SOAP. Las implementaciones populares de la pila SOAP en la plataforma Java incluyen Metro
(http://metro.java.net) y Apache CXF (http://cxf.apache.org/). El soporte SOAP incorporado
para Groovy es bastante básico, pero se usa con éxito para proyectos de producción.
Primero, exploraremos cómo puede usar SOAP con Groovy puro de una manera efectiva pero
concisa.
println doc[wsdl.portType][wsdl.operación].'@nombre'
15Para obtener consejos sobre cómo leer la descripción de un servicio WSDL, consulte www.w3.org/TR/wsdl.
www.it-ebooks.info
Aplicación de SOAP 557
SOAP usa algo llamado formato de sobre para la solicitud. Los detalles están más allá del
alcance de este capítulo. Vea las especificaciones para más detalles. Nuestro sobre se ve así:
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://
esquemas .xmlsoap.org/soap/envelope/"> <soap:Cuerpo>
<ConversionRate xmlns="http://www.webserviceX.NET/">
<FromCurrency>${from}</FromCurrency>
<ToCurrency>${to}</ToCurrency> </
ConversionRate>
</jabon:Cuerpo>
</jabon:Sobre>
Como puede ver en la notación ${}, este sobre es una plantilla que podemos usar con un
motor de plantillas Groovy.
El código del listado 15.12 lee esta plantilla, la llena con parámetros para la conversión de dólares
estadounidenses a euros y la agrega a unaCORREOsolicitud a la URL del servicio. La solicitud necesita
encabezados de solicitud adicionales, como elSOAPActionpara que el servidor lo entienda. Usamos
explícitamenteUTF-8codificación de caracteres para evitar problemas de codificación multiplataforma.
El servicio responde con un sobre de resultados SOAP. Sabemos que contiene un nodo llamado
Resultado de la tasa de conversiónperteneciente al espacio de nombres del servicio. Ubicamos el primer
nodo de este tipo en la respuesta y obtenemos la tasa de conversión como sutextovalor.
conn.requestMethod = 'CORREO'
conn.doSalida = verdadero
conn.outputStream << new ByteArrayInputStream(solicitud) if
envía el
(conn.responseCode != conn.HTTP_OK) { solicitud
println "Error - HTTP:${conn.responseCode}" devuelve
www.it-ebooks.info
558 CPASADO15Interactuar con servicios web
resp.
definitivamente =
XmlParser().parse(conn.inputStream) Espacio de
nuevo
Analiza el
servir
definitivamente =
nombres('http://www.webserviceX.NET/')
nuevo
respuesta
def resultado = serv.ConversionRateResult
Esto es sencillo en términos de cada paso individual, pero tomado como un todo, el código es
bastante engorroso. Un punto a tener en cuenta sobre la implementación está oculto al ubicar el
resultado en el sobre de respuesta. usamos elservirespacio de nombres y pídale su
Resultado de la tasa de conversiónpropiedad, que devuelve unQNombre.Lo asignamos a laresultado
variable y hacer uso del hecho de queQNombreimplementa eles igualmétodo con cadenas
para que encontremos el nodo adecuado.
SOAP es detallado en comparación con otros enfoques. Es detallado en el código que exige para su
ejecución y, lo que es más importante, es detallado en el formato de su mensaje. No es inusual que los
mensajes SOAP tengan 10 veces más marcado XML que el tamaño de la carga útil.
Pero el estándar SOAP permite brindar herramientas generales para lidiar con su
complejidad.
@Grab('org.codehaus.groovy.modules.http-builder:http-builder:0.7.2') importar
groovyx.net.http.RESTClient
importar estático groovyx.net.http.ContentType.XML
www.it-ebooks.info
Aplicación de SOAP 559
La mayor parte de esto debería parecer familiar a los ejemplos anteriores de análisis y compilación. HTTP-
Builder sabe cómo crear solicitudes XML y analizar respuestas XML. Utilizará esas capacidades y
proporcionará los elementos, atributos y espacios de nombres correctos que se esperan para una
interacción SOAP.
Quizás la primera parte complicada es que necesita registrar un analizador apropiadoB
(utilizando el 'aplicación/jabón+xml'tipo MIME) para la respuesta devuelta. Dado que la
respuesta SOAP se puede tratar como XML simple y antiguo, puede aprovechar ese
analizador. Además, aunque la solicitud SOAP es simplemente XML antiguo, el servidor SOAP
esperará un tipo de contenido SOAP, por lo que debe establecer un encabezado con el valor
que espera el servidor SOAP.C.
Nuestra implementación de HTTPBuilder es un gran paso adelante con respecto a la lista 15.12, pero
aún contiene bastante código repetitivo. Solo como un ejemplo, el sobre SOAP y los elementos del cuerpo
existirían para cada servicio SOAP. Nuestro próximo paso a considerar es una biblioteca dedicada
compatible con SOAP. Ese es el tema de la siguiente sección.
La biblioteca groovy-wslite conoce SOAP (y REST también si desea considerar una alternativa a
HTTPBuilder para REST). Utiliza un enfoque de estilo constructor que nos permite especificar la
carga útil de nuestro cuerpo SOAP, pero oculta muchos de los detalles asociados con la creación de
las solicitudes SOAP reales o el análisis de las respuestas SOAP. La siguiente lista muestra el código
resultante.
@Grab('com.github.groovy-wslite:groovy-wslite:1.1.0') importar
wslite.soap.SOAPClient
Ahora, eso es mucho más maravilloso! Esta solicitud SOAP en particular utilizará la versión predeterminada de
SOAP 1.1, pero podemos cambiar a SOAP 1.2 tan fácilmente como se puede ver en la siguiente lista.
www.it-ebooks.info
560 CPASADO15Interactuar con servicios web
@Grab('com.github.groovy-wslite:groovy-wslite:1.1.0') importar
wslite.soap.*
Aquí necesitamos establecer explícitamente la versión que requerimos, pero podemos eliminar elSOAPAction
información ya que no es necesaria para SOAP 1.2.
Esperamos que haya disfrutado de nuestro viaje a través de la variedad de tecnologías de clientes de
servicios web. Debe tener suficiente información para crear una amplia variedad de clientes de servicios
web.
15.6 Resumen
Los servicios web son un tema tan amplio que posiblemente no podamos tocar todas las bases en un libro
introductorio sobre Groovy, pero ha visto los aspectos más importantes con suficiente detalle para tener
una buena base para la experimentación y la lectura adicional.
Se ha vuelto cada vez más popular construir arquitecturas de aplicaciones completas en torno a
servicios pequeños, dedicados y débilmente acoplados que cooperan mediante el uso de la mecánica que
hemos mencionado en este capítulo. Se llaman microservicios.
Pueden vivir en su propio pequeño contenedor que incluso puede contener su sistema
operativo privado. Cada uno puede tener su propia forma de exponer su servicio siempre y cuando
cumpla con los estándares web. Pueden ejecutarse en servidores Java Enterprise completos, Spring
Boot, Grails, Groovy + Jetty como en la sección 12.5, o algo tan pequeño y liviano como Ratpack
(www.ratpack.io).
No está claro si esta tendencia continuará, pero de cualquier manera, su conocimiento del
soporte de servicios web de Groovy le permite implementar arquitecturas convencionales tan bien
como las más recientes.caderaarquitecturas
Como ha visto, es fácil enviar XML y JSON alrededor del mundo para hacer que las
computadoras en red trabajen juntas, compartiendo información y poder de cómputo. XML-RPC y
SOAP tienen soporte en las bibliotecas de Groovy, aunque es probable que ese soporte cambie
significativamente con el tiempo. REST no puede beneficiarse de este soporte tan fácilmente (ni
siquiera en el mundo dinámico de Groovy) debido a la falta de estandarización, pero ha visto cómo
el uso de constructores puede simplificar el desarrollo de una API para un servicio REST específico. .
www.it-ebooks.info
Integrando Groovy
Una de las mayores ventajas de Groovy (incluso una de las razones de su creación) es que se
integra de forma nativa con Java porque ambos lenguajes se ejecutan en la misma plataforma y,
en su mayor parte, comparten las mismas estructuras de datos de uso común, como listas y
mapas. Es importante comprender qué hace que Groovy sea una opción tan atractiva cuando
necesita incrustar un lenguaje de secuencias de comandos en su aplicación.
Desde una perspectiva corporativa, tiene sentido construir sobre la misma plataforma en la que ya
se están ejecutando la mayoría de sus proyectos. Esto protege la inversión en habilidades, experiencia
y tecnología, mitigando el riesgo y, por lo tanto, los costos.
561
www.it-ebooks.info
562 CPASADOdieciséisIntegrando Groovy
Donde Java no encaja perfectamente como lenguaje, las características de expresividad, brevedad y potencia
de Groovy pueden ser más apropiadas. Por el contrario, cuando Groovy se queda corto debido a la inevitable
compensación entre agilidad y velocidad, el código crítico para el rendimiento se puede reemplazar con Java sin
procesar.1Estas decisiones de equilibrio pueden tomarse temprano o tarde con pocas repercusiones debido a los
estrechos vínculos entre los dos idiomas. Groovy proporciona un mecanismo de integración transparente que
permite una mezcla y combinación uno a uno de las clases de Java y Groovy. Este no siempre es el caso con otras
soluciones de secuencias de comandos, algunas de las cuales solo proporcionan contenedores o proxies que
rompen el contrato de jerarquía de objetos.
1
Pero asegúrese de leer sobre @CompileStaticen el capítulo 10, que le da a gran parte de su código Groovy una velocidad similar a la
de Java.
www.it-ebooks.info
Preludio a la integración 563
Por otro lado, suponga que está creando un procesador de textos avanzado, una aplicación de hoja
de cálculo o un módulo complejo de cálculo de riesgos para un paquete de software bancario aún más
complicado que tuvo que evolucionar rápidamente para seguir los rápidos cambios del mercado, la
legislación o nuevas reglas de negocio. Estas aplicaciones pueden necesitar un punto de extensión donde
los usuarios finales puedan personalizarlas para satisfacer sus necesidades. La figura 16.1 muestra un
ejemplo de dónde podría integrar Groovy.
Por ejemplo, la aplicación bancaria puede requerir la definición de reglas comerciales en un
script que podría definirse en tiempo de ejecución sin requerir una nueva y tediosa fase de
desarrollo/prueba/calificación, lo que reduce el tiempo de comercialización y aumenta la capacidad
de respuesta a los cambios en las prácticas financieras. Otro ejemplo podría ser un conjunto de
aplicaciones ofimáticas que ofrece un sistema de macros para crear funciones reutilizables que se
pueden invocar con una pulsación de tecla. Se vuelve obvio que una dicotomía del mundo del
software diferencia las aplicaciones monolíticas, que no necesitan evolucionar con el tiempo y
tienen un alcance funcional fijo, de las aplicaciones más fluidas, cuya lógica puede extenderse o
modificarse durante su vida útil para adaptarse a los cambios de contexto.
Antes de considerar usar Groovy en su aplicación, analice si necesita personalizarlo y
vea si desea personalizar, ampliar o modificar la lógica, y no solo parámetros simples. Si
la parametrización satisface sus necesidades, es mejor que utilice mecanismos de
configuración clásicos, como una interfaz web de administración a través de un
conjunto de servicios web; o, para un seguimiento y una acción más avanzados
Captura
Capa de interfaz de usuario
maravilloso
código
Evaluar
capa empresarial Figura 16.1 Un ejemplo de un
solución de integración. El usuario ingresa
GroovyShell el código Groovy en la capa de la interfaz
capa de datos de usuario y luego lo ejecuta en la capa
empresarial.
www.it-ebooks.info
564 CPASADOdieciséisIntegrando Groovy
2
Extensiones de gestión de Java; consulte www.oracle.com/technetwork/java/javase/tech/javamanagement-140525. html
3
Por supuesto, no deseamos desanimarlo de leer el capítulo incluso si no tiene ninguna necesidad de integración en este
momento. Obtener conocimiento es una búsqueda digna en sí misma.
4
El número puede ser diferente si está utilizando una versión diferente.
www.it-ebooks.info
Evaluación de expresiones y scripts con GroovyShell 565
No son solo las aplicaciones Java las que pueden beneficiarse de la disponibilidad de un motor de
secuencias de comandos: ¡incluso puede integrar secuencias de comandos y expresiones Groovy
personalizadas desde una aplicación escrita en Groovy! Mientras explicamos los diversos mecanismos de
incrustación, le mostraremos cómo se pueden explotar los intérpretes y cargadores de clases de Groovy
desde ambos lados de la valla lingüística. Ahora que hemos configurado nuestro entorno, podemos ver la
primera de nuestras tres formas de integración directa con Groovy:GroovyShell.
El requisito de integración más simple imaginable evalúa una expresión. Por ejemplo, algunas
aplicaciones matemáticas pueden requerir que los usuarios ingresen expresiones arbitrarias en un
campo de entrada de formulario que no se puede configurar en el momento del desarrollo en una
función o un cierre (por ejemplo, una aplicación de hoja de cálculo donde las fórmulas son
expresiones Groovy). Esas aplicaciones luego le piden al tiempo de ejecución que calcule la fórmula
ingresada. En tales situaciones, la herramienta elegida para evaluar expresiones y guiones es el
GroovyShellclase. El uso de esta clase es sencillo y es similar si la usa desde Java o desde Groovy. Se
puede implementar un evaluador de expresiones simple usandoGroovyShellcomo se muestra en el
siguiente listado.5
5
Quizás se pregunte por qué elegimos integrar Groovy a Groovy. Bueno, es más probable que lo hagamos desde Java, pero usar Groovy simplifica nuestros
ejemplos. Hacerlo puede ser útil incluso desde Groovy, de modo que pueda organizar el código de la utilidad en secuencias de comandos externas,
ejecutar secuencias de comandos con ciertas políticas de seguridad o ejecutar entradas proporcionadas por el usuario en tiempo de ejecución.
www.it-ebooks.info
566 CPASADOdieciséisIntegrando Groovy
El programa Java completo equivalente es naturalmente un poco más largo debido al código de
andamiaje y las importaciones requeridas, pero la lógica central es exactamente la misma. La siguiente
lista proporciona el código Java completo requerido para realizar la evaluación, aunque sin manejo de
errores. Los ejemplos de Java más adelante en el capítulo se han reducido a solo el código involucrado en
la integración. Las importaciones generalmente se muestran solo cuando no están claras en el contexto.
Listado 16.2 Ejemplo trivial del listado 16.1, esta vez en Java
//Java
importar Groovy.lang.GroovyShell;
Puede evaluar expresiones provenientes de un archivo, un lector, una cadena o un URI. También
hay algunas variantes que no mostramos que toman un parámetro de nombre de archivo adicional
que se usa para especificar el nombre de la clase que se creará al evaluar el script, porque Groovy
siempre genera clases para los scripts también.
6
rara vezbastantetan fácil como el equivalente de Groovy, pero a estas alturas deberías darte cuenta de que esto no tiene nada que ver con las
características que se muestran y todo que ver con que Groovy haga la vida más fácil en general.
www.it-ebooks.info
Evaluación de expresiones y scripts con GroovyShell 567
Desde los scripts Groovy, se puede usar un atajo: los scripts son clases que extienden el
Guionclase, que ya tiene unaevaluarmétodo. En el contexto de un script, nuestro
ejemplo anterior se puede acortar a lo siguiente:
El parámetro de cadena pasado aevaluarpuede ser un script completo con varias líneas de código,
no solo una expresión simple, como puede ver en la siguiente lista.
losyoEl método se utiliza cuando no se requieren parámetros. Los otros métodos se utilizan
para uno, dos y tres parámetros, donde el primer, segundo y tercer parámetro están
disponibles comox, y,yz,respectivamente. Esto es útil cuando su única necesidad es evaluar
expresiones simples o incluso funciones matemáticas. A continuación, verá cómo puede ir
más allá con la parametrización de la evaluación de scripts conGroovyShell.
www.it-ebooks.info
568 CPASADOdieciséis Integrando Groovy
Listado 16.5 Hacer que los datos estén disponibles para unGroovyShellusando unUnión
En este ejemplo, creamos una instancia de enlace a la que agregamos dos parámetros,Xy
y,pasando un mapa a laUniónconstructorB. Nuestro script evaluado crea dos nuevas
variables en el enlace asignando un valor a variables no definidas:xCuadrado
yyCuboC. Podemos recuperar los valores de estas variables conobtenerVariablede Java y
Groovyd, o podemos usar el acceso similar a una propiedad de Groovymi.
www.it-ebooks.info
Evaluación de expresiones y scripts con GroovyShell 569
Se puede poner o recuperar cualquier cosa del enlace, y solo se puede devolver un valor de
retorno como evaluación de la última instrucción del script. El enlace es la mejor manera de
pasar sus objetos de dominio o instancias de sesiones o transacciones predefinidas o
rellenadas previamente a sus scripts. Examinemos una forma más creativa de devolver un
valor de la evaluación de su script.
Usandoevaluartambién puede ser útil para generar nuevas clases dinámicas sobre la marcha. Por
ejemplo, es posible que necesite generar clases para un servicio web en tiempo de ejecución,
basándose en elementos XML del WSDL para el servicio. En la siguiente lista se muestra un ejemplo
artificial para evaluar y devolver una clase ficticia.
En todos los ejemplos que has visto hasta ahora, hemos usado elevaluarmétodo, que compila y
ejecuta un script de una sola vez. Eso está bien para evaluaciones únicas, pero otras situaciones se
benefician al separar la compilación (análisis) de la ejecución, como verá a continuación.
www.it-ebooks.info
570 CPASADOdieciséisIntegrando Groovy
otra vez. (Recuerde nuestroConstructor de columpiotrazador del capítulo 11.) Este método es similar
aevaluar,tomando el mismo conjunto de argumentos; pero en lugar de ejecutar el código, genera
una instancia delGuionclase. Todos los scripts que puede escribir son siempre instancias
deGuion.
Tomemos un ejemplo concreto. Supongamos que dirigimos un banco y tenemos clientes que
piden un préstamo para comprar una casa. Necesitamos calcular el monto mensual que tendrán
que pagar, sabiendo el monto total del préstamo, la tasa de interés y la cantidad de meses para
pagar el préstamo. Pero, por supuesto, queremos reutilizar esta fórmula y la almacenaremos en
una base de datos o en otro lugar del sistema de archivos en caso de que la fórmula evolucione en
el futuro.
Supongamos que las variables del algoritmo son las siguientes:
Con estas variables, queremos calcular el pago mensual. La secuencia de comandos en la siguiente
lista muestra cómo podemos reutilizar la fórmula para calcular esta cifra importante.
Analiza la fórmula en
def shell = nuevo GroovyShell() def script =
guión reutilizable Accesos
shell.parse(mensual)
Unión
variable
script.enlace.cantidad = 154000
guión.tasa = 3.75/100
Enlace de accesos
script.númeroDeMeses = 240 variable usando
taquigrafía
afirmar script.run() == 913.0480050387338
www.it-ebooks.info
Evaluación de expresiones y scripts con GroovyShell 571
Pero existen otras variantes que leen el script desde una URI o toman los parámetros como una
lista en lugar de una matriz. Consulte el GroovyDoc paraGroovyShellpara más detalles.
la ejecución decorreres un poco diferente a la deevaluar. evaluarevalúa solo scripts, pero
corrertambién puede ejecutar clases con unprincipalmétodos y pruebas unitarias. Se aplican
las siguientes reglas:
- Si la clase a ejecutar tiene unmain(Objeto[] argumentos)oprincipal(Cadena[] argumentos)método,
se ejecutará. Tenga en cuenta que un script es una clase Java normal que implementaEjecutable
y escorrermétodo es llamado por un implícitoprincipalmétodo.
- Si la clase se extiendeGroovyTestCasoo es una prueba JUnit, entonces un corredor de prueba
JUnit la ejecuta.
- Si la clase implementaejecutable,se instancia con un constructor tomando un
Cuerdamatriz, o un constructor predeterminado, y la clase se ejecuta con sucorrermétodo.
El mecanismo del corredor también es extensible, por lo que módulos como el módulo groovy-testng
definen su propio corredor.
GroovyShell()
GroovyShell(Binding vinculante)
GroovyShell(CompilerConfiguration configuración)
www.it-ebooks.info
572 CPASADOdieciséisIntegrando Groovy
Cargador de clases A
Padre Padre
Mientras usa elUniónes fácil y autodescriptivo, entendiendo cómo Groovy maneja los
cargadores de clases, en particular cuando crea una instanciaGroovyShellcomo aquí, es muy
importante. Podría terminar creando una pérdida de memoria sin una comprensión
adecuada de la mecánica.
Cargador de clases A
Padre
Cargador de clases B
Padre
Cargador de clases C
Figura 16.3 Lineal
estructura del cargador de clases
www.it-ebooks.info
Evaluación de expresiones y scripts con GroovyShell 573
clases para todas las clases afectadas e imprimir el cargador de clases principal de cada cargador de clases, y así
sucesivamente hasta la raíz de todos los cargadores de clases. Entonces tendrá una buena imagen de toda la
jerarquía de cargadores de clases en su aplicación, y el paso final será configurar los cargadores de clases
principales en consecuencia para aplanar la jerarquía. Aún mejor, intente hacer que las clases sean cargadas por
los mismos cargadores de clases si es posible.
CCONFIGURAR LA COMPILACIÓN
En la lista de constructores de laGroovyShellclase, habrás notado laConfiguración del
compiladorparámetro. Una instancia de esta clase se puede pasar aGroovyShellpara
personalizar las opciones del proceso de compilación.
Sin estudiar todas las opciones disponibles, repasemos algunas de las más útiles, como
se muestra en la tabla 16.1. Algunas funciones más se tratan en la sección 16.7.
setRecompileGroovySource Ajustado averdaderopara volver a cargar las fuentes de Groovy que han
www.it-ebooks.info
574 CPASADOdieciséisIntegrando Groovy
guion baseextiendeGuion,que es una clase abstracta, por lo que la clase debe declararse
abstracta, porque elcorrerEl método es abstracto. Al compilar o interpretar scripts,
Groovy ampliará este script base e inyectará las declaraciones del script en elcorrer
método.
Para hacer de esta clase la clase base de sus scripts, ahora necesita pasar unorg.code-
haus.groovy.control.CompilerConfigurationinstancia aGroovyShell's construcción-
tor, como se explica en el siguiente ejemplo de Groovy:
Esta no es la única forma de inyectar funciones en todos sus scripts. Otro truco para
compartir funciones entre scripts es almacenar cierres en el enlace deGroovyShellsin
necesidad de usarConfiguración del compilador.Esto se puede ver en el siguiente listado.
También debe poder escribir el mismo código en Java, por lo que debemos poder crear
cierres y ponerlos en el enlace. Desde Java, crear un cierre no es tan sencillo como en
Groovy. Debe crear una clase que derive degroovy.lang.Cierree implementar unObjeto
doCall (argumentos de objeto)método. Una técnica alternativa es
7
La multiplicación es fácil de demostrar en un libro, pero los ejemplos del mundo real pueden incluir el manejo de recursos
transaccionales, la configuración y el registro.
www.it-ebooks.info
Uso del motor de secuencias de comandos Groovy 575
//Java
MétodoCierremclos=new MethodClosure(multiplicador, "multiplicar"); Vinculación
vinculación = nueva vinculación ();
vinculante.setVariable("multiplicar",mclos); shell GroovyShell
= nuevo GroovyShell (enlace); shell.evaluar("multiplicar(5, 6)");
Ahora hemos cubierto completamente cómoGroovyShellse puede operar tanto desde Java como desde Groovy
para extender su aplicación.GroovyShelles una buena clase de utilidad para crear puntos de extensión en su
propio código y ejecutar lógica que se puede externalizar en scripts almacenados como cadenas, en el sistema de
archivos o en una base de datos. Esta clase es excelente para evaluar, analizar o ejecutar secuencias de
comandos que representan una unidad de trabajo única e independiente, pero es menos fácil de usar cuando la
lógica se distribuye entre secuencias de comandos dependientes. Aquí es donde
laGroovyScriptEngineyGroovyClassLoaderpoder ayudar. Estos son los temas de
las siguientes dos secciones.
losGroovyShellLa clase es ideal para secuencias de comandos independientes y aisladas, pero puede ser
menos fácil de usar cuando las secuencias de comandos dependen unas de otras. La solución más simple
en ese punto es usarGroovyScriptEngine.Esta clase también brinda la capacidad de recargar scripts a
medida que cambian, lo que permite que su aplicación admita modificaciones en vivo de su lógica
comercial. Cubriremos los usos básicos del motor de secuencias de comandos y le mostraremos cómo
decirle al motor dónde encontrar secuencias de comandos.
El motor de secuencias de comandos tiene varios constructores para elegir cuando lo instancia. Puede
pasar diferentes argumentos a estos constructores, como una serie de rutas o direcciones URL en las que
el motor intentará encontrar los scripts de Groovy, un cargador de clases que se usará como cargador de
clases principal o un programa especial.conector de recursosque proporcionaURLConexións. En nuestros
ejemplos, asumiremos que estamos cargando y ejecutando scripts desde el sistema de archivos:
El motor asume que las cadenas representan ubicaciones del sistema de archivos. Si sus scripts se van a
cargar desde un lugar que no sea el sistema de archivos, debe usar URL en su lugar:
www.it-ebooks.info
576 CPASADOdieciséisIntegrando Groovy
El motor buscará el recurso siguiendo cada URL secuencialmente hasta que encuentre
el script.
Los constructores también pueden tomar un cargador de clases, que luego será utilizado por el motor para
el cargador de clases principal de las clases compiladas:
El motor almacena en caché automáticamente los scripts cargados y se actualizan cada vez que se
actualiza el recurso. El motor también puede cargar clases de script directamente con elcargar-
ScriptByNamemétodo; devuelve unClaseobjeto que representa la clase del script, que es una clase
derivada demaravilloso.lang.Script.Sin embargo, hay una trampa a tener en cuenta con este método.
Toma una secuencia de comandos con una notación de nombre de clase completamente calificada en
lugar de la ruta relativa del archivo:
Este ejemplo devuelve la clase del script myScript.groovy situado en la carpeta de prueba. Si
no está usando el sistema de archivos, estará usando URL en lugar de archivos, y en ese caso
es obligatorio usar un conector de recursos especial que es responsable de cargar los
recursos.
Si desea cargar secuencias de comandos desde una ubicación en particular, es posible que desee
proporcionar su propio conector de recursos. Esto se hace pasándolo como argumento al
constructor deGroovyScript Engine,ya sea con o sin la especificación de un cargador de clases
principal. El siguiente ejemplo muestra ambos métodos sobrecargados:
www.it-ebooks.info
Trabajando con GroovyClassLoader 577
Para implementar su propio conector, debe crear una clase que implemente el
Groovy.util.ResourceConnectorinterfaz, que contiene un solo método:
Aunque generalmente almacenará su script en el sistema de archivos o dentro de una base de datos,
implementando su propioconector de recursosyURLConexiónle permite controlar los scripts que provienen
de cualquier ubicación: desde una base de datos, un sistema de archivos remoto, un documento XML o
un almacén de datos de objetos.
GroovyScriptEnginees perfecto para manejar scripts, pero se queda corto para la
manipulación más compleja de clases. De hecho, ambosGroovyShellyGroovyScriptEngine
confiar en un único mecanismo para cargar scripts o clases: elGroovyClassLoader.Este cargador de clases
especial es lo que discutiremos a continuación.
clase hola {
def saludo() { "¡Hola!" }
}
www.it-ebooks.info
578 CPASADOdieciséisIntegrando Groovy
Instanciando GroovyClassLoader
En el ejemplo, usamos el constructor predeterminado. Pero esta clase ofrece más
constructores.GroovyClassLoader (cargador de ClassLoader)le permite definir un cargador
de clases principal para evitar problemas con una jerarquía compleja, como se explica en la
sección sobreGroovyShell.el constructorGroovyClassLoader (cargador de ClassLoader,
configuración de configuración del compilador)le da más control sobre el comportamiento
del cargador de clases, como se explica en la sección sobreGroovyShell,gracias a la
parametrización deConfiguración del compilador.
//Java
GroovyClassLoader gcl = nuevo GroovyClassLoader();
Class greetingClass = gcl.parseClass(nuevo archivo("Hola.groovy")); GroovyObjeto
hola = (GroovyObject) greetingClass.newInstance();
Objeto[] argumentos = {};
afirmar "¡Hola!".equals(hola.método de invocación("saludo", argumentos));
losmétodo de invocaciónEl método toma dos parámetros: el nombre del método a llamar y
uno que corresponde a los parámetros para pasar al método que está intentando llamar. Si el
método toma solo un parámetro, páselo directamente como argumento; si se esperan varios
parámetros, deben envolverse dentro de una matriz deObjetos, que se convierte en el
argumento. Si desea llamar a un método que agrega dos objetos junto con una firma como
agregar (a, b),lo llamas así:
www.it-ebooks.info
Trabajando con GroovyClassLoader 579
Pero si un método al que desea llamar requiere una matriz como parámetro único, también debe
envolverlo dentro de una matriz:
A pesar de que es posible llamar a cualquier método en una clase Groovy desde Java con
método de invocación,hacerlo no es compatible con Java porque el compilador de Java no sabrá que
existen estas clases y no le permitirá usar elsaludométodo directamente, a menos que haya
precompilado sus clases de Groovy y las haya empaquetado dentro de un archivo JAR.
Afortunadamente, hay una solución para eludir esta deficiencia dejavac.Para que Java comprenda
sus clases de Groovy, tanto Groovy como Java tienen que encontrar un terreno común de acuerdo.
Esto es lo que llamamos el problema del huevo y la gallina.
Las versiones anteriores de Groovy hacían bastante difícil resolver el problema del huevo y la
gallina. Si tenía una clase de Java que usaba una clase de Groovy, que a su vez usaba una clase de
Java definida en el mismo proyecto, tenía un problema. Arreglar esto implicó la refactorización del
código, como la introducción de interfaces para eliminar las dependencias cíclicas. La buena noticia
es que esto ya no es un problema, gracias acompilación conjunta. La compilación conjunta es el
proceso de compilar clases de Java y Groovy en un solo paso aparente, solo usando elmaravilloso
dominio.
Para ilustrar, consideremos la aplicación Java en la siguiente lista.
//Java
clase pública ShapeInfoMain {
public static void main(String[] args) {
Cuadrado s = nuevo Cuadrado(7);
Circulo c = nuevo Circulo(4); nuevo
MaxAreaInfo().displayInfo(s, c);
nuevo MaxPerimeterInfo().displayInfo(s, C);
}
}
www.it-ebooks.info
580 CPASADOdieciséisIntegrando Groovy
losGroovyClassLoadertiene varios métodos que le permiten analizar y cargar clases de Groovy desde diferentes
orígenes: desde un archivo, desde un flujo de entrada o desde una cadena. Estos son algunos de los métodos
que se pueden usar cuando se le pide explícitamente al cargador de clases que cargue una clase determinada:
Si está almacenando sus fuentes en una base de datos, una posible solución es recuperarlas como un
Cuerdao como unFlujo de entrada.Luego, puede usar el cargador de clasesparseClassmétodos
para analizar y cargar sus clases. Pero en lugar de implementar explícitamente la plomería y
la búsqueda y analizarlo usted mismo, Groovy proporciona una mejor solución, en forma de
unGroovy.lang.GroovyResourceLoader.El cargador de recursos es una interfaz que debe
implementar para especificar dónde se encuentran sus fuentes: déle un nombre de un
recurso y se devolverá una URL que apunta a la ubicación del recurso. Esto se hace mediante
un único método desde esa interfaz:
}
}
PROPINAComo fue el caso conGroovyScript Engine,si estás creando el tuyo propio
URLyURLConexiónclases derivadas, asegúrese de que suURLanula su
conexión abiertamétodo, que devuelve una instancia deURLConexión;y
asegúrese de anular también elobtenerÚltimaModificación, obtenerURL,y
getInput-Streammétodos de la devoluciónURLConexión.
www.it-ebooks.info
Trabajando con GroovyClassLoader 581
Una vez que haya definido esta clase, debe registrarla en su cargador de clases antes de usarla de esta
manera:
¡Su cargador de clases ahora usará su cargador de recursos para encontrar los recursos que
necesita desde donde quiera! En este punto, puede encontrar que tiene menos control del que le
gustaría sobre qué código se ejecuta. Es posible que deba bloquear cuánto acceso tiene el código
al resto del sistema, dependiendo de cuánto sepa sobre los orígenes del código. Aquí es donde
entra en juego el modelo de seguridad de Java y Groovy, como verá en la siguiente sección.
Al empaquetar una aplicación, sabe que todo su código fuente es de confianza. Cuando abre las puertas a
un código dinámico que puede evolucionar con el tiempo, como cambiar las reglas comerciales debido a
un cambio en la legislación, debe asegurarse de que también se pueda confiar en este código. Solo los
usuarios de confianza deberían poder cambiar el código dinámico iniciando sesión y proporcionando las
credenciales pertinentes. Pero incluso con la autenticación y la autorización vigentes, nunca estará
protegido contra los errores humanos. Es por eso que Groovy proporciona un segundo nivel de confianza
en el código dinámico en forma de un espacio aislado seguro que puede configurar para cargar este
código externo.
Modificar, cargar y ejecutar código dinámico en tiempo de ejecución es una buena manera de
extender su aplicación de manera ágil, reduciendo el tiempo requerido para adaptarla según sea
necesario. Los largos y tediosos escenarios de reempaquetado, recalificación y redistribución pueden
desaparecer en poco tiempo. Este no es un tema para tomar a la ligera y, por supuesto, siempre tendrás
que entregar tu aplicación al equipo de aceptación y pasar las pruebas de integración pertinentes; pero
incrustar código de un lenguaje de secuencias de comandos en su aplicación puede ayudarlo a ser más
versátil cuando los requisitos cambian.
NOTACubrir todo el modelo de seguridad de Java con sus administradores de seguridad, permisos y
archivos de políticas está más allá del alcance de este capítulo. Suponemos que está familiarizado con
estos conceptos. De lo contrario, recomendamos los recursos en línea proporcionados en el sitio web
de Oracle para obtener una visión detallada de cómo funciona la seguridad en la plataforma Java.
www.it-ebooks.info
582 CPASADOdieciséisIntegrando Groovy
En el modelo de seguridad de Java, se otorgan permisos a las fuentes de código de acuerdo con su código
fuente. Una fuente de código se compone de una base de código en forma de URL desde la cual el
cargador de clases cargó el código fuente y, potencialmente, un certificado que se usa para verificar el
código cuando se obtiene de un archivo JAR firmado.
Hay dos casos que tienes que considerar. Si todas sus fuentes de Groovy se compilan primero en
archivos .class y finalmente se agrupan en un archivo JAR, se aplican los mecanismos de seguridad
estándar. Esas clases son como fuentes normales compiladas de Java, por lo que siempre puede usar los
mismos administradores de seguridad que de costumbre. Pero cuando estás compilando fuentes de
Groovy sobre la marcha, a través de la integración significa que has estudiado hasta ahora, se deben
seguir pasos adicionales.
La primera parte otorga todos los permisos a nuestra aplicación de servidor, la segunda parte solo
permite los scripts delarchivo:/restringidobase de código para acceder a laarchivo.codificación
propiedad en modo de sólo lectura. Este archivo de política debe estar disponible en el classpath
de la aplicación y la propiedad del sistemajava.politica.de.seguridadla definición del archivo de
política que se utilizará debe especificarse en la línea de comandos que inicia la JVM o en el código.
Un script que solicite leer la propiedad del sistema incluiría un código como:
www.it-ebooks.info
Trabajando con GroovyClassLoader 583
Para que la aplicación que llama pueda crear unGroovyCodeFuentecon un código base
específico, la política debe otorgarle permiso. El permiso específico requerido
es unGroovy.security.GroovyCodeSourcePermission,cuál es la aplicación de llamada
tiene implícitamente porque el archivo de política le otorgó lajava.seguridad.Todos los permisos, que otorga
todos los derechos posibles.
GroovyClassLoadertambién tiene dos métodos; ambas clases de análisis, pero el último también proporciona una
opción para controlar si la clase analizada debe colocarse en la memoria caché del cargador de clases:
www.it-ebooks.info
584 CPASADOdieciséisIntegrando Groovy
Armado con diferentes medios para integrar Groovy de forma segura en su aplicación, puede crear
aplicaciones extremadamente flexibles. Por supuesto, esos mecanismos son específicos de Groovy.
Sin embargo, estos no son los únicos medios disponibles. Si está utilizando Spring Framework
como base común para su aplicación, o si está utilizando la compatibilidad con secuencias de
comandos agregada en Java 6 (JSR-223), puede utilizar los mecanismos proporcionados en estas
plataformas para cargar su código dinámico en una manera que facilitaría alejarse de Groovy, si
alguna vez lo desea.8
NOTAEstá más allá del alcance de esta sección explicar cómo se puede instalar,
usar o configurar Spring. Suponemos que el lector interesado ya está
familiarizado con el marco. Si este no es el caso, los creadores de Spring tienen
documentación en línea completa y detallada en http://spring.io/ docs que
debería ser ideal para descubrir de qué se trata.
Explicaremos cómo puede conectar POGO en Spring, analizaremos la recarga del código fuente de Groovy sobre
la marcha y cubriremos cómo el código fuente de Groovy se puede especificar directamente en el
8
No es que podamos pensar en ninguna razón por la que desee hacerlo, pero nos gusta el principio de evitar el bloqueo de proveedores siempre que sea
posible.
www.it-ebooks.info
Integración de primavera 585
especifica Crea
www.it-ebooks.info
586 CPASADOdieciséisIntegrando Groovy
En nuestro archivo fuente de Groovy, tenemos el mismo constructor que teníamos anteriormente,
y hemos agregado uncolorpropiedad a nuestroCirculoclase. En el archivo de definición de Spring, el
anidadoconstructorindica el valor a pasar al constructor durante la creación de nuestroCirculo.los
propiedadelemento indica que elcolorLa propiedad también debe establecerse como parte de la
inicialización. Para hacer uso de estas definiciones, necesitamos cambiar nuestraprincipalmétodo
enShapeInfoPrincipalen el listado 16.10 para convertirse
//Java
probar {
ApplicationContext ctx =
nuevo ClassPathXmlApplicationContext("beans.xml"); Forma s =
nuevo Cuadrado (7);
Forma c = (Forma) ctx.getBean("círculo");
información de ShapeInfo = (ShapeInfo) ctx.getBean("maxareainfo");
info.displayInfo(s, c);
nuevo MaxPerimeterInfo().displayInfo(s, c); } captura
(Excepción e) {
e.printStackTrace();
}
Spring proporciona una serie de mecanismos para crear beans para usted. En este caso, usamos lo
que se llama elcontexto de aplicación. Tiene unobtenerBeanmétodo que nos permite pedir un bean
por su nombre.
Como mencionamos anteriormente, asumimos aquí que todas nuestras clases de Groovy están
precompiladas. Entonces, ¿qué hemos ganado? Hemos comenzado el proceso de eliminación de
dependencias explícitas de nuestro código base. Con el tiempo, podríamos comenzar a mover más
información de dependencia al archivo de cableado y permitir que nuestro sistema se configure más
fácilmente. Como consecuencia, nuestro diseño también se vuelve más flexible, porque podemos cambiar
fácilmente nuestras implementaciones concretas. Esto es particularmente importante para las pruebas
unitarias, donde podríamos reemplazar implementaciones concretas con implementaciones simuladas.
Sin embargo, podemos hacer más: Spring admite la compilación dinámica de nuestros scripts Groovy
a través de una clase especial de fábrica Groovy. Así es como lo usaríamos. Ampliaríamos nuestro archivo
de configuración de bean de la siguiente manera:
…
<lang:id maravilloso="maxareainfo2"
script-source="classpath:MaxAreaInfo.groovy"> <lang:property
name="prefix" value="Live Groovy dice" /> </lang:groovy>
Spring 2.0 y versiones posteriores admiten una serie de lenguajes de secuencias de comandos dinámicos a través
de fábricas especiales específicas del lenguaje. el espacio de nombresidioma: maravillosoaccede
automáticamente a la fábrica Groovy especial. Ahora podemos usarmaxareainfo2como el nombre que le
pasamos a la fábrica de beans cuando creamos nuestro bean, y Spring compilará automáticamente los archivos
fuente de Groovy necesarios.
www.it-ebooks.info
Integración de primavera 587
…
<lang:id maravilloso="maxareainfo2"
refresh-check-delay="5000" script-
source="classpath:MaxAreaInfo.groovy"> <lang:property
name="prefix" value="Live Groovy dice" /> </lang:groovy>
Actualizar beans sobre la marcha puede hacer que el desarrollo sea más rápido, pero debe considerar
deshabilitarlo nuevamente para los sistemas de producción: reiniciar el sistema después de que se haya
realizado un cambio tiende a evitar situaciones confusas en las que durante un período de tiempo (por
breve que sea) solopartedel sistema ha visto la actualización.
Aunque podría decirse que es una mala idea poner código dentro del archivo de configuración de Spring, Spring
ofrece otra forma de definir beans con secuencias de comandos alen líneaellos, incluida la fuente directamente
en el archivo de configuración. La documentación de Spring menciona escenarios para tal caso, como dibujar y
definir validadores para controladores Spring MVC o controladores de secuencias de comandos para creación
rápida de prototipos o definición de flujo lógico.
En el siguiente listado, alineamos una variación deMaxAreaInfo (tenemos que cambiar nuestra
fábricaobtenerBeanllamar para usarmaxareainfo3).
<lang:id maravilloso="maxareainfo3">
Le dice a Spring que somos
<lang:inline-script> usando Groovy
importar resorte.forma.común
importar spring.common.ShapeInfo Define el
clase que queremos
clase SufijoMaxAreaInfo implementa ShapeInfo { una instancia de
sufijo de cadena
void displayInfo(Forma s1, Forma s2) {
print "La forma con el área más grande es: "
if (s1.area() > s2.area()) println s1 + ":" + sufijo else println s2 + ":" +
sufijo
}
}
</lang:inline-script>
<lang:propiedad nombre="sufijo" Especifica un
value="¿Lo has adivinado correctamente?"/> propiedad de frijol
</lang:genial>
www.it-ebooks.info
588 CPASADOdieciséisIntegrando Groovy
En este caso, debido a que el contenido está codificado, la configuración del atributo actualizable de la fábrica de
secuencias de comandos no se aplica a esos beans con secuencias de comandos en línea. Una última
observación: si su secuencia de comandos contiene un signo menor que (<), la configuración XML Spring no será
válida, porque el analizador XML pensará que es el comienzo de una nueva etiqueta. Para eludir este problema,
debe envolver todo el bean con script en una sección CDATA.
Esta ha sido una breve introducción a las capacidades del bean de secuencias de comandos del
marco Spring. Para obtener más detalles y explicaciones más detalladas, consulte la
documentación del proyecto en http://spring.io/docs.
Spring no es la única tecnología reciente que adopta las secuencias de comandos. La
siguiente sección anticipa la próxima versión de la plataforma Java y explora qué soporte se
brindará para la integración de Groovy.
www.it-ebooks.info
Montando Mustang y JSR-223 589
- codificación <codificación> Especificar la codificación de caracteres utilizada por los archivos de script.
- f <archivo de script> Evaluar el archivo de script dado.
-f- Modo interactivo, lea el script desde la entrada
estándar
- ayuda, -? Imprime este mensaje de uso y sal
-q Enumere todos los motores de secuencias de comandos disponibles y salga.
Aunque la línea de comando le permite ejecutar Groovy a través de la nueva API sin escribir
ningún código para hacerlo, si su aplicación va a integrar Groovy, usará la API directamente
en lugar de depender de la herramienta. Conozcamos las clases principales involucradas en
la ejecución de scripts a través de JSR-223.
16.6.2 El administrador del motor de secuencias de comandos y sus motores de secuencias de comandos
Por lo tanto, si desea recuperar el motor de secuencias de comandos Groovy proporcionado con la
implementación de referencia, puede buscarlo por su nombre:
pueden lanzar unexcepción de secuencia de comandos,que puede contener una causa de excepción raíz, un
mensaje, un nombre de archivo e incluso un número de línea y un número de columna donde ocurrió un
error, particularmente cuando el error es un error de compilación. el opcionalScriptContext
www.it-ebooks.info
590 CPASADOdieciséisIntegrando Groovy
Más allá de las capacidades básicas de evaluación de guiones, el motor Groovy implementa dos
otras interfaces:javax.script.Compilableyjavax.script.Invocable.El primero
le permite precompilar y reutilizar scripts, y este último le permite ejecutar un método, una unidad
de ejecución, en lugar de ejecutar un script completo como lo hace con elevaluarmétodo. La
implementación de estas interfaces no es obligatoria, pero el motor Groovy proporciona esta
función:
//Java
Administrador de ScriptEngineManager = nuevo ScriptEngineManager();
ScriptEngine gEngine = manager.getEngineByName("groovy"); compilable
compilable= (Compilable)gEngine; compilable.put("nombre", "Dierk");
//Java
Administrador de ScriptEngineManager = nuevo ScriptEngineManager();
ScriptEngine gEngine = manager.getEngineByName("groovy");
www.it-ebooks.info
Montando Mustang y JSR-223 591
//Java
interfaz Servicio empresarial {
vacío en eso();
Objeto ejecutar(Objeto[] parámetros);
vacío liberar();
}
Creamos un script que contiene funciones mapeando las mismas firmas que las
provistas en elServicio empresarialinterfaz:
// genial
void init() { println "init" }
Objeto ejecutar(Objeto[] objs) { println "ejecutar" } anular liberación()
{ println "liberar" }
Podemos hacer que un script de este tipo parezca implementar elServicio empresarialinterfaz
llamando alobtenerInterfazmétodo del motor de script invocable:
//Java
Administrador de ScriptEngineManager = nuevo ScriptEngineManager();
ScriptEngine gEngine = manager.getEngineByName("groovy"); invocable
invocable= (Invocable)gEngine; invocable.evaluar(scriptAsAString); Servicio
empresarialServicio=
invocable.obtenerInterfaz(BusinessService.clase);
Servicio.en eso();
Resultado del objeto =Servicio.execute(nuevo Objeto[] {});
Servicio.liberar();
Primero, evaluamos el script que se mostró anteriormente, luego llamamos alobtenerInterfazmétodo con
la clase de la implementación que queremos que nuestro script implemente, y luego recuperamos
www.it-ebooks.info
592 CPASADOdieciséisIntegrando Groovy
una instancia que implementa esa interfaz. Nuestro script ni siquiera tiene que implementar
explícitamente elServicio empresarialinterfaz, pero a través del mecanismo de proxy, parece
como si fuera el caso. Con dicho mecanismo, puede manipular scripts como si fueran beans
Java normales, sin tener que llamar a algún tipo deinvocarmétodo.
El motor de JavaScript se incluye con los JDK de Oracle. Para otros idiomas, es posible que también
deba obtener el motor de ejecución JSR-223 respectivo de un idioma.
Eso concluye nuestra discusión sobre las opciones de integración independientes del lenguaje
usando Spring y JSR-223. En breve, discutiremos todos los pros y los contras de las opciones de
integración de Groovy nativas y neutrales en cuanto al idioma, y uno de los puntos de discusión será qué
tan profundo necesita acceder a las partes internas de Groovy. Antes de hacerlo, ampliemos una de las
clases clave para una integración nativa profunda con Groovy, elCompiladorConfiguración
clase. Mencionamos la clase anteriormente en este capítulo, pero tiene habilidades avanzadas que cubriremos a
continuación.
www.it-ebooks.info
Mastering CompilerConfiguración 593
Este ejemplo consta de dos partes bien diferenciadas: configurar unConfiguración del compilador, que
incluye el personalizador de compilación y la evaluación de un script. Debido a que el personalizador de
compilación le dice al compilador que agregue importaciones de manera transparente, cuando se ejecuta
el script ya no es necesario agregarlos para que se compile el script.
Hagamos un breve recorrido por los personalizadores de compilación que proporciona Groovy.
www.it-ebooks.info
594 CPASADOdieciséisIntegrando Groovy
Groovy es ideal para construir DSL, pero hay algunos puntos a considerar. Ningúninterno DSL
basado en Groovy es en realidad código Groovy. Sin embargo, el objetivo de un DSL es que los
expertos del dominio puedan utilizarlo. No hay ninguna razón por la que los usuarios de su DSL
sean programadores. Teniendo eso en cuenta, sería muy desafortunado que los usuarios tuvieran
que agregar importaciones a sus scripts para que funcionen.
Imaginemos un DSL que permita la evaluación de expresiones matemáticas. La
idea natural sería aprovechar las funciones y constantes disponibles en el
java.lang.matemáticasclase. Por supuesto, un usuario podría escribir esto:
Pero obviamente, la única parte importante del guión es la propia expresión matemática. los
importardeclaración está aquí para que sea más agradable de escribir o leer. El problema es que le
pedimos al usuario que agregue elimportardeclaración, aunque como sabemos que nuestro DSL
está destinado a evaluar expresiones matemáticas, lo normal sería hacer las importaciones por
defecto y dejar que el usuario llame alporquefunción así como laPiconstante sin problemas. La
primera solución obvia al problema es agregar importaciones al script del usuario:
definitivamentecaparazón=nuevo GroovyShell()
shell.evaluate('importar java.lang.Math.*\n'+expresión estática)
Si bien esto funciona, la solución no es muy elegante y presenta un problema importante: los
scripts, incluso si son "evaluados" por un Groovy Shell, al final son compilados y ejecutados por una
JVM. Esto significa que si el script contiene un error (y sucederá en algún momento), se lanzará una
excepción. En ese caso, el seguimiento de la pila no coincidirá con el código fuente: con el ejemplo
anterior, estamos introduciendo una línea de código adicional, lo que significa que cuando la
excepción muestre un error en la línea 145, el error será, para el usuario, estar realmente en la
línea 144 (debido a la importación adicional). Por supuesto, podría filtrar el seguimiento de la pila y
arreglar los números de línea/columna usted mismo, pero no resolvería el problema de
depuración: si el script está compilado, hay algunas formas de depurarlo (por ejemplo, establecer
puntos de interrupción en el IDE), y una vez más, los números de línea en el código de bytes no
coincidirían con los del código fuente. Esto es definitivamente un impedimento para la depuración.
definitivamenteconferencia=new CompilerConfiguration()
def personalizador = nuevo ImportCustomizer()
personalizador.addStarImports 'java.lang.Math'
conf.addCompilationCustomizers(personalizador) def shell =
nuevo GroovyShell(conferencia) valor def =
shell.evaluate('cos(PI/2)')
www.it-ebooks.info
Mastering CompilerConfiguración 595
El personalizador de importaciones le permite agregar varios tipos de importaciones, desde "regulares" hasta
importaciones de estrellas estáticas, incluida la capacidad de usar alias:
personalizador.addStaticImport '-','java.lang.Math','PI'
personalizador.addStaticImport 'coseno','java.lang.Math','cos'
conf.addCompilationCustomizers(personalizador) def
shell = new GroovyShell(conferencia) valor def =
shell.evaluate('coseno(-/2)')
La Tabla 16.2 resume los métodos disponibles a través del personalizador de importación.
Método Descripción
addStarImport(String nombre del paquete) Agrega una importación de estrellas para un paquete específico
miembro de la cadena)
addStaticStar(String clasName) Agrega una importación de estrella estática de todos los miembros de
una clase
Una aplicación típica de Groovy consta de archivos fuente compilados por el compilador de Groovy, ya sea
mediante la herramienta de línea de comandos, Gradle, Ant o Maven. Pero, ¿qué sucede si sus archivos
fuente son, de hecho, scripts de usuario? ¿Qué sucede si se supone que esos scripts deben compilarse
utilizando una configuración de compilador específica porque, por ejemplo, corresponden a un
www.it-ebooks.info
596 CPASADOdieciséisIntegrando Groovy
ADSL? En ese caso, una opción que tiene es omitir esos archivos de la compilación y tener un contenedor
(normalmente unGroovyShell)que compilará los archivos en tiempo de ejecución utilizando una
configuración de compilador específica. Un problema con esto es que los scripts se compilan en tiempo
de ejecución, lo que significa que paga el costo de la compilación al inicio de la aplicación o durante su
ciclo de vida. En algunas circunstancias esto no es aceptable.
Otro requisito típico del usuario es tener diferentes opciones de compilación según la extensión del
archivo. De manera predeterminada, Groovy usa la extensión de archivo .groovy, pero algunos usuarios
quieren poder usar diferentes extensiones con diferentes significados. Por ejemplo, un archivo .spec
podría corresponder a un archivo de especificación ejecutable que implica transformaciones AST que no
son necesarias para los archivos .groovy normales.
Para esos casos de uso, el personalizador consciente de la fuente proporciona un poderoso
mecanismo de configuración que básicamente aplica diferentes opciones de compilación basadas
en la fuente real. En la práctica, este personalizador actúa como un protector para otro
personalizador, según el archivo de origen. La siguiente lista crea un personalizador de origen que
aplica elEncadenarTransformación AST a clases cuyos nombres terminan conFrijol.
importar groovy.transform.ToString
importar org.codehaus.groovy.control.CompilerConfiguration
importar org.codehaus.groovy.control.customizers.* bCrea
se envuelve enC def conf = nueva configuración del compilador() ToString AST
personalizador
una fuente- def ASTPersonalizador = new ASTTransformationPersonalizador(ToString) def
consciente
sourceAwareCustomizer =
personalizador
nuevo SourceAwareCustomizer(astCustomizer)
sourceAwareCustomizer.baseNameValidator = {
nombre -> nombre.termina con 'Bean'
Crea una base-
}
conf.addCompilationCustomizers(sourceAwareCustomizer)
dfiltro de nombre
Creamos el personalizador de transformación ASTB, que se habría aplicado a todas las clases
compiladas si lo hubiéramos agregado directamente a la configuración del compilador. En su
lugar, creamos un personalizador consciente de la fuenteCque envuelve el personalizador de
transformación AST, luego establecemos un predicado en el nombre basedque determina en qué
condición se aplicará el personalizador de transformación AST. Como último paso, hacemos uso de
la configuración en conjunto con unGroovyClassLoaderpara compilar una clasemi.
www.it-ebooks.info
Mastering CompilerConfiguración 597
Tal como están, los personalizadores conscientes de la fuente ofrecen tres formas de proteger a otro personalizador.
Usar el personalizador consciente de la fuente es muy interesante, pero debemos advertirle que es una
herramienta muy poderosa que puede conducir a resultados difíciles de analizar (porque el código fuente
no cumple con las expectativas dependiendo de la extensión del archivo, por ejemplo) .
Groovy viene con muchas opciones de personalización que presentamos aquí desde un
integraciónperspectiva. En el capítulo 19, los revisaremos en parte con el propósito de cómo crear
un DSL. Allí, también discutiremos elPersonalizador de transformación ASTy elpersonalizador AST
seguro,que también sería pertinente en el contexto de la integración.
Pero no tienes que vivir con un conjunto fijo de personalizadores que te ofrece Groovy. Puedes
escribir el tuyo con la misma facilidad.
}
} bfase
Este es el código mínimo que tendrás que escribir. AB, estamos configurando la fase de
compilación donde funciona el personalizador de compilación. Al igual que con las
transformaciones AST, un personalizador de compilación debe elegir la fase de compilación
adecuada y, a menudo, cuanto antes, mejor. Ahora tenemos que escribir el código, que realmente
verificará si el campo existe:
www.it-ebooks.info
598 CPASADOdieciséisIntegrando Groovy
si (campo) {
if (!field.type.equals(ClassHelper.STRING_TYPE)) {
source.addError(new SyntaxException("Clase ${classNode.name} " +
"define el campo 'nombre' pero usando el tipo incorrecto"),
field.lineNumber, field.columnNumber)
}
} más {
source.addError(new SyntaxException("Clase ${classNode.name} " +
"no define un campo llamado 'nombre' de tipo 'Cadena'",
classNode.lineNumber, classNode.columnNumber))
}
}
Como puede ver, esta opción requiere un archivo de configuración que es en sí mismo un script de
Groovy. Este archivo de configuración le dará acceso a laCompiladorConfiguracióninstancia que el
maravillosoEl comando crea internamente, lo que le brinda la oportunidad de conectar sus
personalizadores de compilación. Esta instancia de configuración del compilador se expone en el script de
configuración usando elconfiguraciónvariable. Esto significa que puede escribir esto en el archivo de
configuración:
importar groovy.transform.Log
importar org.codehaus.groovy.control.customizers.ASTTransformationCustomizer
config.addCompilationCustomizers(nuevo ASTTransformationCustomizer(Registro))
Esta opción de configuración también está disponible en elmaravillosocomando, así como en la tarea Ant.
Por lo tanto, todos los archivos compilados utilizarán la configuración modificada por el script.
www.it-ebooks.info
Mastering CompilerConfiguración 599
Pero lo que es realmente bueno es que este script de configuración también expone un buen DSL para
personalizar la configuración, lo que reduce drásticamente la cantidad de código que se requiere para
modificar elConfiguración del compilador.Este DSL es un generador de personalizadores de compilación,
que se vincula automáticamente alconConfigmétodo:
withConfig(config) {
ast(Registro)
}
Este código es semánticamente equivalente al anterior, a pesar de ser mucho más conciso (ya no es
necesario importar), pero usa la sintaxis del constructor en su lugar, lo que significa que
ast(Registro)crea un personalizador de transformación AST para elTroncoTransformación AST.
La Tabla 16.3 resume el mapeo entre la sintaxis del constructor y la sintaxis
tradicional.
www.it-ebooks.info
600 CPASADOdieciséisIntegrando Groovy
Para hacer esto, siempre debe tomarse el tiempo para documentar la configuración, explicar por qué se hizo de
la manera en que se hizo y asegurarse de que su archivo de compilación use la configuración del compilador. Al
final, nunca use un archivo de configuración local y considere los scripts de configuración del compilador como
parte del código fuente. ¡Si no lo hace, es demasiado fácil crear construcciones irreproducibles!
Ahora conoce las técnicas nativas de Groovy para integrar Groovy en su aplicación
Java y las soluciones más independientes del lenguaje que usan Spring o JSR-223. Lo
bueno de esto es que te presenta una opción. La desventaja es que debe tomar una
decisión, por lo que brindamos orientación en la última sección de este capítulo.
Soporte de secuencias de comandos de Spring Se integra bien con Spring Requiere Primavera
Puede cambiar de idioma
fácilmente Admite la recarga
www.it-ebooks.info
Resumen 601
La base de la integración de Groovy es su excelente compatibilidad con Java. Hemos enumerado las
formas más comunes de integrar Groovy con Java, pero en cualquier lugar donde se pueda integrar Java,
Groovy también puede funcionar. Algunas bases de datos permiten que los procedimientos almacenados
se escriban en Java, por ejemplo, por lo que Groovy se puede usar de la misma manera. Es posible que
con el tiempo aparezcan mecanismos de integración adicionales de diversas formas. (Vea Grengine,
http://grengine.ch/.) ¡No asuma que las opciones dadas aquí son exhaustivas!
16.9 Resumen
Este capítulo le ha dado una idea de cómo podría permitir que sus aplicaciones se vuelvan más
flexibles, brindando a los usuarios apropiados la capacidad de personalizar el comportamiento de
una manera que les permita resolver los problemas.exactoproblema al que se enfrentan, en lugar
del que estaba más cerca de lo que podía imaginar al diseñar la aplicación.
Los medios para integrar Groovy en su aplicación se dividen en dos campos: los
proporcionados directamente por las bibliotecas de Groovy y los proporcionados de manera
neutral por Spring y, desde Java 6, a través de JSR-223. Como suele ser el caso, las soluciones
más específicas resultan ser las más poderosas, pero a costa de la neutralidad lingüística.
Como sujetalibros del capítulo, discutimos los tipos de aplicaciones que se benefician de
este tipo de integración y ofrecemos orientación sobre qué mecanismo de integración podría
ser mejor para su situación.
Hay una buena razón por la cual el equipo de Spring hizo de Groovy un ciudadano de primera clase y
su lenguaje de secuencias de comandos preferido en la versión 4.0: la integración de Groovy con su
plataforma subyacente es tan profunda que es la elección natural para cualquier actividad dinámica en la
JVM.
Puede beneficiarse de las ventajas de ambos mundos: puede crear aplicaciones empresariales grandes y
escalables sin dejar de utilizar Groovy para una configuración inteligente, reglas empresariales adaptables, lógica
definida por el usuario e inspecciones espontáneas en tiempo de ejecución.
www.it-ebooks.info
www.it-ebooks.info
parte 3
Groovy aplicado
www.it-ebooks.info
604 PAGSARTE3Groovy aplicado
bibliotecas y marcos que lo ayudan con tareas tan diversas como escribir aplicaciones web,
aplicaciones de escritorio, automatizar Windows, usar herramientas de análisis de calidad, diseñar
por contrato y mucho más. Es una descripción general rápida pero amplia para despertar su
interés en aprender más sobre estos proyectos. Esperamos que lo tomes como tu trampolín para
sumergirte en el océano Groovy.
www.it-ebooks.info
Pruebas unitarias con Groovy
- Integración de IDE
- Probando con Spock
- Automatización del proceso de construcción
La principal diferencia entre algo que podría salir mal y algo que no
puede salir mal es que cuando algo que no puede salir mal sale mal,
por lo general resulta imposible repararlo.
—Douglas Adams
1
Véase Kevin Tate,Desarrollo de software sostenible: una perspectiva ágil(Addison Wesley Professional, 2005) y
Greg Smith y Ahmed Sidky,Volverse ágil(Manning, 2009).
2
Véase Petar Tahchiev, et al.,JUnit en Acción, 2Dakota del Norteed.(Manning, 2010); JB Rainsberger,Recetas JUnit(Manning,
2004) y www.junit.org para obtener más información.
605
www.it-ebooks.info
606 CPASADO17Pruebas unitarias con Groovy
Al desarrollar aplicaciones Java en los últimos años del siglo XX, las pruebas unitarias
automatizadas eran casi desconocidas. Sí, escribimos pruebas, ¡pero no estaban automatizadas ni
formaban parte de una compilación estándar!
Avance rápido hasta el presente, y muchas personas no pensarían en escribir, y mucho menos
liberando, código sin pruebas unitarias correspondientes. Escribimos pruebas todo el tiempo y
esperamos que todos los demás en nuestros equipos hagan lo mismo. Además, está creciendo el
impulso detrás de la idea de escribir código escribiendo siempre primero las pruebas. Aunque esto
no es universal, es otro indicador de que continuará el crecimiento reciente en la importancia de
las pruebas.
Realizamos pruebas en todos los niveles, desde pruebas unitarias hasta pruebas de integración y
pruebas de sistemas. A veces es más divertido escribir las pruebas que el tema bajo prueba, porque
hacerlo mejora no solo el código en sí, sino también el diseño del código. Cuando las pruebas se escriben
con frecuencia y de manera continua, el código tiene la ventaja de ser altamente extensible, además de
estar obviamente más libre de defectos y más fácil de reparar cuando sea necesario.
Combine este mayor conocimiento de las pruebas de desarrollador con Groovy, y tendrá una
combinación perfecta. Con Groovy, las pruebas se pueden escribir de forma más rápida y sencilla. Se
vuelve aún mejor cuando combina la simplicidad de las pruebas unitarias en Groovy con Java normal.
Puede escribir pruebas de Groovy para sus sistemas basados en Groovy y aprovechar las muchas
bibliotecas de Java y paquetes de extensión de prueba. Puede escribir pruebas de Groovy para sus
sistemas basados en Java y aprovechar los beneficios de sintaxis mejorada y la funcionalidad de prueba
extendida de Groovy.
Groovy hace que las pruebas unitarias sean muy sencillas, independientemente de la forma en que lo use, principalmente debido a cuatro
aspectos clave:
- Groovy incorpora JUnit, por lo que no tiene que configurar una nueva dependencia.
- Groovy tiene una clase de caso de prueba mejorada, que agrega una plétora de nuevos métodos
de aserción.
- Groovy tiene funciones integradas de simulación, código auxiliar y otras funciones dinámicas de creación de clases que
- Las pruebas escritas en Groovy se pueden ejecutar fácilmente desde Gradle, Maven o su IDE favorito.
Nuestro enfoque en este capítulo es la prueba unitaria; sin embargo, muchas de las ideas también se
pueden extender a otros tipos de pruebas. Mencionaremos ejemplos específicos a lo largo del capítulo.
3Java también admite aserciones a nivel de idioma, pero las desactiva de forma predeterminada.
www.it-ebooks.info
Empezando 607
cuando sea necesario, y brindando los medios para ejecutar conjuntos de casos de prueba fácilmente,
tanto desde la línea de comandos como a través de la integración con su IDE o entorno de compilación.
Esta sección le muestra lo simple que puede ser y le presentaGroovyTestCase,la clase base utilizada para la
mayoría de las pruebas unitarias en Groovy.
convertidor de clase {
estático celsius (fahrenheit) { (fahrenheit - 32) * 5 / 9 }
}
¿Es correcta esta implementación? Probablemente, pero no puedes estar seguro. Debe ganar más
confianza en este método antes de que el próximo viajero fuera de los EE. UU. use su método para
comprender el pronóstico del tiempo de los EE. UU.
Un enfoque común con las pruebas unitarias es llamar al sujeto bajo prueba con datos de
muestra estáticos que producen resultados bien conocidos. De esa manera, puede comparar los
resultados calculados con sus expectativas.
Elegir un buen conjunto de muestras es clave. Como regla general, tener algunos casos
típicos y todos los casos de esquina que se te ocurran es una buena opción.4Los casos típicos
serían 68° F = 20° C para tener una fiesta en el jardín o 95° F = 35° C para ir a la playa. Los
casos de esquina serían 0° F, que está entre -17° C y -18° C, la temperatura más fría que
Gabriel Daniel Fahrenheit pudo crear con una mezcla de hielo y sal común en 1714. Otro caso
de esquina es cuando el agua se congela a 32 °F = 0°C.
¿Suena complicado? no lo es La siguiente lista importa el método de forma estática y luego agrega pruebas
unitarias con secuencias de comandos utilizando afirmaciones simples que están integradas en el propio
lenguaje.
Listado 17.1 Pruebas unitarias con guión para el método de conversión de Fahrenheit a Celsius
Las pruebas con guión de este tipo son útiles. Como ejemplo, mire este libro: la mayoría de los listados
contienen afirmaciones de autocomprobación para garantizar que el código funcione y ayudar a revelar
sus expectativas del código al mismo tiempo. La mayoría incluso trabaja comopruebas en líneadonde las
aserciones viven dentro del código bajo prueba.
4
Encontrar buenos datos de prueba es una ciencia en sí misma e implica actividades como el análisis estructural del dominio de parámetros.
Para nuestros propósitos, lo mantenemos simple. Consulte la literatura de antecedentes para obtener más información.
www.it-ebooks.info
608 CPASADO17Pruebas unitarias con Groovy
Pero, ¿qué pasa si una prueba falla debido a un error de implementación? Groovy informará de
esto de forma visual. Digamos que en lugar de convertir 95° F a 35° C, asumimos incorrectamente
que el resultado debería ser 34° C. Si ejecutamos lo siguiente:
afirmar 34 == celsius(95)
Aquí puedes ver el Power Assert de Groovy en funcionamiento. Power Assert, introducido
originalmente en Spock Testing Framework, proporciona una forma muy concisa y clara de
informar errores al enviar el resultado de cada invocación a la consola. Esto hace que sea más
fácil entender qué partes salieron bien y cuáles mal.
Cada vez que cambia el entorno del código de autoevaluación, las pruebas en línea
afirman que todavía está funcionando. Los cambios ambientales pueden ocurrir por varias
razones: evaluar el script en una máquina diferente, usar una versión actualizada de JDK o
Groovy, o ejecutar diferentes versiones de paquetes de los que depende el script.
Hay circunstancias en las que las pruebas no se puedenen línea, como debido a los requisitos de
rendimiento. Algunas vecescon guionlas pruebas no son lo suficientemente convenientes porque no se
autoorganizan en árboles de conjuntos de pruebas. En tales casos, es convencional empaquetar todas las
pruebas de una secuencia de comandos o clase dada en una clase separada que resida en un archivo separado.
Aquí es dondeGroovyTestCasoaparece en el escenario.
Método Descripción
void assertContains(char esperado, char[] Verifica que una matriz dada decarbonizarses contiene un
array) valor esperado
www.it-ebooks.info
Empezando 609
Método Descripción
void assertContains(int esperado, Verifica que una matriz dada deEn ts contiene un
matriz int[]) valor esperado
guion)
void shouldFail(String scriptText) Verifica que el script provisto falla cuando se ejecuta
void shouldFail(Clase clazz, Verifica que el script provisto arroja una excepción de tipo
Cadena scriptText) estruendocuando se ejecuta
void debe fallar con causa (clase Verifica que el cierre provisto falla y que una
clazz, código de cierre) excepción particular es la causa de la falla
En el ejemplo anterior, el caso de prueba se marca como aún no implementado. Si la prueba pasa de
alguna manera, lo que aún no se esperaba, la prueba fallará con un mensaje de error descriptivo.
Groovy no te obliga a extenderGroovyTestCase,y eres libre de continuar extendiendo el
tradicionalCaso de pruebaclase proporcionada por JUnit.5Habiendo dicho eso, a menos que
5 Estos métodos amplían la versión 4.12 de JUnit, que se incluye con Groovy.
www.it-ebooks.info
610 CPASADO17Pruebas unitarias con Groovy
necesita la funcionalidad de una subclase diferente deCaso de prueba,tienes muchas razones para
usarGroovyTestCasoy no hay razones para evitarlo específicamente. Junto con las afirmaciones
enumeradas en la tabla 17.1, es más fácil trabajar conGroovyTestCasoqueCaso de prueba, como verá
en la siguiente sección.
importar org.junit.Prueba
importar estático org.junit.Assert.assertEquals
clase SimpleUnitTest {
@Prueba
vacío debe agregar () {
afirmarEquals("Groovy debe agregar correctamente", 2, 1 + 1)
}
}
Recuerde, usted es libre de extender cualquierCaso de pruebaclase que elija, siempre que esté en su
classpath. Puede extender fácilmente JUnitCaso de pruebacomo sigue:
importar junit.framework.TestCase
Los casos de prueba se pueden ejecutar a través demaravillosocomando que ha utilizado anteriormente para
scripts y aplicaciones. Por ejemplo, puede ejecutar elPruebaUnitariaSimplescript visto anteriormente, por tip-
ing el comandomaravilloso SimpleUnitTest:
Bien (1 prueba)
6No tiene que importarlo: reside en uno de los paquetes importados de forma predeterminada.
www.it-ebooks.info