<<

#15

CONTENTS INCLUDE:

n Groovy/Java Integration n Language Elements n Operators

n Groovy Collective Datatypes n Meta Programming n Hot Tips and more... By Dierk König Visit refcardz.com

GroovyShell ABOUT GROOVY Use groovy.util.GroovyShell for more flexibility in the Binding and optional pre-parsing: Groovy is a dynamic language for the Java™ Virtual Machine (JVM). It shines with full object-orientation, scriptability, optional GroovyShell shell= new GroovyShell(); typing, operator customization, lexical declarations for the Script scpt = shell.parse("y = x*x"); most common data types, advanced concepts like closures and Binding binding = new Binding(); ranges, compact property syntax and seamless Java™ integra- scpt.setBinding(binding); tion. This reference card provides exactly the kind of information binding.setVariable("x", 2); you are likely to look up when programming Groovy. scpt.run(); (int) binding.getVariable("y"); STARTING GROOVY Chapter 11 of Groovy in Action has more details about Install Groovy from http://groovy.codehaus.org and you will integration options. Here is an overview: have the following commands available: Integration option Features/properties

Command Purpose Eval/GroovyShell for small expressions + reloading, security

groovy Execute Groovy code GroovyScriptEngine for dependent scripts + reloading groovyc Compile Groovy code - classes, security

groovysh Open Groovy shell GroovyClassLoader the catch-all solution + reloading, security

groovyConsole Open Groovy UI console Spring Beans integrates with Spring + reloading

java2groovy Migration helper JSR-223 easy language switch but limited in API - reloading, security requires Java 6 The groovy command comes with -h and --help options to show all options and required arguments. Typical usages are:

www.dzone.com Get More Refcardz! Execute file MyScript.groovy LANGUAGE ELEMENTS groovy MyScript Evaluate (e) on the command line Classes & Scripts groovy -e "print 12.5*Math.PI" A Groovy class declaration looks like in Java. Default visibility modifier is public Print (p) for each line of input echo 12.5 | groovy -pe class MyClass { "line.toDouble() * Math.PI" void myMethod(String argument) { Inline edit (i) filedata.txt by reversing each line and save a backup } groovy -i.bak –pe } → "line.reverse()" data.txt

GROOVY/JAVA INTEGRATION Get More Refcardz (They’re free!) From Groovy, you can call any Java code like you would do from Java. It’s identical. n Authoritative content n Designed for developers From Java, you can call Groovy code in the following ways. n Written by top experts Note that you need to have the groovy-all.jar in your classpath. n Latest tools & technologies Cross-compilation n Hot tips & examples Use groovyc, the ant task or your IDE integration to n compile your groovy code together with your Java code. This Bonus content online enables you to use your Groovy code as if it was written in Java. n New issue every 1-2 weeks Eval Subscribe Now for FREE! Use class groovy.util.Eval for evaluating simple code that is Refcardz.com captured in a Java String: (int) Eval.xyz(1,2,3,"x+y+z"); Groovy

DZone, Inc. | www.dzone.com 2 Groovy tech facts at your fingertips

Language Elements (Classes and Scripts), continued Customizable Operators, continued

