Jump to content

Apache Groovy

From Wikipedia, the free encyclopedia

This is an old revision of this page, as edited by Aptasii (talk | contribs) at 03:01, 10 November 2013 (moved JSR refs into history section). The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.

Groovy
Groovy-logo
ParadigmObject-oriented, imperative, scripting, functional
Designed byJames Strachan
DeveloperGuillaume LaForge
(Project Manager)
First appeared2003
Stable release
2.1.9 / October 29, 2013; 10 years ago (2013-10-29)
Typing disciplineDynamic, Static, Strong, Duck
PlatformJava Virtual Machine
OSCross-platform
LicenseApache License v2.0
Websitegroovy.codehaus.org
Influenced by
Java, Python, Ruby, Perl, Smalltalk, Objective-C

Groovy is an object-oriented programming language for the Java platform. It is a dynamic language with features similar to those of Python, Ruby, Perl, and Smalltalk. It can be used as a scripting language for the Java Platform, is dynamically compiled to Java Virtual Machine (JVM) bytecode, and interoperates with other Java code and libraries. Groovy uses a Java-like curly-bracket syntax. Most Java code is also syntactically valid Groovy.

Groovy 1.0 was released on January 2, 2007, and Groovy 2.0 in July, 2012. Groovy 3.0 is planned for release in early 2014, with support for Java 8 features and a new Meta Object Protocol.[1] Since version 2, Groovy can also be compiled statically, offering type inference and performance close to, or even greater than, Java's.[2][3] Groovy is backed by VMware, after its acquisition of SpringSource, which acquired G2One, the Groovy and Grails company.

History

James Strachan first talked about the development of Groovy in his blog in August 2003.[4] Several versions were released between 2004 and 2006. After the JCP standardization process began, the version numbering was 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 rebranded as Groovy 1.5 as a reflection of the many changes that were made.

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

In November 2008, SpringSource acquired the Groovy and Grails company (G2One).[7] In August 2009, SpringSource was acquired by VMWare[8]

In July 2009, Strachan wrote on his blog, "I can honestly say if someone had shown me the Programming in Scala book by Martin Odersky, Lex Spoon & Bill Venners back in 2003 I'd probably have never created Groovy."[9] Strachan had left the project silently a year before the Groovy 1.0 release in 2007.[citation needed]

In March 2004, Groovy had been submitted to the Java Community Process as JSR 241 [10]and accepted by ballot. After 8 years of inactivity, the Spec Lead changed its status to dormant in April 2012.

On July 2, 2012, Groovy 2.0 was released, which, among other new features, added static compilation and a static type checker to Groovy.

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 require all the elements that Java requires.[11] This makes it possible for Java programmers to gradually learn Groovy by starting with familiar Java syntax before acquiring more Groovy idioms.[12]

Groovy features not available in Java include both static and dynamic typing (with the def keyword), closures, operator overloading, native syntax for lists and associative arrays (maps), native support for regular expressions, polymorphic iteration, expressions embedded inside strings, additional helper methods, and the safe navigation operator "?." to automatically check for nulls (for example, "variable?.method()", or "variable?.field").[13]

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 lib, type checking, static compilation, Project Coin syntax enhancements, multicatch blocks and ongoing performance enhancements using JDK7's invoke dynamic instruction.[14]

Groovy's syntax can be made far more compact than Java. For example, a declaration in Standard Java 5+ such as:

 for (String it : new String[] {"Rod", "Carlos", "Chris"})
     if (it.length() <= 4)
         System.out.println(it);

can be expressed in Groovy as:

 ["Rod", "Carlos", "Chris"].findAll{it.size() <= 4}.each{println it}

Groovy provides native support for various markup languages such as XML and HTML, accomplished via an inline 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, is a class with a main method, or is a Runnable or GroovyTestCase. A Groovy script is fully parsed, compiled, and generated before execution (similar to Perl and Ruby). (This occurs under the hood, and the compiled version is not saved as an artifact of the process.)[15]

GroovyBeans / Properties

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

class AGroovyBean {
  String color
}

def myGroovyBean = new AGroovyBean()

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

myGroovyBean.color = 'pewter'
assert myGroovyBean.color == 'pewter'

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

def movieList = ['Dersu Uzala', 'Ran', 'Seven Samurai']  //looks like an array, but is a list
assert movieList[2] == 'Seven Samurai'
movieList[3] = 'Casablanca'  //adds an element to the list
assert movieList.size() == 4

def monthMap = [ 'January' : 31, 'February' : 28, 'March' : 31 ]  //declares a map
assert monthMap['March'] == 31  //accesses an entry
monthMap['April'] = 30  //adds an entry to the map
assert monthMap.size() == 4

