Since Groovy 2.3 we can easily create a fluent API for our classes with the @Builder
AST transformation. We can apply the annotation to our classes and the resulting class file will have all the necessary methods to support a fluent API. We can customize how the fluent API is generated with different annotation parameters. In Groovy code we already can use the with
method to have a clean way to set property values or use the named constructor arguments. But if our classes need to be used from Java it is nice to give the Java developers a fluent API for our Groovy classes.
In the following sample we apply the @Builder
annotation to a simple class Message
with some properties. We leave everything to the default settings and then the resulting Message
class file will have a new builder
method that return an internal helper class we can use to set our properties. For each property their is a new method with the name of the property so we can set a value. And finally our class contains a build
that will return a new instance of the Message
class with the correct values for the properties.
Continue reading →
Since Groovy 1.8 we can use the trampoline
method for a closure to get better recursive behavior for tail recursion. All closure invocations are then invoked sequentially instead of stacked, so there is no StackOverFlowError
. As from Groovy 2.3 we can use this for recursive methods as well with the @TailRecursive
AST transformation. If we apply the annotation to our method with tail recursion the method invocations will be sequential and not stacked, like with the closure's trampoline
method.
import groovy.transform.TailRecursive
@TailRecursive
long sizeOfList(list, counter = 0) {
if (list.size() == 0) {
counter
} else {
sizeOfList(list.tail(), counter + 1)
}
}
// Without @TailRecursive a StackOverFlowError
// is thrown.
assert sizeOfList(1..10000) == 10000
Continue reading →
Running Groovy scripts with GroovyShell
is easy. We can for example incorporate a Domain Specific Language (DSL) in our application where the DSL is expressed in Groovy code and executed by GroovyShell
. To limit the constructs that can be used in the DSL (which is Groovy code) we can apply a SecureASTCustomizer
to the GroovyShell
configuration. With the SecureASTCustomizer
the Abstract Syntax Tree (AST) is inspected, we cannot define runtime checks here. We can for example disallow the definition of closures and methods in the DSL script. Or we can limit the tokens to be used to just a plus or minus token. To have even more control we can implement the StatementChecker
and ExpressionChecker
interface to determine if a specific statement or expression is allowed or not.
In the following sample we first use the properties of the SecureASTCustomizer
class to define what is possible and not within the script:
Continue reading →
The @ToString
AST transformation has several parameters we can define to customize the generated code for the toString
method. We have already seen some of the parameters in an earlier blog post, but in new Groovy releases some extra parameters were added.
For example we can leave out the package name of the class with the parameter includePackage
. If we set the value to false
the package name is not included:
Continue reading →
In a previous post we learned about the Writable
interface and how the GString implementation implements this interface. In Groovy we can also use a closure as an implementation of the Writable
interface. The Closure
class has the method asWritable()
that will return a version of the closure with an implementation of the writeTo()
method. The Writer
object that is used as an argument for the writeTo()
method will be passed as argument to the closure. The asWritable()
method also adds a toString()
implementation for the closure to return the result of a closure as a String
.
In the following code we write a sample make()
method. The make()
method return a Writable
closure. The closure is only executed when the writeTo()
or toString()
method is invoked.
Continue reading →
The Groovy API has the interface Writable. Classes that implement this interface are capable of writing their selves to a java.io.Writer
object. The interface has one method writeTo()
where the code is that writes the contents to a given Writer
instance. Most implementations will also use the implementation of the writeTo()
method in their toString()
implementation.
The GString implementation in Groovy also implements the Writable
interface. This means we can redirect the GString contents to some Writer
instance if we want to. In the following code we use a FileWriter
to write the contents of a GString to a file:
Continue reading →
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
Continue reading →
When we mock or stub methods we can use the method arguments passed to the method in the response for the mocked or stubbed method. We must write a closure after the rightShift operator (>>
) and the closure arguments will resemble the arguments of the mocked or stubbed method. Alternatively we can use a single non-typed argument in the closure and this will contains the method argument list.
Let's create a specification where we use this feature. In the following sample we use a mock for the AgeService
used in the class under test. The method allowedMaxTime()
is invoked by the class under test and basically should return the maximum hour of the day a show can be broadcasted. In our specification we use the name of the show to return different values during the test.
Continue reading →
Spock has some great features to write specifications or tests that are short and compact. One of them is the old()
method. The old()
method can only be used in a then:
block. With this method we get the value a statement had before the when:
block is executed.
Let's see this with a simple example. In the following specification we create a StringBuilder
with an initial value. In the then:
block we use the same initial value for the assertion:
Continue reading →
To add logging to a class with Groovy is easy. We apply one of the logging AST transformations and we get a variable in our class named log
. We can invoke methods on the variable and the AST transformation will also automatically wrap those statement in a "if-logging-level-is-enabled" block. The transformation is even intelligent enough to do this only if Strings are added or a GString is used. If we want to use a different name than log
we simply use the value
parameter of the annotation. We assign the name we want to use and then we can use it in our code.
import groovy.util.logging.*
@Log(value = 'LOGGER')
class Event {
String name
Boolean started
void start() {
LOGGER.info "Event $name is started"
started = true
}
}
final Event event = new Event(name: 'gr8Conf')
event.start()
Continue reading →
Willem Cheizoo already wrote an blog post about How to test for an exception with JUnit and this inspired me to write the same sample with Spock. In Spock we can use the thrown()
method to check for exceptions. We can use it in a then:
block of our test.
import spock.lang.*
public class JDrivenServiceSpecification extends Specification {
private JDrivenService service = new JDrivenService()
def "publishArticle throws ArticleNotFoundException() {
when:
service.publishArticle null
then:
final ArticleNotFoundException exception = thrown()
// Alternate syntax: def exception = thrown(ArticleNotFoundException)
exception.message == 'Article not found please provide an article to publish'
}
}
Continue reading →