Jump to content

Apache Groovy

From Alfawiki
Apache Groovy
Company typeOpen source programming language
IndustrySoftware development
FoundedJanuary 2, 2007; 19 years ago (2007-01-02)
Headquarters
N/A
ProductsProgramming language
OwnerApache Software Foundation
Websitegroovy-lang.org

Apache Groovy is an object-oriented programming language compatible with Java syntax, designed for the Java platform. It accommodates both static and dynamic typing paradigms and incorporates features reminiscent of Python, Ruby, and Smalltalk. Functioning as both a scripting and programming language for Java, Groovy compiles into Java virtual machine (JVM) bytecode and integrates smoothly with existing Java libraries and codebases. Its syntax employs curly braces similar to Java’s and includes support for closures, multiline strings, and string interpolation. A significant aspect of its flexibility arises from AST transformations activated by annotations.

The initial release, Groovy 1.0, debuted on January 2, 2007. The subsequent major update, Groovy 2.0, arrived in July 2012, introducing static compilation with type inference that brought performance close to native Java. Groovy 2.4 was the final major version under the stewardship of Pivotal Software, concluding in March 2015. Afterward, project oversight transitioned to a Project Management Committee within the Apache Software Foundation.

History

Development of Groovy was first publicized by James Strachan via his blog in August 2003. The language was submitted to the Java Community Process (JCP) as JSR 241 in March 2004 and subsequently approved. Multiple versions were released between 2004 and 2006, culminating in the official 1.0 launch on January 2, 2007. By December 2007, Groovy had advanced to version 1.5, featuring considerable improvements.

At JAX 2007, Groovy received the innovation award’s top honor, while Grails—a web framework built on Groovy—secured second place at JAX 2008.

In November 2008, SpringSource acquired G2One, the company responsible for Groovy and Grails. This was followed by VMware’s acquisition of SpringSource in August 2009.

JSR 241 was declared dormant in April 2012 after a period of inactivity. Although Strachan had departed from the project prior to the Groovy 1.0 release, he reaffirmed his support for Groovy and related initiatives as late as 2016.

Groovy 2.0 was officially released on July 2, 2012, bringing in features such as static compilation and type checking.

Following the spin-off of Pivotal Software from EMC and VMware in April 2013, Groovy and Grails became part of Pivotal’s offerings. Pivotal ended its sponsorship in April 2015; concurrently, governance shifted to an Apache Software Foundation Project Management Committee (PMC). In November 2015, Groovy graduated from Apache’s incubator program to become a top-level project.

Groovy 3.0 was launched on February 7, 2020, with version 4.0 following on January 25, 2022.

Features

Most Java source files are also valid Groovy scripts. Although closely related, Groovy code tends to be more concise by eliminating many syntactic requirements mandatory in Java. This design enables Java developers to adopt Groovy incrementally—starting with familiar constructs before embracing Groovy-specific idioms.

Groovy introduces capabilities beyond those available in Java, such as support for both static and dynamic typing using def, operator overloading, native list and map literals for collections, integrated regular expression handling, polymorphic iteration mechanisms, string interpolation techniques, additional utility methods, and a safe navigation operator ?. that prevents null pointer exceptions (e.g., variable?.method()).

Starting with version 2, modularization allows distribution of only essential jar files to minimize library size. This release also incorporated type checking, static compilation options, Project Coin syntax enhancements from Java, multicatch exception blocks, and performance optimizations leveraging the invokedynamic bytecode instruction introduced in Java 7.

Groovy provides native support for markup languages including XML and HTML through inline DOM syntax constructs. This facilitates succinct creation and manipulation of diverse data formats using consistent programming patterns.

Unlike Java source files—which require explicit compilation—Groovy files containing executable code outside class definitions or including a main method or implementations of Runnable or GroovyTestCase can be run directly as scripts. These scripts undergo full parsing and compilation at runtime without generating persistent compiled files.

GroovyBeans and Property Handling

In Groovy, GroovyBeans serve as the equivalent of JavaBeans, featuring automatic generation of accessor and mutator methods. For instance, in the example below, methods like setColor(String color) and getColor() are implicitly created. Direct access to the color attribute actually invokes these automatically generated methods.

<syntaxhighlight lang="groovy"> class AGroovyBean {

 String color

}

def myGroovyBean = new AGroovyBean()

myGroovyBean.setColor('baby blue') assert myGroovyBean.getColor() == 'baby blue'

myGroovyBean.color = 'pewter' assert myGroovyBean.color == 'pewter' </syntaxhighlight>

Groovy offers streamlined syntax for working with lists and maps, providing functionality similar to Java arrays:

<syntaxhighlight lang="groovy"> def movieList = ['Dersu Uzala', 'Ran', 'Seven Samurai'] // List declaration assert movieList[2] == 'Seven Samurai' movieList[3] = 'Casablanca' // Adding an element assert movieList.size() == 4