When a .groovy file or any other source of Groovy code Operator Method contains code that is not enclosed in a class declaration, a-- a.previous() --a then this code is considered a Script, e.g. a**b a.power(b) println "Hello World" a|b a.or(b) Scripts differ from classes in that they have a Binding that a&b a.and(b) serves as a container for undeclared references (that are not a^b a.xor(b) allowed in classes). ~a ~a a.bitwiseNegate() // sometimes referred to as negate | +a a.positive() // sometimes referred to as unaryMinus println text // expected in Binding | -a a.negative() // sometimes referred to as unaryPlus result = 1 // is put into Binding a[b] a.getAt(b) a[b] = c a.putAt(b, c) Optional Typing a << b a.leftShift(b) Static types can be used like in Java and will be obeyed a >> b a.rightShift(b) at runtime. Dynamic typing is used by replacing the type a >>> b a.rightShiftUnsigned(b) declaration with the def keyword. Formal parameters to switch(a){ b.isCase(a) case b: // b is a classifier method and closure declarations can even omit the def. } [a].grep(b) Properties if(a in b) Properties are declared as fields with the default visibility a == b a.equals(b) modifier, no matter what type is used. a != b ! a.equals(b) a <=> b a.compareTo(b) class MyClass { a > b a.compareTo(b) > 0 String stringProp def dynamicProp a >= b a.compareTo(b) >= 0 } a < b a.compareTo(b) < 0 a <= b a.compareTo(b) <= 0 Java-style getters and setters are compiled into the bytecode a as B a.asType(B) automatically. Properties are referred to like Actively look for opportunities to implement println obj.stringProp // getter Hot operator methods in your own Groovy class. obj.dynamicProp = 1 // setter Tip This often leads to more expressive code. regardless of whether obj was written in Java or Groovy, the Typical candidates are ==, <=>, +, -, <<, respective getters/setters will be called. and isCase(). See also Ranges. Multimethods Methods are dispatched by the runtime type, allowing code like Special Operators class Pers { Operator Meaning Name String name a ? b : c if (a) b else c ternary if boolean equals(Pers other) { a ?: b a ? a : b Elvis name == other.name a?.b a==null ? a : a.b null safe } a(*list) a(list[0], list[1], ...) spread } assert new Pers(name:'x') == new Pers(name:'x') list*.a() [list[0].a(), list[1].a() ...] spread-dot assert new Pers(name:'x') != 1 a.&b reference to method b in method closure object a as closure a.@field direct field access dot-at OPERATORS SIMPLE DATATYPES Customizable Operators Operators can be customized by implementing/ overriding Numbers the respective method. All Groovy numbers are objects, not primitive types. Literal declarations are: Operator Method

a + b a.plus(b) Type Example literals

a – b a.minus(b) java.lang.Integer 15, 0x1234ffff

a * b a.multiply(b) java.lang.Long 100L, 100l java.lang.Float 1.23f, 4.56F a / b a.div(b) java.lang.Double 1.23d, 4.56D a % b a.mod(b) java.math.BigInteger 123g, 456G a++ a.next() ++a java.math.BigDecimal 1.23, 4.56, 1.4E4, 2.8e4, 1.23g, 1.23G

DZone, Inc. | www.dzone.com 3 Groovy tech facts at your fingertips

