stringtranslate.com

Apache maravilloso

Apache Groovy es un lenguaje de programación orientado a objetos compatible con la sintaxis de Java para la plataforma Java . Es un lenguaje tanto estático como dinámico con características similares a las de Python , Ruby y Smalltalk . Se puede utilizar como lenguaje de programación y lenguaje de secuencias de comandos para la plataforma Java, está compilado en el código de bytes de la máquina virtual Java (JVM) e interopera perfectamente con otros códigos y bibliotecas de Java . Groovy utiliza una sintaxis de llaves similar a la de Java. Groovy admite cierres , cadenas multilínea y expresiones incrustadas en cadenas . Gran parte del poder de Groovy reside en sus transformaciones AST , activadas mediante anotaciones.

Groovy 1.0 se lanzó el 2 de enero de 2007 y Groovy 2.0 en julio de 2012. Desde la versión 2, Groovy se puede compilar estáticamente , ofreciendo inferencia de tipos y rendimiento cercano al de Java. [4] [5] Groovy 2.4 fue la última versión importante bajo el patrocinio de Pivotal Software , que finalizó en marzo de 2015. [6] Desde entonces, Groovy ha cambiado su estructura de gobierno a un Comité de Gestión de Proyectos en la Apache Software Foundation . [7]

Historia

James Strachan habló por primera vez sobre el desarrollo de Groovy en su blog en agosto de 2003. [8] En marzo de 2004, Groovy fue presentado al JCP como JSR 241 [9] y aceptado mediante votación. Se lanzaron varias versiones entre 2004 y 2006. Después de que comenzó el esfuerzo de estandarización del Java Community Process (JCP), la numeración de las versiones cambió y el 2 de enero de 2007 se lanzó una versión llamada "1.0". Después de varias versiones beta y candidatas a la versión 1.1, El 7 de diciembre de 2007, se lanzó Groovy 1.1 Final e inmediatamente pasó a ser Groovy 1.5 para reflejar los numerosos cambios realizados.

En 2007, Groovy ganó el primer premio en el premio a la innovación JAX 2007. [10] En 2008, Grails , un marco web Groovy , ganó el segundo premio en el premio a la innovación JAX 2008. [11]

En noviembre de 2008, SpringSource adquirió la empresa Groovy and Grails (G2One). [12] En agosto de 2009, VMware adquirió SpringSource. [13]

En abril de 2012, después de ocho años de inactividad, el líder de especificaciones cambió el estado de JSR 241 a inactivo. [9]

Strachan había abandonado el proyecto en silencio un año antes del lanzamiento de Groovy 1.0 en 2007. [ cita necesaria ] En octubre de 2016, Strachan declaró: "Todavía amo groovy (¡las tuberías de jenkins son tan geniales!), java, go, mecanografiado y kotlin". [14]

El 2 de julio de 2012 se lanzó Groovy 2.0, que, entre otras características nuevas, agregó compilación estática y verificación de tipos estáticos .

Cuando EMC Corporation (EMC) y VMware escindieron la empresa conjunta Pivotal Software en abril de 2013, Groovy y Grails formaron parte de su cartera de productos. Pivotal dejó de patrocinar a Groovy y Grails a partir de abril de 2015. [6] Ese mismo mes, Groovy cambió su estructura de gobierno de un repositorio Codehaus a un Comité de Gestión de Proyectos (PMC) en Apache Software Foundation a través de su incubadora. [7] Groovy se graduó de la incubadora de Apache y se convirtió en un proyecto de alto nivel en noviembre de 2015. [15]

El 7 de febrero de 2020, se lanzó Groovy 3.0. [16] La versión 4.0 se lanzó el 25 de enero de 2022. [17]

Características

La mayoría de los archivos Java válidos también son archivos Groovy válidos. Aunque los dos lenguajes son similares, el código Groovy puede ser más compacto porque no necesita todos los elementos que necesita Java. [18] Esto hace posible que los programadores de Java aprendan Groovy gradualmente comenzando con la sintaxis familiar de Java antes de adquirir más modismos de programación de Groovy . [19]

Las características de Groovy que no están disponibles en Java incluyen escritura estática y dinámica (con la palabra clave def), sobrecarga de operadores , sintaxis nativa para listas y matrices asociativas (mapas), soporte nativo para expresiones regulares , iteración polimórfica, interpolación de cadenas , métodos auxiliares agregados y la operador de navegación segura ?. para comprobar automáticamente si hay punteros nulos (por ejemplo, variable?.method()o variable?.field). [20]