Metaprogramming

Groovy offers support for metaprogramming through ExpandoMetaClass, Extension Modules (only in Groovy 2), Categories and DelegatingMetaClass.[18]

ExpandoMetaClass offers a DSL to express easily the changes in the class, similar to Ruby's open class concept:

Number.metaClass {
  sqrt = { Math.sqrt(delegate) }
}

assert 9.sqrt() == 3
assert 4.sqrt() == 2

Groovy's changes in code through metaprogramming are not visible in Java, since each attribute/method invocation in Groovy goes through the metaclass registry. To access a code changed in Groovy from Java, it needs to get through 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:

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

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

Dot and parentheses

Groovy's syntax permits omitting parentheses and dots in some situations. The following groovy code (from Guillaume LaForge's DSL slideshare):

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

can be written as:

take coffee with sugar, milk and liquor

Enabling the development of Domain-specific languages (DSLs) which look like plain English.

Functional programming

Although Groovy is mostly an objected-oriented language, it also offers functional 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".[20] Groovy's closures support free variables, i.e. variables which have not been explicitly passed as a parameter to it, but exist in its declaration context, partial application (which it terms 'currying'[21]), 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]

/* 
 * 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 }
 */
def odds = list.findAll { it % 2 }

assert odds == [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 implementation
def operations = {
  declare 5
  sum 4
  divide 3
  print
}

/* 
 * This class will handle the operations that can be used in the closure above. We could declare 
 * another class having the same methods, but using, for example, webservice operations in the
 * calculations.
 */
class Expression {
  BigDecimal value

  /* 
   * Though an Integer is passed as a parameter, it is coerced into a BigDecimal, as we defined. 
   * If the class had a 'declare(Integer value)' method, it would be used instead.
   */
  def declare(BigDecimal value) {
    this.value = value
  }
  
  def sum(BigDecimal valueToAdd) {
    this.value += valueToAdd
  }
  
  def divide(BigDecimal dividend) {
    this.value /= dividend
  }
  
  def propertyMissing(String property) {
    if (property == "print") println value
  }
}

// Here we define who is going to respond the expressions in the block
operations.delegate = new Expression()
operations()

Curry

Usually called partial application,[21] this Groovy feature allows closures parameters to be set to a default parameters in any of its arguments, creating a new closure with the bound value. If you supply one argument to the curry() method you will fix the first argument. If you supply N arguments you will fix arguments 1..N.

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')
// def prependHello = joinTwoWordsWithSymbol.curry(' ', 'Hello')
assert prependHello('World') == 'Hello World'

Curry can also be used in the reversed direction (fixing arguments N to N-1) using rcurry.

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

Groovy also supports lazy evaluation,[22][23] reduce/fold,[24] infinite structures and immutability,[25] among others.[26]

XML and JSON Processing

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

<languages>
  <language year="1995">
    <name>java</name>
    <paradigm>Object oriented</paradigm>
    <typing>Static</typing>
  </language>
  <language year="1995">
    <name>ruby</name>
    <paradigm>Object oriented, Functional</paradigm>
    <typing>Dynamic, duck typing</typing>
  </language>  
  <language year="2003">
    <name>groovy</name>
    <paradigm>Object oriented, Functional</paradigm>
    <typing>Dynamic, Static, Duck typing</typing>
  </language>
</languages>

Can be generated through the following Groovy code:

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 "object oriented, functional"
    typing "dynamic, duck typing"
  }
  language (year: 2003) {
    name "groovy"
    paradigm "object oriented, functional"
    typing "dynamic, static, duck typing"
  }
}

And also can be processed in a streaming way through StreamingMarkupBuilder. To change the implementation to JSON, we can just swap the MarkupBuilder to JsonBuilder.[27]

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

def languages = new XmlSlurper().parseText writer.toString()

// Here we employ groovy's regex syntax for a matcher (=~) which will be coerced to a boolean value: 
// either true if the value contains our string, or false otherwise.
def functional = languages.language.findAll { it.paradigm =~ "functional" }
assert functional.collect { it.name } == ["ruby", "groovy"]

String interpolation

In Java, when creating a string by joining a string literal to an expression, it's necessary to end the literal and use the concatenation operator (+). In Groovy we can interpolate the string with variables and expressions by using GStrings:[28]

BigDecimal account = 10.0
def text = "Your account shows currently a balance of $account"
assert text == "Your 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:

BigDecimal minus = 4.0
text = "Your account shows currently a balance of ${account - minus}"
assert text == "Your account shows currently a balance of 6.0"