Simple Datatypes (Numbers), continued Regular Expressions, continued Coercion rules for math operations are explained in Groovy Symbol Meaning in Action, chapter 3. Some examples to remember are: . any character ^ start of line (or start of document, when in single-line mode) Expression Result type $ end of line (or end of document, when in single-line mode) 1f * 2f Double \ digit character 1f / 2f Double \D any character except digits (Byte)1 + (Byte)2 Integer \s whitespace character 1 * 2L Long \S any character except whitespace 1 / 2 BigDecimal (0.5) \w word character (int)(1/2) Integer (0) \W any character except word characters 1.intdiv(2) Integer (0) \b word boundary Integer.MAX_VALUE+1 Integer () grouping 2**31 Integer (x|y) x or y as in (Groovy|Java|Ruby) 2**33 Long \1 backmatch to group one, e.g. find doubled characters with (.)\1 2**3.5 Double x* zero or more occurrences of x. 2G + 1G BigInteger x+ one or more occurrences of x. 2.5G + 1G BigDecimal x? zero or one occurrence of x. 1.5G == 1.5F Boolean (true) x{m,n} at least “m” and at most “n” occurrences of x. 1.1G == 1.1F Boolean (false) x{m} exactly “m” occurrences of x. [a-f] character class containing the characters 'a', 'b', 'c', 'd', 'e', 'f' Strings [^a] character class containing any character except 'a' 'literal String' (?is:x) switches mode when evaluating x; i turns on ignoreCase, s single-line mode '''literal (?=regex) positive lookahead multiline String''' (?<=text) positive lookbehind def lang = 'Groovy' "GString for $lang" "$lang has ${lang.size()} chars" COLLECTIVE DATATYPES """multiline GString with Ranges late eval at ${-> new Date()}""" Ranges appear inclusively like 0..10 or half-exclusively like Placeholders in GStrings are dereferenced at declaration time 0..<10. They are often enclosed in parentheses since the but their text representation is queried at GString String range operator has low precedence. conversion time. assert (0..10).contains(5) /String with unescaped \ included/ assert (0.0..10.0).containsWithinBounds(3.5) Regular Expressions for (item in 0..10) { println item } for (item in 10..0) { println item } The regex find operator =~ (0..<10).each { println it } The regex match operator ==~ Integer ranges are often used for selecting sublists. Range The regex Pattern operator ~String boundaries can be of any type that definesprevious() , next() and Examples: implements Comparable. Notable examples are String and Date. def twister = 'she sells sea shells' // contains word 'she' Lists assert twister =~ 'she' Lists look like arrays but are of type java.util.List plus new methods. // starts with 'she' and ends with 'shells' [1,2,3,4] == (1..4) assert twister ==~ /she.*shells/ [1,2,3] + [1] == [1,2,3,1] // same precompiled [1,2,3] << 1 == [1,2,3,1] def pattern = ~/she.*shells/ [1,2,3,1] - [1] == [2,3] assert pattern.matcher(twister).matches() [1,2,3] * 2 == [1,2,3,1,2,3] [1,[2,3]].flatten() == [1,2,3] // matches are iterable [1,2,3].reverse() == [3,2,1] // words that start with 'sh' [1,2,3].disjoint([4,5,6]) == true def shwords = (twister =~ /\bsh\w*/).collect{it}.join(' ') [1,2,3].intersect([4,3,1]) == [3,1] assert shwords == 'she shells' [1,2,3].collect{ it+3 } == [4,5,6] [1,2,3,1].unique().size() == 3 // replace through logic [1,2,3,1].count(1) == 2 assert twister.replaceAll(/\w+/){ [1,2,3,4].min() == 1 it.size() [1,2,3,4].max() == 4 } == '3 5 3 6' [1,2,3,4].sum() == 10 [4,2,1,3].sort() == [1,2,3,4] // regex groups to closure params [4,2,1,3].findAll{it%2 == 0} == [4,2] // find words with same start and end def anims=['cat','kangaroo','koala'] def matcher = (twister =~ /(\w)(\w+)\1/) anims[2] == 'koala' matcher.each { full, first, rest -> def kanims = anims[1..2] assert full in ['sells','shells'] anims.findAll{it =~ /k.*/} ==kanims assert first == 's' anims.find{ it =~ /k.*/} ==kanims[0] } anims.grep(~/k.*/) ==kanims →

DZone, Inc. | www.dzone.com 4 Groovy tech facts at your fingertips

Collective Datatypes, continued CLOSURES Lists The sort() method is often used and comes in three flavors: Closures capture a piece of logic and the enclosing scope. They are first-class objects and can receive messages, can Sort call Usage col.sort() natural sort for comparable objects be returned from method calls, stored in fields, and used as col.sort { applying the closure to each item before comparing arguments to a method call. it.propname the results } Use in method parameter col.sort { a,b -> closure defines a comparator for each comparison a <=> b def forEach(int i, Closure yield){ } for (x in 1..i) yield(x) Lists can also be indexed with negative indexes and } reversed ranges. Use as last method argument def list = [0,1,2] forEach(3) { num -> println num } assert list[-1] == 2 assert list[-1..0] == list.reverse() Construct and assign to local variable assert list == [list.head()] + list.tail() def squareIt = { println it * it} Sublist assignments can make a list grow or shrink and lists forEach(3, squareIt) can contain varying data types. Bind leftmost closure param to fixed argument list[1..2] = ['x','y','z'] def multIt = {x, y -> println x * y} assert list == [0,'x','y','z'] forEach 3, multIt.curry(2) Maps forEach 3, multIt.curry('-') Maps are like lists that have an arbitrary type of key instead Closure parameter list examples: of integer. Therefore, the syntax is very much aligned. Closure Parameters def map = [a:0, b:1] { ... } zero or one (implicit 'it') Maps can be accessed in a conventional square-bracket syntax or as if the key was a property of the map. {-> ... } zero {x -> ... } one assert map['a'] == 0 assert map.b == 1 {x=1 -> ... } one or zero with default map['a'] = 'x' {x,y -> ... } two map.b = 'y' assert map == [a:'x', b:'y'] { String x -> ... } one with static type