Desde la versión 2, Groovy también admite modularidad (pudiendo enviar solo los frascos necesarios según las necesidades del proyecto, reduciendo así el tamaño de la biblioteca de Groovy), verificación de tipos, compilación estática, mejoras de sintaxis de Project Coin, bloques multicatch y mejoras continuas de rendimiento utilizando el invokedynamicInstrucción introducida en Java 7 . [21]

Groovy proporciona soporte nativo para varios lenguajes de marcado como XML y HTML , logrado a través de una sintaxis de modelo de objetos de documento (DOM) en línea. Esta característica permite la definición y manipulación de muchos tipos de activos de datos heterogéneos con una sintaxis y una metodología de programación uniformes y concisas. [ cita necesaria ]

A diferencia de Java, un archivo de código fuente de Groovy se puede ejecutar como un script (no compilado) , si contiene código fuera de cualquier definición de clase, si es una clase con un método principal o si es un Runnable o GroovyTestCase . Un script Groovy se analiza, compila y genera completamente antes de ejecutarlo (similar a Python y Ruby). Esto ocurre internamente y la versión compilada no se guarda como un artefacto del proceso. [22]

GroovyBeans, propiedades

GroovyBeans es la versión de Groovy de JavaBeans . Groovy genera implícitamente captadores y definidores. En el siguiente código, setColor(String color)y getColor()se generan implícitamente. Las dos últimas líneas, que parecen acceder al color directamente, en realidad llaman a los métodos generados implícitamente. [23]

clase AGroovyBean { color de cadena }    def myGroovyBean = nuevo AGroovyBean ()    miGroovyBean . setColor ( 'azul bebé' ) afirma myGroovyBean . getColor () == 'azul bebe'   miGroovyBean . color = 'peltre' afirmar myGroovyBean . color == 'peltre'     

Groovy ofrece una sintaxis simple y consistente para manejar listas y mapas , que recuerda a la sintaxis de matrices de Java . [24]

def movieList = [ 'Dersu Uzala' , 'Ran' , 'Seven Samurai' ] // Parece una matriz, pero es una lista afirmar movieList [ 2 ] == 'Seven Samurai' movieList [ 3 ] = 'Casablanca' // Agrega un elemento a la lista afirmar movieList . tamaño () == 4               def MonthMap = [ 'Enero' : 31 , 'Febrero' : 28 , 'Marzo' : 31 ] // Declara un mapa afirmar MonthMap [ 'Marzo' ] == 31 // Accede a una entrada MonthMap [ 'Abril' ] = 30 // Agrega una entrada al mapa afirmar MonthMap . tamaño () == 4                        

Extensión de prototipo

Groovy ofrece soporte para extensión de prototipos a través de módulos de extensión (solo en Groovy 2), categoríasExpandoMetaClass similares a Objective-C y . [25]DelegatingMetaClass

ExpandoMetaClassofrece un lenguaje específico de dominio (DSL) para expresar fácilmente los cambios en la clase, similar al concepto de clase abierta de Ruby :

Número . metaClass { sqrt = { Matemáticas . sqrt ( delegado ) } }      afirmar 9 . sqrt () == 3 afirmar 4 . raíz cuadrada () == 2      

Los cambios de Groovy en el código a través de la creación de prototipos no son visibles en Java, ya que cada invocación de atributo/método en Groovy pasa por el registro de metaclase. Solo se puede acceder al código modificado desde Java yendo al registro de metaclase.

Groovy también permite anular métodos como getProperty(), propertyMissing()entre otros, permitir al desarrollador interceptar llamadas a un objeto y especificar una acción para ellos, de una manera simplificada orientada a aspectos . El siguiente código permite que la clase java.lang.Stringresponda a la hexpropiedad:

enum Color { NEGRO ( '#000000' ), BLANCO ( '#FFFFFF' ), ROJO ( '#FF0000' ), AZUL ( '#0000FF' ) Cadena hexadecimal Color ( Cadena hexadecimal ) { this . hexadecimal = hexadecimal } }                 Cadena . metaclase . getProperty = { Propiedad de cadena -> def stringColor = delegar if ( propiedad == 'hex' ) { Color . valores (). Encuéntralo .nombre (). igual aIgnoreCase stringColor }?. hexadecimal } }                    afirmar "BLANCO" . hexadecimal == "#FFFFFF" afirmar "AZUL" . hexadecimal == "#0000FF" afirmar "NEGRO" . hexadecimal == "#000000" afirmar "VERDE" . hexadecimal == nulo            

