Search

Dark theme | Light theme
Showing posts with label GroovyGoodness:Intermediate. Show all posts
Showing posts with label GroovyGoodness:Intermediate. Show all posts

March 4, 2019

Groovy Goodness: Use Expanded Variables in SQL GString Query

Working with SQL database from Groovy code is very easy using the groovy.sql.Sql class. The class has several methods to execute a SQL query, but we have to take special care if we use methods from Sql that take a GString argument. Groovy will extract all variable expressions and use them as values for placeholders in a PreparedStatement constructed from the SQL query. If we have variable expressions that should not be extracted as parameters for a PreparedStatement we must use the Sql.expand method. This method will make the variable expression a groovy.sql.ExpandedVariable object. This object is not used as parameter for a PreparedStatement query, but the value is evaluated as GString variable expression.

In the following sample we have a class that invokes several methods of an Sql object with a GString query value. We can see when to use Sql.expand and when it is not needed:

package mrhaki

import groovy.sql.*

class SampleDAO {
    private static final String TABLE_NAME = 'sample'
    private static final String COLUMN_ID = 'id'
    private static final String COLUMN_NAME = 'name'
    private static final String COLUMN_DESCRIPTION = 'description'

    private final Sql sql = 
        Sql.newInstance(
            'jdbc:h2:test', 'sa', 'sa', 'org.h2.Driver')

    Long create() {
        // We need to use Sql.expand() in our GString query.
        // If we don't use it the GString variable expressions are interpreted 
        // as a placeholder in a SQL prepared statement, but we don't
        // that here.
        final query = 
            """
            INSERT INTO ${Sql.expand(TABLE_NAME)} DEFAULT VALUES
            """

        final insertedKeys = sql.executeInsert(query)
        return insertedKeys[0][0]
    }

    void updateDescription(final Long id, final String description) {
        // In the following GString SQL we need
        // Sql.expand(), because we use executeUpdate
        // with only the GString argument.
        // Groovy will extract all variable expressions and
        // use them as the placeholders
        // for the SQL prepared statement.
        // So to make sure only description and id are 
        // placeholders for the prepared statement we use
        // Sql.expand() for the other variables.
        final query = 
            """
            UPDATE ${Sql.expand(TABLE_NAME)} 
            SET ${Sql.expand(COLUMN_DESCRIPTION)} = ${description}
            WHERE ${Sql.expand(COLUMN_ID)} = ${id}
            """
        sql.executeUpdate(query)
    }

    void updateName(final Long id, final String name) {
        // In the following GString SQL we don't need
        // Sql.expand(), because we use the executeUpdate
        // method with GString argument AND argument
        // with values for the placeholders.
        final query = 
            """
            UPDATE ${TABLE_NAME} 
            SET ${COLUMN_NAME} = :nameValue
            WHERE ${COLUMN_ID} = :idValue
            """
        sql.executeUpdate(query, nameValue: name, idValue: id)
    }
}

Written with Groovy 2.5.4.

June 7, 2018

Groovy Goodness: Using String Values In Ranges

We can use ranges in Groovy using an easy syntax where the start and end values of the range are separated by .. for an inclusive range and ..< for an exclusive range as we have seen in a previous post. The values of the range are mostly numbers or enum values. But we can also use String values to define a range. Groovy will check if the String values are the same length and if the values, except for the last character, are the same. Then the natural ordering of the last character of the String value, based on the character's int value, is used to create the range values.

In the following example we define several ranges using String values. We can even define a reverse range using String values.

// Range is defined based on int
// value of character.
def characters = 'A'..'F'

assert characters.from == 'A'
assert characters.to == 'F'
assert characters.toList() == ['A', 'B', 'C', 'D', 'E', 'F']
assert characters.step(2) == ['A', 'C', 'E']


// We can create a reverse range
// also based on the int value
// of the character.
def sample = '&'..'!'

assert sample.toList() == ['&', '%', '$', '#', '"', '!']
assert sample.reverse
assert sample.from == '!'
assert sample.to == '&'


// We can use String values and
// the last character is used
// to create a range. Therefore
// the last character must be valid
// to create a range from.
def groovyRange = 'Groovy10'..<'Groovy15'

assert groovyRange.from == 'Groovy10'
assert groovyRange.to == 'Groovy14'
assert groovyRange.toList() == ['Groovy10', 'Groovy11', 'Groovy12', 'Groovy13', 'Groovy14']