There is also an explicit get method that optionally takes a Closure.isCase(b) sends b to the closure and returns the call default value. result as boolean. Use as in assert map.c == null switch ('xy'){ assert map.get('c',2) == 2 assert map.c == 2 case {it.startsWith('x')} :... } Map iteration methods take the nature of Map.Entry objects [0,1,2].grep { it%2 == 0 } into account. map.each { entry -> println entry.key GDK println entry.value } map.each { key, value -> Methods for java.lang.Object println "$key $value" Get object info } for (entry in map) { println obj.dump() println "$entry.key $entry.value" } or in a GUI import groovy.inspect.swingui.* GPath ObjectBrowser.inspect(obj) Calling a property on a list returns a list of the property for each item in the list. Print properties, methods, and fields of obj employees.address.town println obj.properties returns a list of town objects. println obj.class.methods.name println obj.class.fields.name To do the same with method calls, use the spread-dot operator. employees*.bonus(2008) Two ways to invoke a method dynamically calls the bonus method on each employee and stores the obj.invokeMethod(name, paramsAry) result in a list. obj."$name"(params)

DZone, Inc. | www.dzone.com 5 Groovy tech facts at your fingertips

Files and I/0, continued GDK Often used reading methods GDK (Methods for java.lang.Object). continued def file = new File('/data.txt') Further methods println file.text is(other) // identity check (also for Reader, URL, InputStream,Process) isCase(candidate) //default:equality def listOfLines = file.readLines() obj.identity {...}; obj.with {...} file.eachLine { line -> ... } print(); print(value), println(); println(value) file.splitEachLine(/\s/) { list -> } printf(formatStr, value) file.withReader { reader -> ... } printf(formatStr, value[]) (also for Reader, URL, InputStream) sleep(millis) sleep(millis) { onInterrupt } file.withInputStream { is -> ...} use(categoryClass) { ... } (also for URL) use(categoryClassList) { ... } Often-used writing methods Every object is iterable in Groovy—even if it was implemented out << 'content' in Java. See Groovy in Action, chapter 9 on what strategy for out of type File, Writer, OutputStream, Socket, and Process Groovy applies to make this happen. file.withWriter('ASCII') {writer -> } Not only can you use any obj in loops like file.withWriterAppend('ISO8859-1'){ for (element in obj) { ... } writer -> ... } but you can also apply the following iterative objects methods: Reading and writing with Strings Returns Purpose def out = new StringWriter() Boolean any {...} out << 'something' List collect {...} def str = out.toString() Collection collect(Collection collection) {...} def rdr = new StringReader(str)

(void) each {...} println rdr.readLines() (void) eachWithIndex {item, index-> ...} Connecting readers and writers Boolean every {...} writer << reader Object find {...} Special logic for writable objects, e.g. writeTo() List findAll {...} writer << obj Integer findIndexOf {...}

Integer findIndexOf(startIndex) {...} Transform (with closure returning the replacement) and filter

Integer findLastIndexOf {...} (with closure returning boolean)

Integer findLastIndexOf(startIndex) {...} reader.transformChar(writer){c -> }

List findIndexValues {...} reader.transformLine(writer){line-> }

