Jim Cheung

reading notes on

Making Java Groovy

Chapter 1, Why add Groovy to Java?

(no notes)

Chapter 2, Groovy by example

Hello, Groovy

two additional differences in syntax between groovy and java:

Accessing Google Chart Tools

using https://developers.google.com/chart/image/

In a groovy script you don't actually have to declare any types at all. If you declare a type the variable becomes local to the script. If not, it becomes part of the "binding"

String base = 'http://chart.apis.google.com/chart?'

groovy is optionally typed, you can specify a type or you can use the def keyword if you don't know or care.

"If you think of a type, type it"

def params = [cht:'p3',chs:'250x100',chd:'t:60,40',chl:'Hello|World']

in groovy you create a map with [], and each entry consists of keys and values separated by :

// init a map
Map somemap = [:]

the keys are assumed to be strings by default. the values can be anything.

by default params is an instance of `java.util.LinkedHashMap'

single-quoted strings are instance of java.lang.String; double-quoted strings are "interpolated" strings (known as GStrings

params.collect { k,v -> "$k=$v" }

collect method takes a closure as an argument, applies the closure to each element of the collection, and return a new collection containing the results.

closure is a block of code, delimited by {}, which can be treated as an object.

if the closure takes one argument, the argument represents a Map.Entry; with two arguments, the first is the key and the second is the value for each entry.

if the last argument to any methods is a closure you can put the closure outside the parentheses.

// above actually is:
params.collect ( { k,v -> "$k=$v" } )

join method takes a single argument that's used as the separator when assembling the elements into a String

params.collect { k,v -> "$k=$v" }.join('&')

note that there is () on join method above. in groovy, if you leave off the parentheses when calling a method with no arguments the compiler assumes you are asking for the corresponding getter or setter method.

groovy assert keyword, which takes a boolean expression as an argument. if the expression is true, nothing is returned. but if not, you get the error printed to the console.

params.each { k,v ->
    assert qs.contains("$k=$v")
}

groovy jdk adds toURL() method to the String class, converts an instance of java.lang.String into java.net.URL

url.toURL().text

accessing properties in groovy automatically invokes the associated getter or setter method.

above, .text is actually invoking getText() method

In groovy every class has a metaclass. A metaclass is another class that manages the actual invocation process.

if you invoke a method on class that doesn't exists, the call is untimately intercepted by a method in the metaclass called methodMissing. likewise, accessing a property that doesn't exist eventually calls propertyMissing in the metaclass.

customizing the behavior of methodMissing and propertyMissing is the heart of groovy runtime metaprogramming.

Groovy automatically imports:

the as keyword has several uses, one of which is to provide an alias for imported classes.

in groovy, if you don't specify an access modifier, attributes are assumed to be provate, and methods are assumed to be public.

if you don't add a constructor, you get not only the default, but also a map-based constructor that allows you to set any combination of attribute values by supplying them as key-value pairs.

[stadium.name, stadium.city, stadium.state].collect {
    URLEncoder.encode(it, 'UTF-8')
}.join(',')

if you use a closure without specifying a dummy parameter, each element of the list is assigned to a variable called it.

the last expression in a closure is returned automatically.

parse xml

def response = new XmlSlurper().parse(url)
def homeName = response.result[0].boxscore.@home_name

groovy has two classes for parsing XML. One is XmlParser and the other is XmlSlurper. both convert XML into a DOM tree. from a practical point of view the slurper is more efficient and takes less memory.

whether you use an XmlParser or an XmlSlurper, exracting data from XML means just walking the dom tree. (slurping JSON is just as easy)

Dots . traverse from parent elements to children, and @ signs represent attriute values.

work with regular expressions

def pitchers = boxscore.pitching.pitchers
pitchers.each { p ->
    if (p.@note && p.@note =~ /W|L|S/) {
        println " ${p.@name} ${p.@note}"
    }
}

the =~ method in groovy returns an instance of java.util.regex.Matcher

for parsing HTML, use some third-partly library to do it, like NekoHTML parser

generating XML

the standard groovy library includes a class groovy.xml.MarkupBuilder

MarkupBuilder builder = new MarkupBuilder()
builder.games {
    results.each { g -> 
        game(
            outcome:"...",
            lat:g.stadium.latitude,
            lng:g.stadium.longitude
        )
    }
}

there is no game method in MarkupBuilder, the builder intercepts that method call and creates a node out of it.

query database

Sql db = Sql.newInstance(
    'jdbc:mysql://localhost:3306/baseball',
    '...username...',
    '...password...',
    'com.mysql.jdbc.Driver'
)

The Sql class has a static newInstance method, whose arguments are the JDBC URL, username, password, and the driver class.

db.execute "drop table if exists stadium;"
db.execute '''
    create table statidum(
        ...
    );
'''

the three single quotes ''' represent a multiline string. three double quotes """ would be a multiline GString

stadium.each { s ->
    db.execute """
        insert into stadium (name, ...)
        values (${s.name}, ...);
    """
}

use ${...} notation to substitute values.

assert db.rows('select * from stadium').size() == stadium.size()
db.eachRow('select latitude, longitude from stadium') { row ->
    assert row.latitude ...
    assert row.longitude ...
}

groovlets

a groovlet is a script that is executed by a class called groovy.servlet.GroovyServlet

groovlets executed this way are deployed as source code rather than as compiled classes under WEB-INF

more about groovlets in chapter 10

Chapter 3, Code-level integration

Groovy and Java together at runtime

at runtime, compiled groovy and compiled java both result in bytecodes for the JVM. to execute code that combines them, all that's necessary is to add a single JAR file to the system. compiling and testing your code requires the Groovy compiler and libraries, but at runtime all you need is one JAR.

> groovyc hello_world.groovy
> java -cp .:$GROOVY_HOME/embeddable/groovy-all-2.1.5.jar hellow_world

using JSR223 scripting for the JAVA platform API

build into Java SE 6 and above, the API for JSR223, Scripting for the Java Platform, is a standard mechanism you can use to call scripts written in other languages.

the JSR223 allows you to call Groovy scripts using purely Java classes

public class ExecuteGroovyFromJSR223 {
    public static void main(String[] args) {
        ScriptEngine engine = new ScriptEngineManager().getEngineByName("groovy");
        try {
            engine.eval("println 'Hello, Groovy!'");
            engine.eval(new FileReader("src/hello_world.groovy"));
        } catch (ScriptException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
}

supplying parameters to a groovy script

a binding is a collection of variables at a scope that makes them visible inside a script.

String address = [street,city,state].collect {
    URLEncoder.encode(it, 'UTF-8')
}.join(',')

street,city,state are not declared in the script, this adds them to the binding, making them available to the caller. (something like global variables)

// set binding variables
engine.put("street", "...")
engine.put("city", "...")
engine.put("state", "...")

(Groovy Eval and GroovyShell classes sections are skipped)

so use ScriptEngine class from Java, or the Eval and GroovyShell classes from Groovy, along with a Binding if necessary, to call Groovy scripts from Java.

and this this the hard way

Calling Groovy from Java the easy way

the easy way: put the Groovy code in a class, compile it as usual, and then instantiate it and invoke methods as thought it was Java.

Calling Java from Groovy

String address = [street,city,state].collect {
    URLEncoder.encode(it, 'UTF-8')
}.join(',')

here, URLEncoder is Java library code.

whenever you mix Java and Groovy, compile everything with groovyc, let groovyc handle all the cross-compiler issues. any compiler flags you would normally send to javac work just fine in groovyc as well.

Chapter 4, Using Groovy features in Java

def slayers = [buffy, faith]
assert ['Buffy', 'Failth'] == slayers*.name

spread-dot operator extracts name property from each instance and return a list of the results (same as collect does)

in groovy all operators are represented by methods, you can overload any operator by Implementing the appropriate method in your groovy class.

public class Department {
    // overriding + 
    public Department plus(Employee e) {
        hire(e);
        return this;
    }
    // overriding -
    public Department minus(Employee e) {
        layOff(e);
        return this;
    }
}

check doc for list of operators that can be overridden in groovy.

the groovy jdk

every groovy class contains a metaclass. the metaclass contains methods that come into play if a method or property that doesn't exist is accessed through an instance.

for example, groovy adds many methods to the java.util.Collection interface, including collect,count,find,findAll,leftShift,max,min,sort,sum

check doc for more API of groovy jdk

AST transformations

groovy 1.6 introduced Abstract Syntax Tree (AST) transformations.

@Delegate

public class Camera {
    public String takePicture() {
        return "taking picture";
    }
}
public class Phone {
    public String dial(String number) {
        return "dialing " + number;
    }
}
class SmartPhone {
    @Delegate Camera camera = new Camera()
    @Delegate Phone phone = new Phone()
}

@Immutable

making a class support immutability requires that

@Immutable AST transformation does everything for you.

the @Immutable transformation can only be applied to Groovy classes, but those classes can then be used in Java applications.

@Immutable
class ImmutablePoint {
    double x
    double y
    String toString() { "($x,$y)" }
}

it allows the properties to be set through a constructor, but once set the properties can no longer be modified.

the annotation has its limitations: you can only apply it to classes that contain primitives or certain library classes, like String or Date. It also works on classes what contain properties that are also immutable.

@Singleton

@Singleton
class ImmutablePointFactory {
    ImmutablePoint newImmutablePoint(xval, yval) {
        return new ImmutablePoint(x:xval, y:yval)
    }
}

the class now contains a static property called instance which contains the instance of the class.

ImmutablePoint p = ImmutablePointFactory.instance.newImmutablePoint(3,4)

Working with XML

(already covered above)

Working with JSON data

String url = 'http://api.icndb.com/jokes/random?limitTo=[nerdy]'
String jsonTxt = url.toURL().text
def json = new JsonSlurper().parseText(jsonTxt)
def joke = json?.value?.joke
println joke

JsonBuilder class generates JSON strings using the same mechanism as XmlSlurper

Chapter 5, Build processes

The build challenge The Java approach, part 1: Ant Making Ant Groovy The Java approach, part 2: Maven Grapes and @Grab The Gradle build system

Chapter 6, Testing Groovy and Java projects

Working with JUnit Testing scripts written in Groovy Testing classes in isolation The future of testing: Spock

Chapter 7, The Spring framework

A Spring application Refreshable beans Spring AOP with Groovy beans Inline scripted beans Groovy with JavaConfig Building beans with the Grails BeanBuilder

Chapter 8, Database access

The Java approach, part 1: JDBC The Groovy approach, part 1: groovy.sql.Sql The Java approach, part 2: Hibernate and JPA The Groovy approach, part 2: Groovy and GORM Groovy and NoSQL databases

Chapter 9, RESTful web services

The REST architecture The Java approach: JAX-RS Implementing JAX-RS with Groovy RESTful Clients Hypermedia Other Groovy approaches

Chapter 10, Building and testing web applications

Groovy servlets and ServletCategory Easy server-side development with groovlets Unit- and integration-testing web components Grails: the Groovy "killer app"