// Also works in reverse.
def groovyReverse = 'Groovy19'..'Groovy15'

assert groovyReverse.reverse
assert groovyReverse.from == 'Groovy15'
assert groovyReverse.to == 'Groovy19'
assert groovyReverse.toList() == ['Groovy19', 'Groovy18', 'Groovy17', 'Groovy16', 'Groovy15']


import static groovy.test.GroovyAssert.shouldFail

// Should fail because String values,
// except for the last character, should
// be the same.
shouldFail(IllegalArgumentException) {
    def invalidRange = 'Groovy15'..'Groovy20'
}

Written with Groovy 2.5.0.

March 30, 2017

Groovy Goodness: Redirecting Print Methods In Scripts

To run external Groovy scripts in our Java or Groovy application is easy to do. For example we can use GroovyShell to evaluate Groovy code in our applications. If our script contains print methods like println we can redirect the output of these methods. The Script class, which is a base class to run script code, has an implementation for the print, printf and println methods. The implementation of the method is to look for a property out, either as part of a Script subclass or in the binding added to a Script class. If the property out is available than all calls to print, printf and println methods are delegated to the object assigned to the out property. When we use a PrintWriter instance we have such an object, but we could also write our own class with an implementation for the print methods. Without an assignment to the out property the fallback is to print on System.out.

In the following example we have a external script defined with the variable scriptText, but it could also be a file or other source with the contents of the script we want to run. We assign our own PrintWriter that encapsulates a StringWriter to capture all invocations to the print methods:

// Groovy script to execute.
def scriptText = '''
def s = "Groovy rocks!"

// Print value of s.
println s

// Use printf for formatted printing.
printf 'The answer is %X', 42
'''

// Assign new PrintWriter to "out"
// variable of binding object.
def stringWriter = new StringWriter()
def shellBinding = new Binding(out: new PrintWriter(stringWriter))

// Create GroovyShell to evaluate script.
def shell = new GroovyShell(shellBinding)

// Run the script.
shell.evaluate(scriptText)

// Check the output of print, println and printf methods.
assert stringWriter.toString() == 'Groovy rocks!\nThe answer is 2A'

Another option is to directory set the out property of a Script object:

def scriptText = '''
def s = "Groovy rocks!"

// Print value of s.
println s

// Use printf for formatted printing.
printf 'The answer is %X', 42
'''

def shell = new GroovyShell()

// Parse script text and return Script object.
def script = shell.parse(scriptText)

// Assign new PrintWriter to "out"
// variable of Script class.
def stringWriter = new StringWriter()
script.out = new PrintWriter(stringWriter)

// Run the script.
script.run()

// Check the output of print, println and printf methods.
assert stringWriter.toString() == 'Groovy rocks!\nThe answer is 2A'

Written with Groovy 2.4.10.

March 26, 2015

Groovy Goodness: New Methods to Sort and Remove Duplicates From Collection

In Groovy we can use the sort and unique methods to sort a collection or remove duplicates from a collection. These methods alter the collection on which they are invoked. This is a side effect we might want to avoid. Therefore the sort and unique methods where changed and we could pass a boolean argument to indicate if the original collection should be changed or that we must have a new collection as the result of the methods, leaving the original collection untouched. Since Groovy 2.4 we have two new methods which by default return a new collection: toSorted and toUnique.

In the following sample we see the new methods in action:

@groovy.transform.Sortable
@groovy.transform.ToString
class User {
    String username, email
}

def mrhaki1 = new User(username: 'mrhaki', email: 'mrhaki@localhost')
def mrhaki2 = new User(username: 'mrhaki', email: 'user@localhost')
def hubert1 = new User(username: 'hubert', email: 'user@localhost')
def hubert2 = new User(username: 'hubert', email: 'hubert@localhost')


// We make the list immutable,
// so we check the toSorted and toUnique methods
// do not alter it.
def users = [mrhaki1, mrhaki2, hubert1, hubert2].asImmutable()


// toSorted 
def sortedUsers = users.toSorted()

// @Sortable adds a compareTo method 
// to User class to sort first by username
// and then email.
assert sortedUsers == [hubert2, hubert1, mrhaki1, mrhaki2]

// Original list is unchanged.
assert users == [mrhaki1, mrhaki2, hubert1, hubert2]