List findIndexValues(startIndex) {...} src.filterLine(writer){line-> } writer << src.filterLine {line -> } Object inject(startValue) {temp, item -> ...}

List grep(Object classifier) For src in File, Reader, InputStream // uses classifier.isCase(item) Threads & Processes Two ways of spawning new threads Implement the iterator() method that returns Hot an Iterator object to give your own Groovy def thread = Thread.start { ... } Tip class meaningful iterable behavior with the def t = Thread.startDaemon { ... } above methods. Two ways of talking to an external process ('cmd /c' is for Windows platforms only)

Files and I/0 today = 'cmd /c date /t' Often-used filesystem methods .execute().text.split(/\D/) def dir = new File('somedir') proc = ['cmd','/c','date'] def cl = {File f -> println f} .execute() dir.eachDir cl Thread.start {System.out << proc.in} dir.eachFile cl Thread.start {System.err << proc.err} dir.eachDirRecurse cl proc << 'no-such-date' + "\n" dir.eachFileRecurse cl proc << today.join('-') + "\n" dir.eachDirMatch(~/.*/, cl) proc.out.close() dir.eachFileMatch(~/.*/, cl) proc.waitForOrKill(0)

DZone, Inc. | www.dzone.com 6 Groovy tech facts at your fingertips

XML SQL, continued Alternative with using a datasource Reading XML import org.hsqldb.jdbc.* def source = new jdbcDataSource() Decide to use the parser (for state-based processing) or the source.database = 'jdbc:hsqldb:mem:GInA' slurper (for flow-based processing) source.user = 'user-name' def parser = new XmlParser() source.password = 'password' def slurper = new XmlSlurper() def db = new groovy.sql.Sql(source) Common parse methods: Submitting Queries When a query contains wildcards, it is wise to use a parse(org.xml.saxInputSource) PreparedStatement parse(File) . Groovy SQL does this automatically when parse(InputStream) you supply either the list of values in an extra list or when the parse(Reader) statement is a GString. So each method below has three variants: parse(String uri) method('SELECT ... ') parseText(String text) method('SELECT ...?,?', [x,y]) method("SELECT ... $x,$y") The parse methods of parser and slurper return different ob- jects (Node vs. GPathResult) but you can apply the following Returns Method name Parameters methods on both: boolean execute prepStmt Integer executeUpdate prepStmt result.name() void eachRow prepStmt result.text() { row -> } result.toString() void query prepStmt result.parent() { resultSet -> ... } result.children() List rows prepStmt result.attributes() Object firstRow prepStmt result.depthFirst() In the above, attributes can be fetched from each row by result.iterator() // see GDK hot tip index or by name Shorthands for children, child, and attribute access: db.eachRow('SELECT a,b ...'){ row -> Shorthand Result println row[0] + ' ' + row.b ['elementName'] All child elements of that name } .elementName [index] Child element by index Combine with GPath ['@attributeName'] List hits = db.rows('SELECT ...') .'@attributeName' The attribute value stored under that name hits.grep{it.a > 0} .@attributeName DataSet Reading the first ten titles from a blog: For easy DB operations without SQL def url= 'http://'+ def dataSet = db.dataSet(tablename) 'www.groovyblogs.org/feed/rss' dataSet.add ( def rss = new XmlParser().parse(url) a: 1, rss.channel.item.title[0..9]*.text() b: 'something' ) Writing XML dataSet.each { println it.a } Groovy (Streaming-) MarkupBuilder allows you to produce dataSet.findAll { it.a < 2 } proper XML with logic while keeping a declarative style. In the last statement, the expression in the findAll closure will def b=new groovy.xml.MarkupBuilder() map directly to a SQL WHERE clause. b.outermost { simple() META PROGRAMMING 'with-attr' a:1, b:'x', 'content' 10.times { count -> nesting { nested count } Categories } Group of methods assigned at runtime to arbitrary classes } that fulfill a common purpose. Applies to one thread. Scope is limited to a closure. SQL class IntCodec { static String encode(Integer self){self.toString()} static Integer decode(String self){self.toInteger()} Connecting to the DB } Getting a new Sql instance directly. For example, a HSQLDB use(IntCodec) {42.encode().decode()} import groovy.sql.Sql ExpandoMetaClass def db = Sql.newInstance( Same example but change applies to all threads and 'jdbc:hsqldb:mem:GInA', unlimited scope. 'user-name', Integer.metaClass.encode << {delegate.toString()} 'password', String.metaClass.decode << {delegate.toInteger()} 'org.hsqldb.jdbcDriver') 42.encode().decode()