El marco Grails utiliza ampliamente la metaprogramación para habilitar buscadores dinámicos GORMUser.findByName('Josh') , como otros. [26]

Punto y paréntesis

La sintaxis de Groovy permite omitir paréntesis y puntos en algunas situaciones. El siguiente código maravilloso

tomar ( café ). con ( azúcar , leche ). y ( licor ) 

Se puede escribir como

tomar café con azúcar , leche y licor      

permitiendo el desarrollo de lenguajes de dominio específico (DSL) que parecen inglés simple.

Programación funcional

Aunque Groovy es principalmente un lenguaje orientado a objetos, también ofrece funciones de programación funcionales .

Cierres

Según la documentación de Groovy: "Los cierres en Groovy funcionan de manera similar a un 'puntero de método', lo que permite escribir y ejecutar código en un momento posterior". [27] Los cierres de Groovy admiten variables libres, es decir, variables que no se le han pasado explícitamente como parámetro, pero que existen en su contexto de declaración, aplicación parcial (que denomina ' currying ' [28] ), delegación, implícita, escrita y parámetros sin tipo.

Al trabajar sobre Colecciones de un tipo determinado, se puede inferir el cierre pasado a una operación sobre la colección:

lista = [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ]          /* * Los números distintos de cero se convierten en verdaderos, por lo que cuando % 2 == 0 (par), es falso. * El IDE puede inferir el tipo del parámetro implícito "it" como un número entero. * También podría escribirse como: * list.findAll { Entero i -> i % 2 } * list.findAll { i -> i % 2 } */ def probabilidades = lista . encontrarTodo { es % 2 }        afirmar probabilidades == [ 1 , 3 , 5 , 7 , 9 ]       

Se puede escribir un grupo de expresiones en un bloque de cierre sin referencia a una implementación y el objeto de respuesta se puede asignar en un momento posterior mediante delegación:

// Este bloque de código contiene expresiones sin referencia a una implementación def operaciones = { declarar 5 suma 4 dividir 3 imprimir }          
/* * Esta clase manejará las operaciones que se pueden usar en el cierre anterior. Se podría declarar otra clase * que tenga los mismos métodos, pero utilizando, por ejemplo, operaciones de servicio web * en los cálculos. */ clase Expresión { Valor decimal grande     /*  * Aunque se pasa un número entero como parámetro, se convierte en un BigDecimal, como  * se definió. Si la clase tuviera un método 'declarar (valor entero)', se usaría en su lugar.  */ def declarar ( valor BigDecimal ) { this . valor = valor } def suma ( valor BigDecimal para agregar ) { this . valor += valorAgregar } def dividir ( divisor BigDecimal ) { this . valor /= divisor } def propiedadMissing ( propiedad de cadena ) { if ( propiedad == "imprimir" ) println valor } }                                      
// Aquí se define quién va a responder las expresiones en el bloque de código anterior. operaciones . delegado = nueva expresión () operaciones ()   

Curry

Generalmente llamada aplicación parcial , [28] esta característica de Groovy permite que los parámetros de los cierres se establezcan en un parámetro predeterminado en cualquiera de sus argumentos, creando un nuevo cierre con el valor vinculado. Proporcionar un argumento al curry()método solucionará el argumento uno. Proporcionar N argumentos arreglará los argumentos 1 .. N.

def joinTwoWordsWithSymbol = { símbolo , primero , segundo -> primero + símbolo + segundo } afirmar joinTwoWordsWithSymbol ( '#' , 'Hola' , 'Mundo' ) == 'Hola#Mundo'                  def concatWords = unirTwoWordsWithSymbol . curry ( '' ) afirmar concatWords ( 'Hola' , 'Mundo' ) == 'Hola mundo'       def anteponerHola = concatWords . curry ( 'Hola' ) //def prependHello = joinTwoWordsWithSymbol.curry(' ', 'Hola') afirmar prependHello ( 'Mundo' ) == 'Hola mundo'      

Curry también se puede usar en la dirección inversa (arreglando los últimos N argumentos) usando rcurry().

def potencia = { valor BigDecimal , potencia BigDecimal -> valor ** potencia }         def cuadrado = potencia . rcurry ( 2 ) def cubo = potencia . correr ( 3 )      afirmar poder ( 2 , 2 ) == 4 afirmar cuadrado ( 4 ) == 16 afirmar cubo ( 3 ) == 27          