// Use toSorted with closure.
def sortedByEmail = users.toSorted { a, b -> a.email <=> b.email }
assert sortedByEmail == [hubert2, mrhaki1, mrhaki2, hubert1]

// Or use toSorted with Comparator.
// @Sortable added static comparatorByProperty
// methods.
def sortedByEmailComparator = users.toSorted(User.comparatorByEmail())
assert sortedByEmailComparator == [hubert2, mrhaki1, mrhaki2, hubert1]


// toUnique with Comparator.
def uniqueUsers = users.toUnique(User.comparatorByUsername())
assert uniqueUsers == [mrhaki1, hubert1]
assert users == [mrhaki1, mrhaki2, hubert1, hubert2]

// toUnique with Closure.
def uniqueByEmail = users.toUnique { a, b -> a.email <=> b.email }
assert uniqueByEmail == [mrhaki1, mrhaki2, hubert2]

Written with Groovy 2.4.3.

October 14, 2014

Groovy Goodness: Closure as a Class

When we write Groovy code there is a big chance we also write some closures. If we are working with collections for example and use the each, collect or find methods we use closures as arguments for these methods. We can assign closures to variables and use the variable name to reference to closure. But we can also create a subclass of the Closure class to implement a closure. Then we use an instance of the new closure class wherever a closure can be used.

To write a closure as a class we must subclass Closure and implement a method with the name doCall. The method can accept arbitrary arguments and the return type can be defined by us. So we are not overriding a method doCall from the superclass Closure. But Groovy will look for a method with the name doCall to execute the closure logic and internally use methods from the Closure superclass.

In the following sample we write a very simple closure as a class to check if an object is a number. Then we use an instance of the class with the findAll method for a collection of objects:

class IsNumber extends Closure<Boolean> /* return type for closure as generic type */ {

    IsNumber() {
        super(null)
    }

    /**
     * Implementation of closure.
     */
    Boolean doCall(final Object value) {
        // Check if value is a number, if so
        // return true, otherwise false.
        value in Number
    }

}

def list = ['a', 100, 'Groovy', 1, 8, 42.0, true]

def numbers = list.findAll(new IsNumber())

assert numbers == [100, 1, 8, 42.0]

Code written with Groovy 2.3.7.

April 3, 2014

Groovy Goodness: Converting Byte Array to Hex String

To convert a byte[] array to a String we can simply use the new String(byte[]) constructor. But if the array contains non-printable bytes we don't get a good representation. In Groovy we can use the method encodeHex() to transform a byte[] array to a hex String value. The byte elements are converted to their hexadecimal equivalents.

final byte[] printable = [109, 114, 104, 97, 107, 105]

// array with non-printable bytes 6, 27 (ACK, ESC)
final byte[] nonprintable = [109, 114, 6, 27, 104, 97, 107, 105]


assert new String(printable) == 'mrhaki'
assert new String(nonprintable) != 'mr  haki'


// encodeHex() returns a Writable
final Writable printableHex = printable.encodeHex()
assert printableHex.toString() == '6d7268616b69'
final nonprintableHex = nonprintable.encodeHex().toString()
assert nonprintableHex == '6d72061b68616b69'


// Convert back
assert nonprintableHex.decodeHex() == nonprintable

Code written with Groovy 2.2.1

September 6, 2013

Groovy Goodness: Replace Characters in a String with CollectReplacements

We can use the collectReplacements(Closure) method to replace characters in a String. We pass a closure to the method and the closure is invoked for each character in the String value. If we return null the character is not transformed, otherwise we can return the replacement character.

def s = 'Gr00vy is gr8'

def replacement = {
    // Change 8 to eat
    if (it == '8') {
        'eat'
    // Change 0 to o
    } else if (it == '0') {
        'o'
    // Do not transform
    } else {
        null
    }
}

assert s.collectReplacements(replacement) == 'Groovy is great'

Code written with Groovy 2.1.6

January 28, 2013

Groovy Goodness: Append Values to Appendable Objects

Since Groovy 2.1 we have a couple of extra methods available for objects that implement the java.lang.Appendable interface. A lot of Writer objects implement this interface. The documentation of the Appendable interface mentions: An object to which char sequences and values can be appended.

First the leftShift() method is added. This means we can use the leftShift operator (<<) to append a value. Then we also can use the withFormatter() method. We can pass a closure to this method or a java.util.Locale object and a closure. The closure has a single parameter which is a java.util.Formatter instance. We can use this method to add printf-style formatted strings to an Appendable object. If we pass a Locale object to the method the Formatter is created with the specified Locale to created localized printf-sytle formatted strings.