DZone, Inc. | www.dzone.com 7 Groovy tech facts at your fingertips

Meta Programming, continued A bit easier to handle are the variants Object methodMissing( Method Invocation Hooks String name, Object args) In your Groovy class, implement the method Object propertyMissing( String name, Object args) Object invokeMethod(String name, Object args) that are called like the name suggests. to intercept calls to unavailable methods. Instead of implementing the above methods, they can also Additionally, implement the interface GroovyInterceptable to be added to the MetaClass of any arbitrary class (or object) to intercept also calls to available methods. achieve the same effect. Implement Integer.metaClass.methodMissing << { Object getProperty(String name) String name, Object args -> Math."$name"(delegate) void setProperty( } String name, Object value) println 3.sin() to intercept property access. println 3.cos()

ABOUT THE AUTHOR RECOMMENDED BOOK

Dierk König Groovy in Action introduces Groovy Dierk is a committer to the Groovy and Grails project since its early days by example, presenting lots of and lead author of the renowned Gina (Groovy in Action) book. He works reusable code while explaining for Canoo Engineering AG in Basel, Switzerland, as a software developer, the underlying concepts. Java mentor, and coach. He enjoys his daily hands-on work in software projects developers new to Groovy find a as well as publishing in leading magazines and speaking at international smooth transition into the dynamic conferences. programming world. Groovy experts Dierk holds degrees in both business administration and computer science, and has gain a solid reference that challenges worked as a professional Java programmer for over 10 years while always keeping an eye them to explore Groovy deeply and creatively. on evolving languages. He is an acknowledged reviewer and/or contributor to numerous leading books on the topics of Extreme Programming, Test-Driven Development, Groovy, and Grails. His strong focus on delivering quality software led him to founding the open- BUY NOW source Canoo WebTest project and managing it since 2001. books.dzone.com/books/groovy-in-action

Get More FREE Refcardz. Visit refcardz.com now!

Upcoming Refcardz: Available: Core Seam Essential Ruby Core CSS: Part I Core CSS: Part III Essential MySQL Struts2 JUnit and EasyMock Core .NET Hibernate Search Getting Started with MyEclipse Very First Steps in Flex FREE Equinox Spring Annotations C# EMF Core Java Groovy Core CSS: Part II NetBeans IDE 6.1 Java Editor XML PHP RSS and Atom JSP Expression Language Getting Started with JPA GlassFish Application Server ALM Best Practices JavaServer Faces Silverlight 2 Design Patterns Published June 2008 HTML and XHTML Visit refcardz.com for a complete listing of available Refcardz.

DZone, Inc. 1251 NW Maynard ISBN-13: 978-1-934238-09-7 ISBN-10: 1-934238-09-0 Cary, NC 27513 5 0 7 9 5 888.678.0399 DZone communities deliver over 4 million pages each month to 919.678.0300 more than 1.7 million software developers, architects and decision Refcardz Feedback Welcome makers. DZone offers something for everyone, including news, [email protected] tutorials, cheatsheets, blogs, feature articles, source code and more. Sponsorship Opportunities 9 781934 238097 $7.95 “DZone is a developer’s dream,” says PC Magazine. [email protected]

Copyright © 2008 DZone, Inc. All rights reserved. No part of this publication may be reproduced, stored in a retrieval system, or transmitted, in any form or by means electronic, mechanical, Version 1.0 photocopying, or otherwise, without prior written permission of the publisher.