Apache Groovy

Last updated
Groovy
Groovy-logo.svg
Groovy Logo
Paradigm Multi-paradigm: object-oriented, imperative, functional, aspect-oriented, scripting
Designed by James Strachan
Developer Guillaume Laforge (PMC Chair)
Jochen Theodorou (Tech Lead)
Paul King
Cedric Champeau
First appeared2003;21 years ago (2003)
Stable release 4.0.20 [1]   OOjs UI icon edit-ltr-progressive.svg (11 March 2024;16 days ago (11 March 2024)) [±]
Preview release
4.0.0-beta-1 / September 6, 2021;2 years ago (2021-09-06) [2]
Typing discipline Dynamic, static, strong, duck
Platform Java SE
License Apache License 2.0
Filename extensions .groovy, .gvy, .gy, .gsh [3]
Website groovy-lang.org OOjs UI icon edit-ltr-progressive.svg
Major implementations
Gradle, Grails
Influenced by
Java, Python, Ruby, Smalltalk
Influenced
Kotlin

Apache Groovy is a Java-syntax-compatible object-oriented programming language for the Java platform. It is both a static and dynamic language with features similar to those of Python, Ruby, and Smalltalk. It can be used as both a programming language and a scripting language for the Java Platform, is compiled to Java virtual machine (JVM) bytecode, and interoperates seamlessly with other Java code and libraries. Groovy uses a curly-bracket syntax similar to Java's. Groovy supports closures, multiline strings, and expressions embedded in strings. Much of Groovy's power lies in its AST transformations, triggered through annotations.

Contents

Groovy 1.0 was released on January 2, 2007, and Groovy 2.0 in July, 2012. Since version 2, Groovy can be compiled statically, offering type inference and performance near that of Java. [4] [5] Groovy 2.4 was the last major release under Pivotal Software's sponsorship which ended in March 2015. [6] Groovy has since changed its governance structure to a Project Management Committee in the Apache Software Foundation. [7]

History

James Strachan first talked about the development of Groovy on his blog in August 2003. [8] In March 2004, Groovy was submitted to the JCP as JSR 241 [9] and accepted by ballot. Several versions were released between 2004 and 2006. After the Java Community Process (JCP) standardization effort began, the version numbering changed, and a version called "1.0" was released on January 2, 2007. After various betas and release candidates numbered 1.1, on December 7, 2007, Groovy 1.1 Final was released and immediately renumbered as Groovy 1.5 to reflect the many changes made.

In 2007, Groovy won the first prize at JAX 2007 innovation award. [10] In 2008, Grails, a Groovy web framework, won the second prize at JAX 2008 innovation award. [11]

In November 2008, SpringSource acquired the Groovy and Grails company (G2One). [12] In August 2009 VMware acquired SpringSource. [13]

In April 2012, after eight years of inactivity, the Spec Lead changed the status of JSR 241 to dormant. [9]

Strachan had left the project silently a year before the Groovy 1.0 release in 2007.[ citation needed ] In Oct 2016, Strachan stated "I still love groovy (jenkins pipelines are so groovy!), java, go, typescript and kotlin". [14]

On July 2, 2012, Groovy 2.0 was released, which, among other new features, added static compiling and static type checking.

When the Pivotal Software joint venture was spun-off by EMC Corporation (EMC) and VMware in April 2013, Groovy and Grails formed part of its product portfolio. Pivotal ceased sponsoring Groovy and Grails from April 2015. [6] That same month, Groovy changed its governance structure from a Codehaus repository to a Project Management Committee (PMC) in the Apache Software Foundation via its incubator. [7] Groovy graduated from Apache's incubator and became a top-level project in November 2015. [15]

On February 7, 2020, Groovy 3.0 was released [16] . Version 4.0 was released on January 25, 2022 [17] .

Features