// Create object that implements the Appendable interface.
final Appendable appendable = new StringWriter()

assert appendable in Appendable


// Use leftShift operator to add to Appendable implementation.
appendable << 'Groovy is Gr8!' << newLine


// Use withFormatter() method.
// Formatter object 
// is passed to closure as parameter.
appendable.withFormatter { formatter ->
    // Simple formatter pattern to reorder the arguments.
    formatter.format(/m r %3$1s %2$1s %1$1s %4$1s%n/, 'k', 'a', 'h', 'i')
}


// Use withFormatter() method and use Locale object
// as extra argument. The Locale is passed on
// to create the Formatter object.
appendable.withFormatter(Locale.US) { formatter ->
    formatter.format("US: " + datePattern, date)
}
// Use different Locale.
appendable.withFormatter(new Locale('nl')) { formatter ->
    formatter.format("Dutch: $datePattern", date)
}


// Check result is as expected:
assert appendable.toString() == '''Groovy is Gr8!
m r h a k i
US: January 27, 2013
Dutch: januari 27, 2013
'''


// Helper getters:

String getNewLine() {
    System.getProperty('line.separator')
}

Date getDate() {
    // Simple date to use in withFormatter() methods.
    Date.parse('yyyy-MM-dd', '2013-01-27')
}

String getDatePattern() {
    // Date pattern for Formatter.
    '%1$tB %1$te, %1$tY%n'
}

Code written with Groovy 2.1

October 25, 2012

Groovy Goodness: Pretty Print XML

The easiest way to pretty print an XML structure is with the XmlUtil class. The class has a serialize() method which is overloaded for several parameter types like String, GPathResult and Node. We can pass an OutputSteam or Writer object as argument to write the pretty formatted XML to. If we don't specify these the serialize() method return a String value.

import groovy.xml.*

def prettyXml = '''\<?xml version="1.0" encoding="UTF-8"?><languages>
  <language id="1">Groovy</language>
  <language id="2">Java</language>
  <language id="3">Scala</language>
</languages>
'''


// Pretty print a non-formatted XML String.
def xmlString = '<languages><language id="1">Groovy</language><language id="2">Java</language><language id="3">Scala</language></languages>'
assert XmlUtil.serialize(xmlString) == prettyXml

// Use Writer object as extra argument.
def xmlOutput = new StringWriter()
XmlUtil.serialize xmlString, xmlOutput
assert xmlOutput.toString() == prettyXml

// Pretty print a Node.
Node languagesNode = new XmlParser().parseText(xmlString)
assert XmlUtil.serialize(languagesNode) == prettyXml


// Pretty print a GPathResult.
def langagesResult = new XmlSlurper().parseText(xmlString)
assert XmlUtil.serialize(langagesResult) == prettyXml


// Pretty print org.w3c.dom.Element.
org.w3c.dom.Document doc = DOMBuilder.newInstance().parseText(xmlString)
org.w3c.dom.Element root = doc.documentElement
assert XmlUtil.serialize(root) == prettyXml


// Little trick to pretty format
// the result of StreamingMarkupBuilder.bind(). 
def languagesXml = {
    languages {
        language id: 1, 'Groovy'
        language id: 2, 'Java'
        language id: 3, 'Scala'
    }
}
def languagesBuilder = new StreamingMarkupBuilder()
assert XmlUtil.serialize(languagesBuilder.bind(languagesXml)) == prettyXml

If we already have a groovy.util.Node object we can also use the XmlNodePrinter. For example if we use XmlParser to parse XML we get a Node object. We create a new instance of the XmlNodePrinter and use the print() method to output the node with child nodes. If we don't specify a Writer object the output is send to System.out.

import groovy.xml.*

// Get groovy.util.Node value.
def xmlString = '<languages><language id="1">Groovy</language><language id="2">Java</language><language id="3">Scala</language></languages>'
Node languages = new XmlParser().parseText(xmlString)


// Create output with all default settings.
def xmlOutput = new StringWriter()
def xmlNodePrinter = new XmlNodePrinter(new PrintWriter(xmlOutput))
xmlNodePrinter.print(languages)