Groovy también admite evaluación diferida , [29] [30] reducción/plegado , [31] estructuras infinitas e inmutabilidad , [32] entre otros. [33]

Procesamiento JSON y XML

En notación de objetos JavaScript ( JSON ) y procesamiento XML, Groovy emplea el patrón Builder , lo que hace que la producción de la estructura de datos sea menos detallada. Por ejemplo, el siguiente XML:

<idiomas> <idioma año= "1995" > <nombre> Java </nombre> <paradigma> orientado a objetos </paradigma> <tipificación > estático </ tipificación> </idioma> <idioma año= "1995" > <nombre > Ruby </name> <paradigm> funcional, orientado a objetos </paradigm> <typing> tipificación pato , dinámica </typing> </language> <language año= "2003" > <name> Groovy </name> <paradigm > funcional, orientado a objetos </paradigm> <typing> tipificación pato , dinámico, estático </typing> </language> </languages>                            

se puede generar a través del siguiente código Groovy:

def escritor = nuevo StringWriter () def constructor = nuevo maravilloso . xml . Constructor MarkupBuilder ( escritor ) . idiomas { idioma ( año: 1995 ) { nombre paradigma "Java" "orientado a objetos" escritura "estática" } idioma ( año: 1995 ) { nombre paradigma "Ruby" escritura "funcional, orientada a objetos" " escritura pato, dinámica" } idioma ( año: 2003 ) { nombre Paradigma "maravilloso" escritura "funcional, orientada a objetos" " escritura pato, dinámica, estática" } }                                         

y también se puede procesar en forma de streaming a través de StreamingMarkupBuilder. Para cambiar la implementación a JSON, se MarkupBuilderpuede cambiar a JsonBuilder. [34]

Para analizarlo y buscar un lenguaje funcional, findAllel método de Groovy puede servir:

def idiomas = nuevo XmlSlurper (). parseText escritor . Encadenar ()     // Aquí se emplea la sintaxis de expresiones regulares de Groovy para un comparador (=~) que será forzado a // un valor booleano: ya sea verdadero, si el valor contiene nuestra cadena, o falso en caso contrario. def funcional = idiomas . idioma . encontrarTodo { eso . paradigma =~ "funcional" } afirmar funcional . recogerlo .nombre } == [ "Maravilloso" , "Rubí" ]               

Interpolación de cadenas

En Groovy, las cadenas se pueden interpolar con variables y expresiones usando GStrings: [35]

BigDecimal account = 10.0 def text = "La cuenta muestra actualmente un saldo de $cuenta" afirmar texto == "La cuenta muestra actualmente un saldo de 10.0"         

Las cadenas G que contienen variables y expresiones deben declararse utilizando comillas dobles.

Una expresión compleja debe estar entre llaves. Esto evita que partes del mismo se interpreten como pertenecientes a la cadena circundante en lugar de a la expresión:

BigDecimal minus = 4.0 text = "La cuenta muestra actualmente un saldo de ${account - minus}" afirmar texto == "La cuenta muestra actualmente un saldo de 6.0"        // Sin los corchetes para aislar la expresión, esto resultaría: text = "La cuenta muestra actualmente un saldo de $cuenta - menos" afirmar texto == "La cuenta muestra actualmente un saldo de 10,0 - menos"     

La evaluación de expresiones se puede aplazar empleando la sintaxis de flechas:

BigDecimal tax = 0.15 text = "La cuenta muestra actualmente un saldo de ${->account - account*tax}" tax = 0.10       // El valor del impuesto se cambió DESPUÉS de la declaración de GString. La expresión // variables se vinculan sólo cuando la expresión realmente debe evaluarse: afirmar texto == "La cuenta muestra actualmente un saldo de 9.000"   

Transformación del árbol de sintaxis abstracta

Según la propia documentación de Groovy, "Cuando el compilador de Groovy compila scripts y clases de Groovy, en algún momento del proceso, el código fuente terminará representándose en la memoria en forma de un árbol de sintaxis concreta, luego transformado en un árbol de sintaxis abstracta. El propósito de AST Transformations es permitir a los desarrolladores conectarse al proceso de compilación para poder modificar el AST antes de que se convierta en código de bytes que será ejecutado por la JVM. AST Transformations proporciona a Groovy capacidades mejoradas de metaprogramación en tiempo de compilación, lo que permite una gran flexibilidad. a nivel de lenguaje, sin penalización en el rendimiento en tiempo de ejecución." [36]