Most valid Java files are also valid Groovy files. Although the two languages are similar, Groovy code can be more compact, because it does not need all the elements that Java needs. [18] This makes it possible for Java programmers to learn Groovy gradually by starting with familiar Java syntax before acquiring more Groovy programming idioms. [19]

Groovy features not available in Java include both static and dynamic typing (with the keyword def), operator overloading, native syntax for lists and associative arrays (maps), native support for regular expressions, polymorphic iteration, string interpolation, added helper methods, and the safe navigation operator ?. to check automatically for null pointers (for example, variable?.method(), or variable?.field). [20]

Since version 2 Groovy also supports modularity (being able to ship only the needed jars according to the project needs, thus reducing the size of Groovy's library), type checking, static compiling, Project Coin syntax enhancements, multicatch blocks and ongoing performance enhancements using the invokedynamic instruction introduced in Java 7. [21]

Groovy provides native support for various markup languages such as XML and HTML, accomplished via an inline Document Object Model (DOM) syntax. This feature enables the definition and manipulation of many types of heterogeneous data assets with a uniform and concise syntax and programming methodology.[ citation needed ]

Unlike Java, a Groovy source code file can be executed as an (uncompiled) script, if it contains code outside any class definition, if it is a class with a main method, or if it is a Runnable or GroovyTestCase. A Groovy script is fully parsed, compiled, and generated before executing (similar to Python and Ruby). This occurs under the hood, and the compiled version is not saved as an artifact of the process. [22]

GroovyBeans, properties

GroovyBeans are Groovy's version of JavaBeans. Groovy implicitly generates getters and setters. In the following code, setColor(String color) and getColor() are implicitly generated. The last two lines, which appear to access color directly, are actually calling the implicitly generated methods. [23]

classAGroovyBean{Stringcolor}defmyGroovyBean=newAGroovyBean()myGroovyBean.setColor('baby blue')assertmyGroovyBean.getColor()=='baby blue'myGroovyBean.color='pewter'assertmyGroovyBean.color=='pewter'

Groovy offers simple, consistent syntax for handling lists and maps, reminiscent of Java's array syntax. [24]

defmovieList=['Dersu Uzala','Ran','Seven Samurai']// Looks like an array, but is a listassertmovieList[2]=='Seven Samurai'movieList[3]='Casablanca'// Adds an element to the listassertmovieList.size()==4defmonthMap=['January':31,'February':28,'March':31]// Declares a mapassertmonthMap['March']==31// Accesses an entrymonthMap['April']=30// Adds an entry to the mapassertmonthMap.size()==4

Prototype extension

Groovy offers support for prototype extension through ExpandoMetaClass, Extension Modules (only in Groovy 2), Objective-C-like Categories and DelegatingMetaClass. [25]

ExpandoMetaClass offers a domain-specific language (DSL) to express the changes in the class easily, similar to Ruby's open class concept:

Number.metaClass{sqrt={Math.sqrt(delegate)}}assert9.sqrt()==3assert4.sqrt()==2

Groovy's changes in code through prototyping are not visible in Java, since each attribute/method invocation in Groovy goes through the metaclass registry. The changed code can only be accessed from Java by going to the metaclass registry.

Groovy also allows overriding methods as getProperty(), propertyMissing() among others, enabling the developer to intercept calls to an object and specify an action for them, in a simplified aspect-oriented way. The following code enables the class java.lang.String to respond to the hex property:

enumColor{BLACK('#000000'),WHITE('#FFFFFF'),RED('#FF0000'),BLUE('#0000FF')StringhexColor(Stringhex){this.hex=hex}}String.metaClass.getProperty={Stringproperty->defstringColor=delegateif(property=='hex'){Color.values().find{it.name().equalsIgnoreCasestringColor}?.hex}}assert"WHITE".hex=="#FFFFFF"assert"BLUE".hex=="#0000FF"assert"BLACK".hex=="#000000"assert"GREEN".hex==null

The Grails framework uses metaprogramming extensively to enable GORM dynamic finders, like User.findByName('Josh') and others. [26]

Dot and parentheses

Groovy's syntax permits omitting parentheses and dots in some situations. The following groovy code

take(coffee).with(sugar,milk).and(liquor)

can be written as

takecoffeewithsugar,milkandliquor

enabling the development of domain-specific languages (DSLs) that look like plain English.

Functional programming

Although Groovy is mostly an object-oriented language, it also offers functional programming features.

Closures

According to Groovy's documentation: "Closures in Groovy work similar to a 'method pointer', enabling code to be written and run in a later point in time". [27] Groovy's closures support free variables, i.e. variables that have not been explicitly passed as a parameter to it, but exist in its declaration context, partial application (that it terms 'currying' [28] ), delegation, implicit, typed and untyped parameters.

When working on Collections of a determined type, the closure passed to an operation on the collection can be inferred:

list=[1,2,3,4,5,6,7,8,9]/*  * Non-zero numbers are coerced to true, so when it % 2 == 0 (even), it is false. * The type of the implicit "it" parameter can be inferred as an Integer by the IDE. * It could also be written as: * list.findAll { Integer i -> i % 2 } * list.findAll { i -> i % 2 } */defodds=list.findAll{it%2}assertodds==[1,3,5,7,9]

A group of expressions can be written in a closure block without reference to an implementation and the responding object can be assigned at a later point using delegation:

// This block of code contains expressions without reference to an implementationdefoperations={declare5sum4divide3print}
/*  * This class will handle the operations that can be used in the closure above. Another class * could be declared having the same methods, but using, for example, webservice operations * in the calculations. */classExpression{BigDecimalvalue/*    * Though an Integer is passed as a parameter, it is coerced into a BigDecimal, as was    * defined. If the class had a 'declare(Integer value)' method, it would be used instead.   */defdeclare(BigDecimalvalue){this.value=value}defsum(BigDecimalvalueToAdd){this.value+=valueToAdd}defdivide(BigDecimaldivisor){this.value/=divisor}defpropertyMissing(Stringproperty){if(property=="print")printlnvalue}}
// Here is defined who is going to respond the expressions in the block of code above.operations.delegate=newExpression()operations()

Curry

Usually called partial application , [28] this Groovy feature allows closures' parameters to be set to a default parameter in any of their arguments, creating a new closure with the bound value. Supplying one argument to the curry() method will fix argument one. Supplying N arguments will fix arguments 1 .. N.

defjoinTwoWordsWithSymbol={symbol,first,second->first+symbol+second}assertjoinTwoWordsWithSymbol('#','Hello','World')=='Hello#World'defconcatWords=joinTwoWordsWithSymbol.curry(' ')assertconcatWords('Hello','World')=='Hello World'defprependHello=concatWords.curry('Hello')//def prependHello = joinTwoWordsWithSymbol.curry(' ', 'Hello')assertprependHello('World')=='Hello World'

Curry can also be used in the reverse direction (fixing the last N arguments) using rcurry().

defpower={BigDecimalvalue,BigDecimalpower->value**power}defsquare=power.rcurry(2)defcube=power.rcurry(3)assertpower(2,2)==4assertsquare(4)==16assertcube(3)==27

Groovy also supports lazy evaluation, [29] [30] reduce/fold, [31] infinite structures and immutability, [32] among others. [33]

JSON and XML processing

On JavaScript Object Notation (JSON) and XML processing, Groovy employs the Builder pattern, making the production of the data structure less verbose. For example, the following XML:

<languages><languageyear="1995"><name>Java</name><paradigm>objectoriented</paradigm><typing>static</typing></language><languageyear="1995"><name>Ruby</name><paradigm>functional,objectoriented</paradigm><typing>ducktyping,dynamic</typing></language><languageyear="2003"><name>Groovy</name><paradigm>functional,objectoriented</paradigm><typing>ducktyping,dynamic,static</typing></language></languages>

can be generated via the following Groovy code:

defwriter=newStringWriter()defbuilder=newgroovy.xml.MarkupBuilder(writer)builder.languages{language(year:1995){name"Java"paradigm"object oriented"typing"static"}language(year:1995){name"Ruby"paradigm"functional, object oriented"typing"duck typing, dynamic"}language(year:2003){name"Groovy"paradigm"functional, object oriented"typing"duck typing, dynamic, static"}}

and also can be processed in a streaming way through StreamingMarkupBuilder. To change the implementation to JSON, the MarkupBuilder can be swapped to JsonBuilder. [34]

To parse it and search for a functional language, Groovy's findAll method can serve:

deflanguages=newXmlSlurper().parseTextwriter.toString()// Here is employed Groovy's regex syntax for a matcher (=~) that will be coerced to a // boolean value: either true, if the value contains our string, or false otherwise.deffunctional=languages.language.findAll{it.paradigm=~"functional"}assertfunctional.collect{it.name}==["Groovy","Ruby"]

String interpolation

In Groovy, strings can be interpolated with variables and expressions by using GStrings: [35]

BigDecimalaccount=10.0deftext="The account shows currently a balance of $account"asserttext=="The account shows currently a balance of 10.0"

GStrings containing variables and expressions must be declared using double quotes.

A complex expression must be enclosed in curly brackets. This prevents parts of it from being interpreted as belonging to the surrounding string instead of to the expression:

BigDecimalminus=4.0text="The account shows currently a balance of ${account - minus}"asserttext=="The account shows currently a balance of 6.0"// Without the brackets to isolate the expression, this would result:text="The account shows currently a balance of $account - minus"asserttext=="The account shows currently a balance of 10.0 - minus"

Expression evaluation can be deferred by employing arrow syntax:

BigDecimaltax=0.15text="The account shows currently a balance of ${->account - account*tax}"tax=0.10// The tax value was changed AFTER declaration of the GString. The expression // variables are bound only when the expression must actually be evaluated:asserttext=="The account shows currently a balance of 9.000"

Abstract syntax tree transformation

According to Groovy's own documentation, "When the Groovy compiler compiles Groovy scripts and classes, at some point in the process, the source code will end up being represented in memory in the form of a Concrete Syntax Tree, then transformed into an Abstract Syntax Tree. The purpose of AST Transformations is to let developers hook into the compilation process to be able to modify the AST before it is turned into bytecode that will be run by the JVM. AST Transformations provides Groovy with improved compile-time metaprogramming capabilities allowing powerful flexibility at the language level, without a runtime performance penalty." [36]

Examples of ASTs in Groovy are:

among others.

The testing framework Spock uses AST transformations to allow the programmer to write tests in a syntax not supported by Groovy, but the relevant code is then manipulated in the AST to valid code. [37] An example of such a test is:

def"maximum of #a and #b is #c"(){expect:Math.max(a,b)==cwhere:a|b||c3|5||57|0||70|0||0}

Traits

According to Groovy's documentation, "Traits are a structural construct of the language that allows: composition of behaviors, runtime implementation of interfaces, behavior overriding, and compatibility with static type checking/compilation."

Traits can be seen as interfaces carrying both default implementations and state. A trait is defined using the trait keyword:

traitFlyingAbility{/* declaration of a trait */Stringfly(){"I'm flying!"}/* declaration of a method inside a trait */}

Then, it can be used like a normal interface using the keyword implements:

classBirdimplementsFlyingAbility{}/* Adds the trait FlyingAbility to the Bird class capabilities */defbird=newBird()/* instantiate a new Bird */assertbird.fly()=="I'm flying!"/* the Bird class automatically gets the behavior of the FlyingAbility trait */

Traits allow a wide range of abilities, from simple composition to testing.

Adoption

Notable examples of Groovy adoption include:

IDE support

Many integrated development environments (IDEs) and text editors support Groovy:

Dialects

There is one alternative implementation of Groovy:

See also

Related Research Articles

In programming languages, a closure, also lexical closure or function closure, is a technique for implementing lexically scoped name binding in a language with first-class functions. Operationally, a closure is a record storing a function together with an environment. The environment is a mapping associating each free variable of the function with the value or reference to which the name was bound when the closure was created. Unlike a plain function, a closure allows the function to access those captured variables through the closure's copies of their values or references, even when the function is invoked outside their scope.

In computer programming, a function object is a construct allowing an object to be invoked or called as if it were an ordinary function, usually with the same syntax. In some languages, particularly C++, function objects are often called functors.

In some programming languages, eval, short for the English evaluate, is a function which evaluates a string as though it were an expression in the language, and returns a result; in others, it executes multiple lines of code as though they had been included instead of the line including the eval. The input to eval is not necessarily a string; it may be structured representation of code, such as an abstract syntax tree, or of special type such as code. The analog for a statement is exec, which executes a string as if it were a statement; in some languages, such as Python, both are present, while in other languages only one of either eval or exec is.

This article compares two programming languages: C# with Java. While the focus of this article is mainly the languages and their features, such a comparison will necessarily also consider some features of platforms and libraries. For a more detailed comparison of the platforms, see Comparison of the Java and .NET platforms.

<span class="mw-page-title-main">Java syntax</span> Set of rules defining correctly structured program

The syntax of Java is the set of rules defining how a Java program is written and interpreted.

<span class="mw-page-title-main">Syntax (programming languages)</span> Set of rules defining correctly structured programs

In computer science, the syntax of a computer language is the rules that define the combinations of symbols that are considered to be correctly structured statements or expressions in that language. This applies both to programming languages, where the document represents source code, and to markup languages, where the document represents data.

<span class="mw-page-title-main">Scala (programming language)</span> General-purpose programming language

Scala is a strong statically typed high-level general-purpose programming language that supports both object-oriented programming and functional programming. Designed to be concise, many of Scala's design decisions are intended to address criticisms of Java.

<span class="mw-page-title-main">JavaScript syntax</span> Set of rules defining correctly structured programs

The syntax of JavaScript is the set of rules that define a correctly structured JavaScript program.

<span class="mw-page-title-main">Python syntax and semantics</span> Set of rules defining correctly structured programs

The syntax of the Python programming language is the set of rules that defines how a Python program will be written and interpreted. The Python language has many similarities to Perl, C, and Java. However, there are some definite differences between the languages. It supports multiple programming paradigms, including structured, object-oriented programming, and functional programming, and boasts a dynamic type system and automatic memory management.

Grails is an open source web application framework that uses the Apache Groovy programming language. It is intended to be a high-productivity framework by following the "coding by convention" paradigm, providing a stand-alone development environment and hiding much of the configuration detail from the developer.

Haxe is a high-level cross-platform programming language and compiler that can produce applications and source code for many different computing platforms from one code-base. It is free and open-source software, released under the MIT License. The compiler, written in OCaml, is released under the GNU General Public License (GPL) version 2.

In computer programming, an anonymous function is a function definition that is not bound to an identifier. Anonymous functions are often arguments being passed to higher-order functions or used for constructing the result of a higher-order function that needs to return a function. If the function is only used once, or a limited number of times, an anonymous function may be syntactically lighter than using a named function. Anonymous functions are ubiquitous in functional programming languages and other languages with first-class functions, where they fulfil the same role for the function type as literals do for other data types.

TypeScript is a free and open-source high-level programming language developed by Microsoft that adds static typing with optional type annotations to JavaScript. It is designed for the development of large applications and transpiles to JavaScript. Because TypeScript is a superset of JavaScript, all JavaScript programs are syntactically valid TypeScript, but they can fail to type-check for safety reasons.

Judoscript is a general purpose programming language designed primarily for scripting tasks on the Java platform. It was conceived and developed by James Jianbo Huang, starting in late 2001. Judoscript was one of the first so-called Java scripting languages; but its most striking characteristics is its audacious multi-domain support philosophy and practice.

The syntax and semantics of PHP, a programming language, form a set of rules that define how a PHP program can be written and interpreted.

Nemerle is a general-purpose, high-level, statically typed programming language designed for platforms using the Common Language Infrastructure (.NET/Mono). It offers functional, object-oriented, aspect-oriented, reflective and imperative features. It has a simple C#-like syntax and a powerful metaprogramming system.

Xtend is a general-purpose high-level programming language for the Java Virtual Machine. Syntactically and semantically Xtend has its roots in the Java programming language but focuses on a more concise syntax and some additional functionality such as type inference, extension methods, and operator overloading. Being primarily an object-oriented language, it also integrates features known from functional programming, e.g. lambda expressions. Xtend is statically typed and uses Java's type system without modifications. It is compiled to Java code and thereby seamlessly integrates with all existing Java libraries.

<span class="mw-page-title-main">Elm (programming language)</span> Functional programming language

Elm is a domain-specific programming language for declaratively creating web browser-based graphical user interfaces. Elm is purely functional, and is developed with emphasis on usability, performance, and robustness. It advertises "no runtime exceptions in practice", made possible by the Elm compiler's static type checking.

Kotlin is a cross-platform, statically typed, general-purpose high-level programming language with type inference. Kotlin is designed to interoperate fully with Java, and the JVM version of Kotlin's standard library depends on the Java Class Library, but type inference allows its syntax to be more concise. Kotlin mainly targets the JVM, but also compiles to JavaScript or native code via LLVM. Language development costs are borne by JetBrains, while the Kotlin Foundation protects the Kotlin trademark.

<span class="mw-page-title-main">Nim (programming language)</span> Programming language

Nim is a general-purpose, multi-paradigm, statically typed, compiled high-level systems programming language, designed and developed by a team around Andreas Rumpf. Nim is designed to be "efficient, expressive, and elegant", supporting metaprogramming, functional, message passing, procedural, and object-oriented programming styles by providing several features such as compile time code generation, algebraic data types, a foreign function interface (FFI) with C, C++, Objective-C, and JavaScript, and supporting compiling to those same languages as intermediate representations.

References

Citations

  1. "Release 4.0.20". 11 March 2024. Retrieved 22 March 2024.
  2. "Releases - apache/groovy" . Retrieved 2020-04-09 via GitHub.
  3. "Groovy Goodness: Default Groovy Script File Extensions".
  4. "Groovy 2.0 Performance compared to Java". 25 Aug 2012.
  5. "Java vs Groovy2.0 vs Scala Simple Performance Test". 10 Jul 2012. Archived from the original on 10 December 2012. Retrieved 7 October 2012.
  6. 1 2 "Groovy 2.4 And Grails 3.0 To Be Last Major Releases Under Pivotal Sponsorship". 19 Jan 2015.
  7. 1 2 "Groovy joins Apache Incubator". 11 Mar 2015.
  8. James Strachan (29 Aug 2003). "Groovy - the birth of a new dynamic language for the Java platform". Archived from the original on 1 September 2003.
  9. 1 2 "Java Community Process JSR 241".
  10. "Groovy wins first prize at JAX 2007 innovation award". 2007-04-26. Archived from the original on 2015-05-13. Retrieved 2012-10-07.
  11. "They say a lot can happen over a cup of coffee". Archived from the original on 2011-04-19. Retrieved 2012-10-07.
  12. "SpringSource Acquires Groovy and Grails company (G2One)". 11 Nov 2008.
  13. "VMWare Acquires SpringSource". 10 Aug 2009.
  14. "Tweet from James Strachan". November 24, 2016. Retrieved 2016-11-24.
  15. "Announcement on dev mailing list".
  16. "Release GROOVY_3_0_0 · apache/groovy". GitHub. Retrieved 2024-03-27.
  17. "Release GROOVY_4_0_0 · apache/groovy". GitHub. Retrieved 2024-03-27.
  18. König 2007, pg. 32
  19. "Groovy style and language feature guidelines for Java developers". Groovy.codehaus.org. Archived from the original on 2015-01-17. Retrieved 2015-01-22.
  20. "Groovy – Differences from Java". Groovy.codehaus.org. Archived from the original on 2009-03-17. Retrieved 2013-08-12.
  21. "What's new in Groovy 2.0?". 28 Jun 2012.
  22. König 2007, pp. 37-8
  23. König 2007, pp. 38-9
  24. König 2007, pp. 41-3
  25. "JN3525-MetaClasses". Archived from the original on 2012-10-01. Retrieved 2012-10-07.
  26. "Metaprogramming Techniques in Groovy and Grails". 11 Jun 2009.
  27. "Groovy - Closures". Archived from the original on 2012-05-22.
  28. 1 2 "Does groovy call partial application 'currying'", 10 Aug 2013
  29. "Groovy - Lazy Transformation". Archived from the original on 2012-10-08. Retrieved 2012-10-07.
  30. "Side Notes: Lazy lists in Groovy". 3 Feb 2011.
  31. "Groovy's Fold". 20 Jun 2011. Archived from the original on 13 February 2015. Retrieved 12 February 2015.
  32. "Functional Programming with Groovy". 5 Nov 2011.
  33. "Function programming in Groovy". Archived from the original on 2012-10-08. Retrieved 2012-10-07.
  34. "JsonBuilder". Archived from the original on 2012-10-02. Retrieved 2012-10-07.
  35. "Groovy Strings - Different ways of creating them". 26 Dec 2009.
  36. "Compile-time Metaprogramming - AST Transformations". Archived from the original on 2012-10-14. Retrieved 2012-10-07.
  37. King, Paul (2020). "A History of the Groovy Programming Language". Proc. ACM Program. Lang. 4: 53. doi: 10.1145/3386326 .
  38. "ScriptRunner Documentation".
  39. "ScriptRunner Press Release with adoption stats".
  40. "Groovy DSL for OFBiz business logic". Apache OFBiz Project Open Wiki.
  41. "Simple-methods examples using Groovy". Apache OFBiz Project Open Wiki.
  42. "Grails at LinkedIn" . Retrieved 2015-06-02.
  43. "Embedded Groovy Scripting". www.logicmonitor.com. Retrieved 2020-11-20.
  44. "Jenkins Pipeline".
  45. Rocher, Graeme (October 2, 2008). "Graeme Rocher's Blog: Sky.com relaunches written in Grails". Graeme Rocher's Blog. Retrieved 2015-06-02.
  46. Security Analysis of Emerging Smart Home Applications
  47. "Scripting and the Script Library | Scripting & Properties". www.soapui.org. Retrieved 2015-06-02.
  48. "Chapter 11. Groovy integration". docs.jboss.org. Retrieved 2015-06-02.
  49. "vCalc, the First ever Social Platform for the world of Math". 4 November 2014. Retrieved 2016-05-05.
  50. "Wired.Com" (PDF). www.springsource.org. Retrieved 2015-06-02.
  51. "XWiki SAS" (PDF). www.springsource.org. Retrieved 2015-06-02.
  52. "Grooscript Documentation". 12 Sep 2016. Archived from the original on 28 June 2017. Retrieved 4 July 2017.
  53. "Presentation at SpringOne/2GX on Grooscript". 13 Dec 2015.
  54. "Grooscript online conversions". 15 May 2017. Archived from the original on 9 July 2017. Retrieved 4 July 2017.

Sources