assert xmlOutput.toString() == '''\
<languages>
  <language id="1">
    Groovy
  </language>
  <language id="2">
    Java
  </language>
  <language id="3">
    Scala
  </language>
</languages>
'''


// Create output and set indent character
// one space.
// (can also by \t for tabs, or other characters)
xmlOutput = new StringWriter()
xmlNodePrinter = new XmlNodePrinter(new PrintWriter(xmlOutput), " " /* indent */)
xmlNodePrinter.print(languages)

assert xmlOutput.toString() == '''\
<languages>
 <language id="1">
  Groovy
 </language>
 <language id="2">
  Java
 </language>
 <language id="3">
  Scala
 </language>
</languages>
'''


// Use properties preserveWhitespace,
// expandEmptyElements and quote to
// change the formatting.
xmlOutput = new StringWriter()
xmlNodePrinter = new XmlNodePrinter(new PrintWriter(xmlOutput))
xmlNodePrinter.with {
    preserveWhitespace = true
    expandEmptyElements = true
    quote = "'" // Use single quote for attributes
}
xmlNodePrinter.print(languages)

assert xmlOutput.toString() == """\
<languages>
  <language id='1'>Groovy</language>
  <language id='2'>Java</language>
  <language id='3'>Scala</language>
</languages>
"""

Code written with Groovy 2.0.5

October 9, 2012

Groovy Goodness: Create a List with Default Values

Since Groovy 1.8.7 we can create a list and use the withDefault() method to define a default value for elements that are not yet in the list. We use a closure as argument of the method, which returns the default value. We can even access the index of the element in the closure as an argument.

Besides the withDefault() method we can use the withLazyDefault() which is just another name for the same functionality. If we request a value for an index that is greater or equal to the size of the list, the list will automatically grow up to the specified index. Any gaps are filled with the value null.

We can also use the withEagerDefault() method. If we use this method the gaps are filled with the result from the closure we pass to the method. So instead of the value null the return result from the closure is used.

The following example script shows the results from using the withDefault() (withLazyDefault()) and withEagerDefault():

def lazy = ['abc', 42].withDefault { 'default' } // Or .withLazyDefault {}

// List grows because 3 is bigger than
// current lazy list size. Value is
// for element at index 3 is set with value
// from init closure.
assert lazy[3] == 'default'

// Gap at index 2 is filled with null value.
assert lazy == ['abc', 42, null, 'default']

// Because value at index 2 is set to null
// before, the init closure is invoked
// for this index now.
assert lazy[2] == 'default'

// List is now filled.
assert lazy == ['abc', 42, 'default', 'default']


def eager = ['abc', 42].withEagerDefault { 'default' }

// Here the list also grows, because
// index 3 is bigger than eager list size.
assert eager[3] == 'default'

// The gaps in the list are now
// filled with the value from
// the init closure.
assert eager == ['abc', 42, 'default', 'default']

// Value is already set because we
// used withEagerDefault.
assert eager[2] == 'default'


// We can use the index value as argument
// for the init closure.
def sample = [1,2,3].withDefault { index ->
    index % 2
}

assert sample[3] == 1
assert sample[4] == 0

(Written with Groovy 2.0.5)

June 28, 2012

Groovy Goodness: Partial Matches

Groovy 2.0 adds the matchesPartially() method to the Matcher class. This method returns true if a String value matches the pattern or if it matches the first part of the pattern. So with the matchesPartially() we get the result true if a String value or a longer String value matches the pattern.

def identification = /[A-Z]{2}\-\d{3,5}/

def matcher = 'AB-1234' =~ identification
assert matcher.matchesPartially()

matcher = 'XY-90' =~ identification
assert matcher.matchesPartially()

matcher = 'HA' =~ identification
assert matcher.matchesPartially()

matcher = 'A-431' =~ identification
assert !matcher.matchesPartially()

matcher = 'YK-901201' =~ identification
assert !matcher.matchesPartially()

June 7, 2012

Groovy Goodness: Revisited Getting the Sum of Items in a Collection

A while ago I wrote a blog post Groovy Goodness: Getting the Sum of Items in a Collection. Today I presented about this little topic as part of the "Groovy Hidden Gems" session at Gr8Conf 2012. One of the attendees noticed the code where we calculate the sum of the Person objects was not working. So it time to revisit this topic.