def monthMap = [ 'January' : 31, 'February' : 28, 'March' : 31 ] // Map declaration assert monthMap['March'] == 31 monthMap['April'] = 30 // Adding a key-value pair assert monthMap.size() == 4 </syntaxhighlight>

Extending Prototypes

Groovy facilitates prototype extension through mechanisms such as ExpandoMetaClass, Extension Modules (available since Groovy 2), Objective-C-style Categories, and DelegatingMetaClass.

With ExpandoMetaClass, developers can effortlessly perform DSL-style modifications to classes, similar to Ruby's open class system:

<syntaxhighlight lang="groovy"> Number.metaClass {

 sqrt = { Math.sqrt(delegate) }

}

assert 9.sqrt() == 3 assert 4.sqrt() == 2 </syntaxhighlight>

These metaprogramming alterations remain hidden from Java code unless accessed via Groovy’s metaclass infrastructure.

Furthermore, Groovy allows overriding methods such as getProperty() and propertyMissing(), enabling simplified aspect-oriented interception of object interactions. The following example demonstrates adding a hex property to java.lang.String:

<syntaxhighlight lang="groovy"> enum Color {

 BLACK('#000000'), WHITE('#FFFFFF'), RED('#FF0000'), BLUE('#0000FF')
 String hex
 Color(String hex) { this.hex = hex }

}

String.metaClass.getProperty = { String property ->

 def stringColor = delegate
 if (property == 'hex') {
   Color.values().find { it.name().equalsIgnoreCase stringColor }?.hex
 }

}

assert "WHITE".hex == "#FFFFFF" assert "BLUE".hex == "#0000FF" assert "BLACK".hex == "#000000" assert "GREEN".hex == null </syntaxhighlight>

The Grails framework extensively uses metaprogramming techniques for features like GORM dynamic finders, exemplified by calls such as User.findByName('Josh').

Omission of Dots and Parentheses

Groovy's syntax permits leaving out parentheses and dots in certain expressions. For example,

<syntaxhighlight lang="groovy"> take(coffee).with(sugar, milk).and(liquor) </syntaxhighlight>

can be rewritten more succinctly as

<syntaxhighlight lang="groovy"> take coffee with sugar, milk and liquor </syntaxhighlight>

This flexibility supports the development of domain-specific languages (DSLs) that read much like natural English.

Functional programming

Although Groovy is mainly an object-oriented language, it also integrates features from functional programming.

Closures

In Groovy, closures function similarly to "method references," allowing execution to be postponed. They accommodate free variables, partial application (referred to as 'currying'), delegation, and parameters that can be either typed or untyped.

When working with typed Collections, the type of the closure's parameter can be automatically determined:

<syntaxhighlight lang="groovy"> list = [1, 2, 3, 4, 5, 6, 7, 8, 9]

def odds = list.findAll { it % 2 }

assert odds == [1, 3, 5, 7, 9] </syntaxhighlight>

Closure bodies may include expressions without immediate execution; their behavior is later defined through delegation:

<syntaxhighlight lang="groovy"> // Expressions defined without direct implementation def operations = {

 declare 5
 sum 4
 divide 3
 print

} </syntaxhighlight> <syntaxhighlight lang="groovy"> class Expression {

 BigDecimal value
 def declare(BigDecimal value) {
   this.value = value
 }
 
 def sum(BigDecimal valueToAdd) {
   this.value += valueToAdd
 }
 
 def divide(BigDecimal divisor) {
   this.value /= divisor
 }
 
 def propertyMissing(String property) {
   if (property == "print") println value
 }

} </syntaxhighlight> <syntaxhighlight lang="groovy"> // Delegating closure execution to handle expressions operations.delegate = new Expression() operations() </syntaxhighlight>

Curry

This Groovy capability, known as partial application, enables presetting certain closure parameters with default values, thereby generating new closures with fixed arguments. The curry() method binds arguments starting from the first parameter, whereas rcurry() binds arguments beginning from the last.

<syntaxhighlight lang="groovy"> def joinTwoWordsWithSymbol = { symbol, first, second -> first + symbol + second } assert joinTwoWordsWithSymbol('#', 'Hello', 'World') == 'Hello#World'

def concatWords = joinTwoWordsWithSymbol.curry(' ') assert concatWords('Hello', 'World') == 'Hello World'

def prependHello = concatWords.curry('Hello') assert prependHello('World') == 'Hello World' </syntaxhighlight>

<syntaxhighlight lang="groovy"> def power = { BigDecimal value, BigDecimal power -> value**power }

def square = power.rcurry(2) def cube = power.rcurry(3)

assert power(2, 2) == 4 assert square(4) == 16 assert cube(3) == 27 </syntaxhighlight>

Groovy further enhances functional programming by supporting lazy evaluation, reduce/fold, infinite data structures, and immutability.

JSON and XML processing

Groovy employs the Builder pattern to facilitate JSON and XML data manipulation, making it easier to construct complex data formats. For instance, the following XML structure:

<syntaxhighlight lang="xml"> <languages>

 <language year="1995">
   <name>Java</name>
   <paradigm>object oriented</paradigm>
   <typing>static</typing>
 </language>
 <language year="1995">
   <name>Ruby</name>
   <paradigm>functional, object oriented</paradigm>
   <typing>duck typing, dynamic</typing>
 </language>
 <language year="2003">
   <name>Groovy</name>
   <paradigm>functional, object oriented</paradigm>
   <typing>duck typing, dynamic, static</typing>
 </language>

</languages> </syntaxhighlight>

can be programmatically generated using:

<syntaxhighlight lang="groovy"> def writer = new StringWriter() def builder = new groovy.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"
 }

} </syntaxhighlight>

For streaming scenarios, Groovy offers StreamingMarkupBuilder, and switching output formats to JSON simply requires substituting MarkupBuilder with JsonBuilder.

Parsing and filtering XML content is straightforward using Groovy’s collection methods such as findAll. For example, filtering languages with a functional paradigm can be done as follows:

<syntaxhighlight lang="groovy"> def languages = new XmlSlurper().parseText(writer.toString()) def functional = languages.language.findAll { it.paradigm =~ "functional" } assert functional.collect { it.name } == ["Groovy", "Ruby"] </syntaxhighlight>

String interpolation

In Groovy, variables and expressions can be embedded within strings through the use of GStrings:

<syntaxhighlight lang="groovy"> BigDecimal account = 10.0 def text = "The account shows currently a balance of $account" assert text == "The account shows currently a balance of 10.0" </syntaxhighlight>

To include variables or expressions inside GStrings, double quotes are required. When embedding complex expressions, curly braces must enclose them to ensure correct parsing:

<syntaxhighlight lang="groovy"> BigDecimal minus = 4.0 text = "The account shows currently a balance of ${account - minus}" assert text == "The account shows currently a balance of 6.0"

// Without using braces: text = "The account shows currently a balance of $account - minus" assert text == "The account shows currently a balance of 10.0 - minus" </syntaxhighlight>

Deferred evaluation of expressions is possible with arrow notation, which binds the variables only at the moment the string is evaluated:

<syntaxhighlight lang="groovy"> BigDecimal tax = 0.15 text = "The account shows currently a balance of ${->account - account*tax}" tax = 0.10

assert text == "The account shows currently a balance of 9.000" </syntaxhighlight>

Abstract syntax tree transformation

During compilation, Groovy converts source code into an Abstract Syntax Tree (AST), allowing developers to alter the code structure prior to bytecode generation. AST Transformations facilitate compile-time metaprogramming, offering enhanced flexibility without impacting runtime efficiency.

Prominent AST transformations include:

  • Category and Mixin transformation
  • Immutable AST Macro
  • Newify transformation
  • Singleton transformation

The Spock testing framework utilizes AST transformations to enable customized test syntax by translating it into valid Groovy code:

<syntaxhighlight lang="groovy"> def "maximum of #a and #b is #c" () {

 expect:
 Math.max(a, b) == c
 where:
 a | b || c
 3 | 5 || 5
 7 | 0 || 7
 0 | 0 || 0

} </syntaxhighlight>

Traits

According to Groovy's documentation, Traits are language constructs that allow for behavior composition, dynamic interface implementation, method overriding, and compatibility with static type checking. Traits resemble interfaces but provide default method implementations and can maintain state.

A trait is defined using the trait keyword:

<syntaxhighlight lang="groovy"> trait FlyingAbility {

 String fly() { "I'm flying!" }

} </syntaxhighlight>

Classes can incorporate traits via the implements keyword:

<syntaxhighlight lang="groovy"> class Bird implements FlyingAbility {} def bird = new Bird() assert bird.fly() == "I'm flying!" </syntaxhighlight>

Traits facilitate various functionalities ranging from straightforward composition to supporting testing frameworks.

Adoption

Groovy has been embraced across multiple major enterprises and technology domains:

  • Apache OFBiz, an open-source ERP solution, integrates Groovy for implementing business logic.
  • Eucalyptus, a platform for cloud management, makes extensive use of Groovy.
  • Gradle, a widely adopted build automation system, is developed using Groovy.
  • LinkedIn applies Groovy and Grails in certain subsystems.
  • Jenkins offers a Pipeline plugin that enables writing build scripts in Groovy.
  • Sky.com employs Groovy and Grails to support its large-scale online media services.
  • SmartThings, an IoT platform for smart homes, utilizes a security-hardened subset of Groovy.
  • SoapUI provides Groovy scripting capabilities for web service testing.
  • Wired.com uses Groovy and Grails in its Product Reviews section.
  • XWiki SAS incorporates Groovy as the scripting language within its collaborative platform.

IDE support

Numerous integrated development environments (IDEs) and text editors offer compatibility with Groovy, among them:

Dialects

One notable alternative Groovy variant is:

  • Grooscript, which translates Groovy code into JavaScript. Although it has certain constraints relative to Apache Groovy, it facilitates the use of domain classes across both client and server environments. It also supports plugins for Grails 3.0 and offers online tools for code conversion.

See also

External links