// Without the brackets to isolate the expression, we would have the following:
text = "Your account shows currently a balance of $account - minus"
assert text == "Your account shows currently a balance of 10.0 - minus"

Expression evaluation can be deferred by employing arrow syntax:

BigDecimal tax = 0.15
text = "Your 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:

assert text == "Your account shows currently a balance of 9.000"

AST (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.".[29]

Examples of ASTs in Groovy are:

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

Among others.

Adoption

IDE support

Many integrated development environments and text editors support Groovy:

See also

References

  • König, Dierk (2006). Groovy in Action. Manning. ISBN 1-932394-84-2. {{cite book}}: Unknown parameter |coauthors= ignored (|author= suggested) (help)
  • König, Dierk (2011). Groovy in Action, Second Edition. Manning. ISBN 978-1-935182-44-3. {{cite book}}: Unknown parameter |coauthors= ignored (|author= suggested) (help)
  • Barclay, Kenneth. Groovy Programming: An Introduction for Java Developers. ISBN 978-0-12-372507-3. {{cite book}}: Unknown parameter |coauthors= ignored (|author= suggested) (help)
  • Davis, Scott. Groovy Recipes: Greasing the Wheels of Java. ISBN 978-0-9787392-9-4.
  • Subramaniam, Venkat. Programming Groovy: Dynamic Productivity for the Java Developer. ISBN 978-1-934356-09-8.

Notes

  1. ^ "Roadmap".
  2. ^ "Groovy 2.0 Performance compared to Java". 25 Aug. 2012. {{cite web}}: Check date values in: |date= (help)
  3. ^ "Java vs Groovy2.0 vs Scala Simple Performance Test". 10 Jul. 2012. {{cite web}}: Check date values in: |date= (help)
  4. ^ James Strachan (29 Aug. 2003). "Groovy - the birth of a new dynamic language for the Java platform". {{cite web}}: Check date values in: |date= (help)
  5. ^ "Groovy wins first prize at JAX 2007 innovation award". 2007-04-26.
  6. ^ "They say a lot can happen over a cup of coffee".
  7. ^ "SpringSource Acquires Groovy and Grails company (G2One)". 11 Nov. 2008. {{cite web}}: Check date values in: |date= (help)
  8. ^ "VMWare Acquires SpringSource". 10 Aug. 2009. {{cite web}}: Check date values in: |date= (help)
  9. ^ "Scala as the long term replacement for java/javac?". July 6, 2009. Retrieved 2009-12-29.
  10. ^ "Java Community Process JSR 241".
  11. ^ König 2007, pg. 32
  12. ^ Q & A with Ed Povazan on Groovy, Dynamic Languages for Java, the State-of-the Eclipse Groovy Plugin and More (Part I)[dead link]
  13. ^ "Groovy - Differences from Java". Groovy.codehaus.org. Retrieved 2013-08-12.
  14. ^ "What's new in Groovy 2.0?". 28 Jun. 2012. {{cite web}}: Check date values in: |date= (help)
  15. ^ König 2007, pp. 37-8
  16. ^ König 2007, pp. 38-9
  17. ^ König 2007, pp. 41-3
  18. ^ "JN3525-MetaClasses".
  19. ^ "Metaprogramming Techniques in Groovy and Grails". 11 Jun. 2009. {{cite web}}: Check date values in: |date= (help)
  20. ^ "Groovy - Closures".
  21. ^ a b "Does groovy call partial application 'currying'". 10 Aug 2013
  22. ^ "Groovy - Lazy Transformation".
  23. ^ "Side Notes: Lazy lists in Groovy". 3 Feb. 2011. {{cite web}}: Check date values in: |date= (help)
  24. ^ "Groovy's Fold". 20 Jun. 2011. {{cite web}}: Check date values in: |date= (help)
  25. ^ "Functional Programming with Groovy". 5 Nov. 2011. {{cite web}}: Check date values in: |date= (help)
  26. ^ "Function programming in Groovy".
  27. ^ "JsonBuilder".
  28. ^ "Groovy Strings - Different ways of creating them". 26 Dev. 2009. {{cite web}}: Check date values in: |date= (help)
  29. ^ "Compile-time Metaprogramming - AST Transformations".
  30. ^ "Groovy Finance". 27 May 2009.
  31. ^ "The Gr8 Conference: Grid computing and computational finance". 20 May 2009.
  32. ^ "Job Trends for Groovy, Scala and Clojure". 07 Oct. 2012. {{cite web}}: Check date values in: |date= (help)

External links