The problem with the presented solution is that with more than two elements in the list the code throws an exception. The return method of the plus() method is a BigDecimal so Groovy tries to invoke the plus() method on the BigDecimal class with a Person type argument. And that doesn't exist, hence the exception.

To fix this we must return a new Product object from the plus() method with the sum of the price property. The code is now:

class Product {
    String name
    BigDecimal price

    Product plus(Product other) {
        new Product(price: this.price + other.price)
    }
}
def products = [
    new Product(name: 'laptop', price: 999), 
    new Product(name: 'netbook', price: 395),
    new Product(name: 'iPad', price: 200)
]

assert 1594 == products.sum().price

EDIT: I like to thank the people that wrote a comment. The current solution focuses on the implementation of a plus() method in a class to get a sum value. But we can also use a closure for the sum(). In the closure we define the property to calculate the sum for. Or we can use the optional spread operator to get the price property of all products and invoke the sum() method.

assert products.sum { it.price } == 1594
assert products.price.sum() == 1594
assert products*.price.sum() == 1594

September 22, 2011

Groovy Goodness: Use Connection Parameters to Get Text From URL

For a long time we can simply get the text from an URL in Groovy. Since Groovy 1.8.1 we can set parameters to the underlying URLConnection that is used to get the content. The parameters are passed as a Map to the getText() method or to the newReader() or newInputStream() methods for an URL.

We can set the following parameters:

  • connectTimeout in milliseconds
  • readTimeout in milliseconds
  • useCaches
  • allowUserInteraction
  • requestProperties is a Map with general request properties

// Contents of http://www.mrhaki.com/url.html:
// Simple test document
// for testing URL extensions
// in Groovy.

def url = "http://www.mrhaki.com/url.html".toURL()

// Simple Integer enhancement to make
// 10.seconds be 10 * 1000 ms.
Integer.metaClass.getSeconds = { ->
    delegate * 1000
}

// Get content of URL with parameters.
def content = url.getText(connectTimeout: 10.seconds, readTimeout: 10.seconds,
                          useCaches: true, allowUserInteraction: false,
                          requestProperties: ['User-Agent': 'Groovy Sample Script'])

assert content == '''\
Simple test document
for testing URL extensions
in Groovy.
'''

url.newReader(connectTimeout: 10.seconds, useCaches: true).withReader { reader ->
    assert reader.readLine() == 'Simple test document'
}

September 21, 2011

Groovy Goodness: Streaming JSON with StreamingJsonBuilder

Since Groovy 1.8 we can use JSONBuilder to create JSON data structures. With Groovy 1.8.1 we have a variant of JsonBuilder that will not create a data structure in memory, but will stream directly to a writer the JSON structure: StreamingJsonBuilder. This is useful in situations where we don't have to change the structure and need a memory efficient way to write JSON.

import groovy.json.*

def jsonWriter = new StringWriter()
def jsonBuilder = new StreamingJsonBuilder(jsonWriter)
jsonBuilder.message {
    header {
        from(author: 'mrhaki')  
        to 'Groovy Users', 'Java Users'
    }
    body "Check out Groovy's gr8 JSON support."
}
def json = jsonWriter.toString()
assert json == '{"message":{"header":{"from":{"author":"mrhaki"},"to":["Groovy Users","Java Users"]},"body":"Check out Groovy\'s gr8 JSON support."}}'

def prettyJson = JsonOutput.prettyPrint(json)
assert prettyJson == '''{
    "message": {
        "header": {
            "from": {
                "author": "mrhaki"
            },
            "to": [
                "Groovy Users",
                "Java Users"
            ]
        },
        "body": "Check out Groovy's gr8 JSON support."
    }
}'''


new StringWriter().withWriter { sw ->
    def builder = new StreamingJsonBuilder(sw)

    // Without root element.
    builder name: 'Groovy', supports: 'JSON'

    assert sw.toString() == '{"name":"Groovy","supports":"JSON"}'
}

new StringWriter().with { sw ->
    def builder = new StreamingJsonBuilder(sw)

    // Combine named parameters and closures.
    builder.user(name: 'mrhaki') {
        active true
    }
    
    assert sw.toString() == '{"user":{"name":"mrhaki","active":true}}'    
}

September 20, 2011

Groovy Goodness: Transform Items into a Collection with collectMany

In Groovy we can use the collectMany() method to transform items from a collection into a collection. The resulting collection is then flattened into a single collection. This means we can use the closure to return a collection with values and at the end all these collections are flattened into a single collection.

