We can add a resourcebundle property file to our application to support internationalization (i18n). The file contains key-value pairs where the value is a localized value per supported language or locale. In IntelliJ IDEA we can easily see which keys are not yet translated. We open a resourcebundle property file and click on the ResourceBundle
tab at the bottom of the editor. We get a list of all available keys on the left and on the right a text area per supported language with the translated values. If a key is not translated for all supported languages it will be colored in red. We only have to select the keys in red and fill in the values on the right for the given languages.
Continue reading →
We can use the run-script
command to run Groovy scripts within the context of a Grails application. We can pass one or more Groovy scripts as argument to the run-script
command. The Grails environment will be configured and we can access the Spring application context, domain classes, Grails services and more. Basically everything we can do in the Grails console or shell can be saved as a Groovy script and run with the run-script
command.
The following Groovy script shows some stats for a Grails application:
Continue reading →
In a previous blog post we have seen how we can use a BaseScript
AST transformation to set a base script class for running scripts. Since Groovy 2.3 we can apply the @BaseScript
annotation on package
and import
statements. Also we can implement a run
method in our Script
class in which we call an abstract method. The abstract method will actually run the script, so we can execute code before and after the script code runs by implementing logic in the run
method.
In the following sample we create a Script
class CustomScript
. We implement the run
method and add the abstract method runCode
:
Continue reading →
Since Groovy 2.3 we can use the @Sortable
annotation to make a class implement the Comparable
interface. Also new comparator
methods are added. All properties of a class are used to implement the compareTo
method. The order of the properties determines the priority used when sorting. With the annotation parameters includes
and excludes
we can define which properties of the class need to be used to implement the compareTo
method.
In the following class with the name Course
we define three properties title
, beginDate
and maxAttendees
. We also apply the @Sortable
annotation. Notice we cannot use int
as a type, because it doesn't implement the Comparable
interface. The class Integer
does.
Continue reading →
We have seen some features of the @Builder
AST transformation in previous and other blog post. We can use another strategy to let the AST transformation generate a class where the class only has a constructor that accepts a builder class. And with @CompileStatic
we can even make sure that all required properties must have a value set by the builder before the constructor accepts the argument. We use the builderStrategy
annotation parameter and set it to InitializerStrategy
:
import groovy.transform.builder.Builder
import groovy.transform.builder.InitializerStrategy
@Builder(builderStrategy = InitializerStrategy)
class Message {
String from, to, subject, body
}
def message = Message.createInitializer()
.from('mrhaki@mrhaki.com')
.subject('Groovy 2.3 is released')
// Returned object is not Message, but
// internal class Message$MessageInitializer
assert !(message instanceof Message)
// Now we can use the initializer in the
// only constructor of Message.
def messageInstance = new Message(message)
assert messageInstance instanceof Message
assert messageInstance.from == 'mrhaki@mrhaki.com'
assert messageInstance.subject == 'Groovy 2.3 is released'
Continue reading →
In a previous post we learned about the new @Builder
AST transformation introduced in Groovy 2.3. We applied to the annotation to our class files and we got a nice fluent API to set property values. But what if we cannot change the class itself, for example if we want to create a fluent API for classes in an external library. Then we can still use the @Builder
AST transformation but we use a different strategy. We can define the builder strategy via a annotation parameter.
In the following sample we assume the Message
class is from an external library and we cannot or do not want to change the class definition. We create a new Groovy class and set the @Builder
annotation on this new class. We use the annotation parameters builderStrategy
to indicate the generated code is not for the new class, but for the class set with the annotation parameter forClass
.
Continue reading →
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 →
Groovy adds a lot of extra methods to the File
object to work with the contents or find and filter files in a directory. These methods are now also added to the java.nio.file.Path
class since Groovy 2.3.
import java.nio.file.*
final Path newFile = Paths.get('output.txt')
if (Files.exists(newFile)) {
Files.delete(newFile)
}
// Different ways to add content.
newFile.write 'START'
newFile.write System.getProperty('line.separator')
newFile << 'Just a line of text'
newFile.withWriterAppend { writer ->
writer.println()
writer.println 'END'
}
// Read contents.
final Path readFilePath = Paths.get('output.txt')
assert readFilePath.readLines().join(';') == 'START;Just a line of text;END'
assert readFilePath.filterLine { it.contains('text') }.toString().normalize() == 'Just a line of text\n'
// Work with Path objects,
// like with File GDK extensions with
// eachFile, eachDir, eachFileRecursive...
final Path root = Paths.get('.')
def paths = root.eachFileMatch(~/.*\.txt$/) {
assert it.toFile().name == 'output.txt'
}
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 →
Writing documentation with Asciidoc is such a treat. We can add markers to our code where we want to explain something in our code. The markers have numbers and are enclosed in <
and >
brackets. The explanation for the markers follows a code listing in a callout list. Here we use the same marker and add extra text to explain the code. We can put the markers in comments in our code so we can use the markers in existing code.
Suppose we have the following piece of documentation where we add two markers (in comments) to some Groovy source code:
Continue reading →
In Grails we can add aliases for standard Grails commands with the alias
command. For example we want to use another name for a command or combine a command with arguments to a single alias. With the following command we create a start-app
alias for the standard run-app
command:
$ grails alias start-app run-app
Alias start-app with value run-app configured
$
Continue reading →
Writing technical documentation with Asciidoc and Asciidoctor is so much fun. Especially the include
macro makes inserting changing content, like source files, a breeze. We only need to maintain the original source file and changes will automatically appear in the generated documentation. We can include only a part of source file using tags. In the source file we add a comment with the following format tag::_tagName_[]
to start the section. We end the section with end::_tagName_[]
. Now in our Asciidoc document we can indicatie the tags we want to include with include::_sourceFile_[tags=_tagName_]
.
Suppose we have the following Groovy source file Sample.groovy
. We want to include the method hello()
in our technical documentation:
Continue reading →