Ejemplos de AST en Groovy son:

entre otros.

El marco de pruebas Spock utiliza transformaciones AST para permitir al programador escribir pruebas en una sintaxis no compatible con Groovy, pero el código relevante luego se manipula en AST para obtener un código válido. [37] Un ejemplo de tal prueba es:

def "el máximo de #a y #b es #c" () { esperar: Matemáticas . máximo ( a , b ) == c          donde: un | segundo || c 3 | 5 || 5 7 | 0 || 7 0 | 0 || 0 }                    

Rasgos

Según la documentación de Groovy, " los rasgos son una construcción estructural del lenguaje que permite: composición de comportamientos, implementación de interfaces en tiempo de ejecución, anulación de comportamientos y compatibilidad con verificación/compilación de tipos estáticos".

Los rasgos pueden verse como interfaces que llevan tanto implementaciones como estados predeterminados. Un rasgo se define utilizando la palabra clave de rasgo:

rasgo FlyingAbility { /* declaración de un rasgo */ String fly () { "¡Estoy volando!" } /* declaración de un método dentro de un rasgo */ }         

Luego, se puede usar como una interfaz normal usando la palabra clave implements:

class Bird implementa FlyingAbility {} /* Agrega el rasgo FlyingAbility a las capacidades de la clase Bird */ def bird = new Bird () /* crea una instancia de un nuevo Bird */ afirmar bird . volar () == "¡Estoy volando!" /* la clase Bird obtiene automáticamente el comportamiento del rasgo FlyingAbility */              

Los rasgos permiten una amplia gama de habilidades, desde una simple composición hasta pruebas.

Adopción

Ejemplos notables de adopción de Groovy incluyen:

soporte IDE

Muchos entornos de desarrollo integrados (IDE) y editores de texto admiten Groovy:

dialectos

Existe una implementación alternativa de Groovy:

Ver también

Referencias