def text = 'groovy' as String[]

def mixedCase = text.collectMany { [it, it.toUpperCase()] }
assert mixedCase == ['g','G','r','R','o','O','o','O','v','V','y','Y']
assert text == 'groovy' as String[]


def list = [12, 20, 34]
def result = list.collectMany { [it, it*2, it*3] }

assert result == [12,24,36,20,40,60,34,68,102]
assert list == [12, 20, 34]

September 16, 2011

Groovy Goodness: GroupBy with Multiple Closures

We can group elements in a List or Map with the groupBy() method for a long time in Groovy. We pass a closure with the grouping condition to get a Map with the items grouped. And since Groovy 1.8.1 we can use more than closure to do the grouping. We can use it for both List and Map objects.

import static java.util.Calendar.*

class User {
    String name
    String city
    Date birthDate
    public String toString() { name }
}

def users = [
    new User(name:'mrhaki', city: 'Tilburg',   birthDate: Date.parse('yyyy-MM-dd', '1973-9-7')),
    new User(name:'bob',    city: 'New York',  birthDate: Date.parse('yyyy-MM-dd', '1963-3-30')),
    new User(name:'britt',  city: 'Amsterdam', birthDate: Date.parse('yyyy-MM-dd', '1980-5-12')),
    new User(name:'kim',    city: 'Amsterdam', birthDate: Date.parse('yyyy-MM-dd', '1983-3-30')),
    new User(name:'liam',   city: 'Tilburg',   birthDate: Date.parse('yyyy-MM-dd', '2009-3-6'))
]

def result = users.groupBy({it.city}, {it.birthDate.format('MMM')})

assert result.toMapString() == 
    '[Tilburg:[Sep:[mrhaki], Mar:[liam]], New York:[Mar:[bob]], Amsterdam:[May:[britt], Mar:[kim]]]'

assert result.Amsterdam.size() == 2
assert result.Tilburg.Mar.name == ['liam']

result = users.groupBy({it.name[0]}, {it.city})
assert result.toMapString() ==
    '[m:[Tilburg:[mrhaki]], b:[New York:[bob], Amsterdam:[britt]], k:[Amsterdam:[kim]], l:[Tilburg:[liam]]]'
assert result.k.Amsterdam.name == ['kim']  

// groupBy with multiple closues also works on Map
def usersByCityMap = users.groupBy({it.city})
def resultMap = usersByCityMap.groupBy({it.value.size()}, { k,v -> k.contains('i') })
assert resultMap.toMapString() ==
    '[2:[true:[Tilburg:[mrhaki, liam]], false:[Amsterdam:[britt, kim]]], 1:[false:[New York:[bob]]]]'
assert resultMap[1].size() == 1
assert resultMap[2].size() == 2
assert resultMap[2][true].Tilburg.name.join(',') == 'mrhaki,liam'

Test the code on Groovy web console.

September 15, 2011

Groovy Goodness: Sort or Remove Duplicates without Changing the Original Collection

We can sort and remove duplicates from collections or arrays in Groovy for a long time. The sort() and unique() methods alter the original collection, so there is a big side effect. Since Groovy 1.8.1 we can use a boolean argument to indicate if we want to mutate the original collection or not. So now we can remove the side effect and leave the original collection or array unchanged.

The reverse() method also accepts this boolean argument since Groovy 1.8.1, but the default behavior was already to leave the original collection unchanged. Now we can explicitly tell the reverse() method to change the original collection.

class User implements Comparable {
    String username, email
    boolean active
    
    int compareTo(Object other) {
        username <=> other.username
    }
    
    String toString() { "[User:$username,$email,$active]" }
}

def mrhaki1 = new User(username: 'mrhaki', email: 'mrhaki@localhost', active: false)
def mrhaki2 = new User(username: 'mrhaki', email: 'user@localhost', active: true)

def hubert1 = new User(username: 'hubert', email: 'user@localhost', active: false)
def hubert2 = new User(username: 'hubert', email: 'hubert@localhost', active: true)

def users = [mrhaki1, mrhaki2, hubert1, hubert2]


/* Sort */
def sortedUsers = users.sort(mutate = false)  // Don't mutate original List
assert sortedUsers == [hubert1, hubert2, mrhaki1, mrhaki2]
assert users == [mrhaki1, mrhaki2, hubert1, hubert2]

// Default behaviour is to change original collection
sortedUsers = users.sort() 
assert sortedUsers == [hubert1, hubert2, mrhaki1, mrhaki2]
assert users == [hubert1, hubert2, mrhaki1, mrhaki2]


/* Unique */
def uniqueUsers = users.unique(mutate = false)  // Don't mutate original List
assert uniqueUsers == [hubert1, mrhaki1]
assert users == [hubert1, hubert2, mrhaki1, mrhaki2]

// Default behaviour is to change original collection
uniqueUsers = users.unique()   
assert uniqueUsers == [hubert1, mrhaki1]
assert users == [hubert1, mrhaki1]


/* Reverse */
def reverseUsers = users.reverse()  // mutate false is default
assert reverseUsers == [mrhaki1, hubert1]
assert users == [hubert1, mrhaki1]

// Default behaviour is to leave original collection alone
reverseUsers = users.reverse(mutate = true)  // Mutate original list
assert reverseUsers == [mrhaki1, hubert1]
assert users == [mrhaki1, hubert1]

You can try this code in Groovy web console.

September 13, 2011

Groovy Goodness: Find Elements Matching Groovy Truth

In Groovy 1.8.1 we can use the find() and findAll() methods to find the elements in for example a List wich complies to Groovy truth. The find() and findAll() methods are defined in the Groovy GDK on the Object class, so we can use it for every object that can be iterated.

class User {
    boolean enabled
    
    Boolean asBoolean() {
        enabled
    }
}

def items = [0, false, null, [], [:], '', new User(enabled: false), 'Groovy rocks!', 101]

assert items.find() == 'Groovy rocks!'

assert items.findAll() == ['Groovy rocks!', 101]

June 3, 2011

Groovy Goodness: Add AST Transformations Transparently to Scripts

With Groovy 1.8 we can add compilation customizers when for example we want to run a Groovy script from our application code. Cedric Champeau has a nice blog post about this feature. And we already learned about the import customizer in a previous Groovy Goodness blog post.

Another customizer is the ASTTransformationCustomizer. We can use this customizer to add an AST transformation to a script. The AST transformation is then applied to all classes in the script. This means we can only apply transformations that can be used at class level. Another thing we need to notice is that we cannot set parameters for the AST transformation, so only the defaults for the parameters are used.

We can use both local and global AST transformations with the ASTTransformationCustomizer. For a local transformation we use the annotation class, for a global transformation we pass the AST transformation class to the constructor.

package com.mrhaki.blog

import org.codehaus.groovy.control.customizers.ASTTransformationCustomizer
import org.codehaus.groovy.control.CompilerConfiguration
import groovy.transform.Canonical

def conf = new CompilerConfiguration()
conf.addCompilationCustomizers(new ASTTransformationCustomizer(Canonical))

def shell = new GroovyShell(conf)
shell.evaluate '''
package com.mrhaki.blog

class User {
    String username, fullname
}

// TupleConstructor is added by Canonical transformation.
def user = new User('mrhaki', 'Hubert A. Klein Ikkink')
// ToString is added by Canonical transformation.
assert user.toString() == 'com.mrhaki.blog.User(mrhaki, Hubert A. Klein Ikkink)'

// AST transformation is also applied to the Script class.
assert this.toString() == 'com.mrhaki.blog.Script1()'
'''

May 31, 2011

Groovy Goodness: Transforming Reader Input to Writer Output

With Groovy we can immediately transform the input from a Reader object(like a file, URL or other input type) to a Writer object (like a file, URL or other output type). Groovy adds the transformLine(Writer, Closure) and transformChar(Writer, Closure) methods to the Reader class. We need to pass the Writer object that will contain the transformed output as the first argument. The second argument is a closure with the rules for the transformation that needs to be applied.

def reader = new StringReader('''\
Groovy's support
for transforming reader input to writer output.
''')

def writer = new StringWriter()

reader.transformLine(writer) { line ->  
    if (line.matches(~/^Groovy.*/)) {
        line = '>>' + line.replaceAll('Groovy', 'GROOVY') + '<< '
    }
    line
}

def resultTransformLine = writer.toString()

reader = new StringReader(resultTransformLine)
writer = new StringWriter()
reader.transformChar(writer) { ch ->
    ch in ['\n', '\r'] ? '' : ch
}

assert writer.toString() == ">>GROOVY's support<< for transforming reader input to writer output."