Citas

  1. ^ "Versión 4.0.20". 11 de marzo de 2024 . Consultado el 22 de marzo de 2024 .
  2. ^ "Lanzamientos: apache/groovy" . Consultado el 9 de abril de 2020 - a través de GitHub .
  3. ^ "Groovy Goodness: extensiones de archivo de script Groovy predeterminadas".
  4. ^ "Rendimiento de Groovy 2.0 en comparación con Java". 25 de agosto de 2012.
  5. ^ "Prueba de rendimiento simple de Java, Groovy2.0 y Scala". 10 de julio de 2012. Archivado desde el original el 10 de diciembre de 2012 . Consultado el 7 de octubre de 2012 .
  6. ^ ab "Groovy 2.4 y Grails 3.0 serán los últimos lanzamientos importantes bajo un patrocinio fundamental". 19 de enero de 2015.
  7. ^ ab "Groovy se une a Apache Incubator". 11 de marzo de 2015.
  8. ^ James Strachan (29 de agosto de 2003). "Groovy: el nacimiento de un nuevo lenguaje dinámico para la plataforma Java". Archivado desde el original el 1 de septiembre de 2003.
  9. ^ ab "Proceso de la comunidad Java JSR 241".
  10. ^ "Groovy gana el primer premio en el premio a la innovación JAX 2007". 2007-04-26. Archivado desde el original el 13 de mayo de 2015 . Consultado el 7 de octubre de 2012 .
  11. ^ "Dicen que pueden pasar muchas cosas con una taza de café". Archivado desde el original el 19 de abril de 2011 . Consultado el 7 de octubre de 2012 .
  12. ^ "SpringSource adquiere la empresa Groovy and Grails (G2One)". 11 de noviembre de 2008.
  13. ^ "VMWare adquiere SpringSource". 10 de agosto de 2009.
  14. ^ "Tweet de James Strachan". 24 de noviembre de 2016 . Consultado el 24 de noviembre de 2016 .
  15. ^ "Anuncio en la lista de correo de desarrolladores".
  16. ^ "Lanzar GROOVY_3_0_0 · apache/groovy". GitHub . Consultado el 27 de marzo de 2024 .
  17. ^ "Lanzar GROOVY_4_0_0 · apache/groovy". GitHub . Consultado el 27 de marzo de 2024 .
  18. ^ König 2007, pág. 32
  19. ^ "Pautas de funciones de lenguaje y estilo maravilloso para desarrolladores de Java". Groovy.codehaus.org. Archivado desde el original el 17 de enero de 2015 . Consultado el 22 de enero de 2015 .
  20. ^ "Groovy: diferencias con Java". Groovy.codehaus.org. Archivado desde el original el 17 de marzo de 2009 . Consultado el 12 de agosto de 2013 .
  21. ^ "¿Qué hay de nuevo en Groovy 2.0?". 28 de junio de 2012.
  22. ^ König 2007, págs.37-8
  23. ^ König 2007, págs.38-9
  24. ^ König 2007, págs.41-3
  25. ^ "JN3525-Metaclases". Archivado desde el original el 1 de octubre de 2012 . Consultado el 7 de octubre de 2012 .
  26. ^ "Técnicas de metaprogramación en Groovy y Grails". 11 de junio de 2009.
  27. ^ "Groovy - Cierres". Archivado desde el original el 22 de mayo de 2012.
  28. ^ ab "¿Grovy llama 'currying' a la aplicación parcial?", 10 de agosto de 2013
  29. ^ "Groovy - Transformación perezosa". Archivado desde el original el 8 de octubre de 2012 . Consultado el 7 de octubre de 2012 .
  30. ^ "Notas al margen: listas diferidas en Groovy". 3 de febrero de 2011.
  31. ^ "El pliegue de Groovy". 20 de junio de 2011. Archivado desde el original el 13 de febrero de 2015 . Consultado el 12 de febrero de 2015 .
  32. ^ "Programación funcional con Groovy". 5 de noviembre de 2011.
  33. ^ "Programación de funciones en Groovy". Archivado desde el original el 8 de octubre de 2012 . Consultado el 7 de octubre de 2012 .
  34. ^ "JsonConstructor". Archivado desde el original el 2 de octubre de 2012 . Consultado el 7 de octubre de 2012 .
  35. ^ "Groovy Strings: diferentes formas de crearlas". 26 de diciembre de 2009.
  36. ^ "Metaprogramación en tiempo de compilación: transformaciones AST". Archivado desde el original el 14 de octubre de 2012 . Consultado el 7 de octubre de 2012 .
  37. ^ Rey, Paul (2020). "Una historia del lenguaje de programación Groovy". Proc. Programa ACM. Lang . 4 : 53. doi : 10.1145/3386326 .
  38. ^ "Documentación de ScriptRunner".
  39. ^ "Comunicado de prensa de ScriptRunner con estadísticas de adopción".
  40. ^ "Maravilloso DSL para la lógica empresarial de OFBiz". Proyecto Apache OFBiz Wiki abierto .
  41. ^ "Ejemplos de métodos simples con Groovy". Proyecto Apache OFBiz Wiki abierto .
  42. ^ "Griales en LinkedIn" . Consultado el 2 de junio de 2015 .
  43. ^ "Secuencias de comandos Groovy integradas". www.logicmonitor.com . Consultado el 20 de noviembre de 2020 .
  44. ^ "Oleoducto Jenkins".
  45. ^ Rocher, Graeme (2 de octubre de 2008). "Blog de Graeme Rocher: relanzamientos de Sky.com escritos en Grails". Blog de Graeme Rocher . Consultado el 2 de junio de 2015 .
  46. ^ Análisis de seguridad de aplicaciones emergentes para hogares inteligentes
  47. ^ "Secuencias de comandos y biblioteca de secuencias de comandos | Secuencias de comandos y propiedades". www.soapui.org . Consultado el 2 de junio de 2015 .
  48. ^ "Capítulo 11. Integración maravillosa". docs.jboss.org . Consultado el 2 de junio de 2015 .
  49. ^ "vCalc, la primera plataforma social para el mundo de las matemáticas". 4 de noviembre de 2014 . Consultado el 5 de mayo de 2016 .
  50. ^ "Wired.Com" (PDF) . www.springsource.org . Consultado el 2 de junio de 2015 .
  51. ^ "XWiki SAS" (PDF) . www.springsource.org . Consultado el 2 de junio de 2015 .
  52. ^ "Documentación de Grooscript". 12 de septiembre de 2016. Archivado desde el original el 28 de junio de 2017 . Consultado el 4 de julio de 2017 .
  53. ^ "Presentación en SpringOne/2GX en Grooscript". 13 de diciembre de 2015.
  54. ^ "Conversiones en línea de Grooscript". 15 de mayo de 2017. Archivado desde el original el 9 de julio de 2017 . Consultado el 4 de julio de 2017 .

Fuentes

enlaces externos