Loading...

February 28, 2017

Gradle Goodness: Skip Task When Input Empty Using @SkipWhenEmpty Annotation

Gradle has excellent incremental build support. This means that Gradle can determine if a task needs to be executed based on the input and output of that task. If for example nothing changed in one of the input and output files, then the task can be skipped. We can add incremental build support for our custom tasks by defining the input and output of the task. We can also define that a task can be skipped when a collection of files or a directory that is the input of the task are empty or not exists. Gradle offers the @SkipWhenEmpty annotation we can apply on the input of our task.

In the next example we have a task DisplayTask that prints the contents of files in a directory. We want to skip the task when the directory is empty.

task display(type:DisplayTask) {
    contentDir = file('src/content')
}

class DisplayTask extends DefaultTask {

    @SkipWhenEmpty
    @InputDirectory
    File contentDir

    DisplayTask() {
        description = 'Show contents of files'
    }

    @TaskAction
    void printMessages() {
        contentDir.eachFile { file ->
            println file.text
        }
    }

}

When we run the task without any files in the input directory we see in the output NO-SOURCE for our task. If we wouldn't have added the @SkipWhenEmpty annotation the build would have failed.

$ gradle display
:display NO-SOURCE

BUILD SUCCESSFUL

Total time: 0.866 secs

Let's add a file in the directory src/content and re-run the task:

$ gradle display
:display
Gradle rocks!


BUILD SUCCESSFUL

Total time: 0.866 secs

Written with Gradle 3.4.

February 27, 2017

Grails Goodness: Custom JSON and Markup Views For Default REST Resources

In Grails we can use the @Resource annotation to make a domain class a REST resource. The annotation adds a controller as URL endpoint for the domain class. Values for the domain class properties are rendered with a default renderer. We can use JSON and markup views to customize the rendering of the domain class annotated with a @Resource annotation. First we must make sure we include views plugin in our build configuration. Then we must create a directory in the grails-app/views directory with the same name as our domain class name. Inside the directory we can add JSON and markup views with names that correspond with the controller actions. For example a file index.gson or index.gml for the index action. We can also create a template view that is automatically used for a resource instance by adding a view with the name of the domain class prefixed with an underscore (_).

In the next example application we create a custom view for the Book domain class that is annotated with the @Resource annotation:

// File: grails-app/domain/mrhaki/sample/Book.groovy
package mrhaki.sample

import grails.rest.Resource

@Resource(uri = '/books')
class Book {
    
    String title
    String isbn
    
    static constraints = {
        title blank: false
        isbn blank: false
    }    
}

Next we must make sure the Grails views code is available as a dependency. In our build.gradle file we must have the following dependencies in the dependencies {} block:

// File: build.gradle
...
dependencies {
    ....
    // Support for JSON views.
    compile "org.grails.plugins:views-json:1.1.5"
    // Support for markup views.
    compile "org.grails.plugins:views-markup:1.1.5"
    ....
}
...

It is time to create new JSON views for JSON responses. We create the directory grails-app/views/book/ and the file _book.gson. This template file is automatically used by Grails now when a Book instances needs to be rendered:

// File: grails-app/views/book/_book.gson
import grails.util.Environment
import mrhaki.sample.Book

model {
    Book book
}

json {
    id book.id
    version book.version
    title book.title
    isbn book.isbn
    information {
        generatedBy 'Sample application'
        grailsVersion Environment.grailsVersion
        environment Environment.current.name
    }
}

We also create the file index.gson to support showing multiple Book instances:

// File: grails-app/views/book/index.gson
import mrhaki.sample.Book

model {
    List<Book> bookList  
} 

// We can use template namespace
// method with a Collection.
json tmpl.book(bookList)

If we also want to support XML we need to create extra markup views. First we a general template for a Book instance with the name _book.gml:

// File: grails-app/views/book/_book.gml
import grails.util.Environment
import mrhaki.sample.Book

model {
    Book book
}

xmlDeclaration()
book {
    id book.id
    title book.title
    isbn book.isbn
    information {
        generatedBy 'Sample application'
        grailsVersion Environment.grailsVersion
        environment Environment.current.name
    }
}

Next we create the file index.gml to show Book instances. Note we cannot use the template namespace in the markup view opposed to in the JSON view:

// File: grails-app/views/book/_book.gml
import grails.util.Environment
import mrhaki.sample.Book

model {
    List<Book> bookList
}

xmlDeclaration()
books {
    bookList.each { bookInstance ->
        book {
            id bookInstance.id
            title bookInstance.title
            isbn bookInstance.isbn
            information {
                generatedBy 'Sample application'
                grailsVersion Environment.grailsVersion
                environment Environment.current.name
            }
        }
    }
}

We start our Grails application and use cUrl to invoke our REST resource:

$ curl -H Accept:application/xml http://localhost:8080/books/1
<?xml version='1.0' encoding='UTF-8'?>
<books>
    <book>
        <id>1</id><title>Gradle Dependency Management</title><isbn>978-1784392789</isbn><information>
            <generatedBy>Sample application</generatedBy><grailsVersion>3.2.6</grailsVersion><environment>development</environment>
        </information>
    </book><book>
        <id>2</id><title>Gradle Effective Implementation Guide</title><isbn>978-1784394974</isbn><information>
            <generatedBy>Sample application</generatedBy><grailsVersion>3.2.6</grailsVersion><environment>development</environment>
        </information>
    </book>
</books>

$ curl -H Accept:application/xml http://localhost:8080/books/1
<?xml version='1.0' encoding='UTF-8'?>
<book>
    <id>1</id><title>Gradle Dependency Management</title><isbn>978-1784392789</isbn><information>
        <generatedBy>Sample application</generatedBy><grailsVersion>3.2.6</grailsVersion><environment>development</environment>
    </information>
</book>

$ curl -H Accept:application/json http://localhost:8080/books
[
    {
        "id": 1,
        "version": 0,
        "title": "Gradle Dependency Management",
        "isbn": "978-1784392789",
        "information": {
            "generatedBy": "Sample application",
            "grailsVersion": "3.2.6",
            "environment": "development"
        }
    },
    {
        "id": 2,
        "version": 0,
        "title": "Gradle Effective Implementation Guide",
        "isbn": "978-1784394974",
        "information": {
            "generatedBy": "Sample application",
            "grailsVersion": "3.2.6",
            "environment": "development"
        }
    }
]

$ curl -H Accept:application/json http://localhost:8080/books/1
{
    "id": 1,
    "version": 0,
    "title": "Gradle Dependency Management",
    "isbn": "978-1784392789",
    "information": {
        "generatedBy": "Sample application",
        "grailsVersion": "3.2.6",
        "environment": "development"
    }
}
$

Written with Grails 3.2.6.

February 21, 2017

Grails Goodness: Using Domain Classes Without Persistence

Normally when we create a domain class in Grails we rely on GORM for all the persistence logic. But we can use the static property mapWith with the value none to instruct Grails the domain class is not persisted. This can be useful for example if we want to use a RestfulController for a resource and use the default data binding support in the RestfulController. The resource must be a domain class to make it work, but we might have a custom persistence implementation that is not GORM. By using the mapWith property we can still have benefits from the RestfulController and implement our own persistence mechanism.

In the following example we have a simple Book resource. We define it as a domain class, but tell Grails the persistence should not be handled by GORM:

// File: grails-app/domain/mrhaki/sample/Book.groovy
package mrhaki.sample

import grails.rest.Resource

@Resource(uri = '/books', superClass= BookRestfulController)
class Book {
    
    static mapWith = 'none'
    
    String title
    String isbn
    
    static constraints = {
        title blank: false
        isbn blank: false
        
        // Allow to set id property directly in constructor.
        id bindable: true
    }
    
}

The application also has a Grails service BookRepositoryService that contains custom persistence logic for the Book class. In the following RestfulController for the Book resource we use BookRepositoryService and override methods of RestfulController to have a fully working Book resource:

// File: grails-app/controllers/mrhaki/sample/BookRestfulController.groovy
package mrhaki.sample

import grails.rest.RestfulController

class BookRestfulController extends RestfulController<Book> {
    
    BookRepositoryService bookRepositoryService
    
    BookRestfulController(final Class<Book> resource) {
        super(resource)
    }

    BookRestfulController(final Class<Book> resource, final boolean readOnly) {
        super(resource, readOnly)
    }

    @Override
    protected Book queryForResource(final Serializable id) {
        bookRepositoryService.get(Long.valueOf(id))
    }
    
    @Override
    protected List<Book> listAllResources(final Map params) {
        bookRepositoryService.all
    }

    @Override
    protected Integer countResources() {
        bookRepositoryService.total
    }

    @Override
    protected Book saveResource(final Book resource) {
        bookRepositoryService.add(resource)
    }

    @Override
    protected Book updateResource(final Book resource) {
        bookRepositoryService.update(resource)
    }

    @Override
    protected void deleteResource(final Book resource) {
        bookRepositoryService.remove(resource.id)
    }
}

Written with Grails 3.2.6.

February 18, 2017

Groovy Goodness: Using The Call Operator ()

In Groovy we can add a method named call to a class and then invoke the method without using the name call. We would simply just type the parentheses and optional arguments on an object instance. Groovy calls this the call operator: (). This can be especially useful in for example a DSL written with Groovy. We can add multiple call methods to our class each with different arguments. The correct method is invoked at runtime based on the arguments.

In the following example we have User class with three call method implementations. Next we see how we invoke the call methods, but without typing the method name and just use the parenthesis and arguments:

import groovy.transform.ToString
@ToString(includeNames = true)
class User {
    
    String name
    String alias
    String email
    String website
    
    // Set name.
    def call(final String name) {
        this.name = name
        this
    }
    
    // Use properties from data to assign
    // values to properties.
    def call(final Map data) {
        this.name = data.name ?: name
        this.alias = data.alias ?: alias
        this.email = data.email ?: email
        this.website = data.website ?: website
        this
    }
    
    // Run closure with this object as argument.
    def call(final Closure runCode) {
        runCode(this)
    }
    
}


def mrhaki = 
    new User(
        name: 'Hubert Klein Ikkink',
        alias: 'mrhaki',
        email: 'mrhaki@email.nl',
        website: 'https://www.mrhaki.com')
        
// Invoke the call operator with a String.
// We don't have to explicitly use the
// call method, but can leave out the method name.
// The following statement is the same:
// mrhaki.call('Hubert A. Klein Ikkink')
mrhaki('Hubert A. Klein Ikkink')

// Of course parentheses are optional in Groovy.
// This time we invoke the call method
// that takes a Map arguemnt.
mrhaki email: 'h.kleinikkink@email.nl'

assert mrhaki.name == 'Hubert A. Klein Ikkink'
assert mrhaki.alias == 'mrhaki'
assert mrhaki.email == 'h.kleinikkink@email.nl'
assert mrhaki.website == 'https://www.mrhaki.com'


// We can pass a Closure to the call method where
// the current instance is an argument for the closure.
// By using the call operator we have a very dense syntax.
mrhaki { println it.alias }  // Output: mrhaki

// Example to transform the user properties to JSON.
def json =  mrhaki { 
    new groovy.json.JsonBuilder([vcard: [name: it.name, contact: it.email, online: it.website]]).toString()
} 

assert json == '{"vcard":{"name":"Hubert A. Klein Ikkink","contact":"h.kleinikkink@email.nl","online":"https://www.mrhaki.com"}}'

Written with Groovy 2.4.8.

February 17, 2017

Groovy Goodness: Creating Root JSON Array With JsonBuilder

To create JSON output with Groovy is easy using JsonBuilder and StreamingJsonBuilder. In the samples mentioned in the links we create a JSON object with a key and values. But what if we want to create JSON with a root JSON array using JsonBuilder or StreamingJsonBuilder? It turns out to be very simple by passing a list of values using the constructor or using the implicit method call.

In the following example we use JsonBuilder to create a root JSON array:

import groovy.json.JsonBuilder

// Example class.
@groovy.transform.Immutable
class Villain { 
    String name 
}

// A list of Villain objects that needs to transformed
// to a JSON array.
def list = ['The Joker', 'Penguin', 'Catwoman', 'Harley Quinn'].collect { name -> new Villain(name) }

// We create a new JsonBuilder and 
// use the list of Villain objects
// as argument for the constructor
// to create a root JSON array.
def json1 = new JsonBuilder(list)

assert json1.toString() == '[{"name":"The Joker"},{"name":"Penguin"},{"name":"Catwoman"},{"name":"Harley Quinn"}]'


// Here we use the no-argument constructor
// to create a JsonBuilder.
// Then we use the instance implicit
// method call with the list of Villain
// objects as arguments
def json2 = new JsonBuilder()
json2(list)

assert json2.toString() == '[{"name":"The Joker"},{"name":"Penguin"},{"name":"Catwoman"},{"name":"Harley Quinn"}]'

In the next example we use StreamingJsonBuilder to create a root JSON array:

import groovy.json.StreamingJsonBuilder

// Example class.
@groovy.transform.Immutable
class Villain { 
    String name 
}

// A list of Villain objects that needs to transformed
// to a JSON array.
def list = ['The Joker', 'Penguin', 'Catwoman', 'Harley Quinn'].collect { name -> new Villain(name) }

// Here we use the no-argument constructor
// to create a JsonBuilder.
// Then we use the instance implicit
// method call with the list of Villain
// objects as arguments
def json = new StringWriter()
def jsonBuilder = new StreamingJsonBuilder(json)
jsonBuilder(list)

assert json.toString() == '[{"name":"The Joker"},{"name":"Penguin"},{"name":"Catwoman"},{"name":"Harley Quinn"}]'

There is also an implicit method call that takes an extra Closure argument. For each element in the list the Closure is invoked with the element as argument. This way we can customize the root JSON array output using the properties of the object that is in the list. In the following example we use both the JsonBuilder and StreamingJsonBuilder classes to transform the elements in the list:

import groovy.json.JsonBuilder
import groovy.json.StreamingJsonBuilder

// Example class.
@groovy.transform.Immutable
class Villain { 
    String name 
}

// A list of Villain objects that needs to transformed
// to a JSON array.
def list = ['The Joker', 'Penguin', 'Catwoman', 'Harley Quinn'].collect { name -> new Villain(name) }

// We create a new JsonBuilder and 
// then we use the instance implicit
// method call with the list of Villain
// objects as arguments and closure
// to transform each Villain object
// in the root JSON array.
def json1 = new JsonBuilder() 
json1(list) { Villain villain ->
    name villain.name
    initials villain.name.split(' ').collect { it[0].toUpperCase() }.join()
}

assert json1.toString() == '[{"name":"The Joker","initials":"TJ"},{"name":"Penguin","initials":"P"},{"name":"Catwoman","initials":"C"},{"name":"Harley Quinn","initials":"HQ"}]'


// We can use the same implicit
// method call for a list and 
// closure to transform each element
// to a root JSON array.
def json = new StringWriter()
def json2 = new StreamingJsonBuilder(json)
json2(list) { Villain villain -> 
    name villain.name
    initials villain.name.split(' ').collect { it[0].toUpperCase() }.join()
}

assert json.toString() == '[{"name":"The Joker","initials":"TJ"},{"name":"Penguin","initials":"P"},{"name":"Catwoman","initials":"C"},{"name":"Harley Quinn","initials":"HQ"}]'

Written with Groovy 2.4.8

February 1, 2017

Gradle Goodness: Check Operating System In Build Scripts

Sometimes we want to check which operating system is used in our build script. For example we have tasks that need to run if the operating system is Windows and not for other operating systems. Gradle has an internal class org.gradle.nativeplatform.platform.internal.DefaultOperatingSystem, but we should not use this class in our build scripts. The class is used internally by Gradle and can change without warning. If we would depend on this class and it changes we break our build scripts. But we can use a class from Ant that is already in Gradle's class path: org.apache.tools.ant.taskdefs.condition.Os. The class has several methods and constants to check the operating system name, version and architecture. The values are based on the Java system properties os.name, os.version and os.arch.

In the following example build script we use import static to include the Os class, so we can directly invoke the methods and refer to the constants in the Os class. We add some tasks that have a condition check with onlyIf so the task only runs when the condition in the closure is true. The task osInfo simply shows values from the Os class:

// File: build.gradle
import static org.apache.tools.ant.taskdefs.condition.Os.*

task os {
    description 'Run all conditional os tasks'
}

// Create 3 tasks that simply print
// the task name that is executed
// if the build scripts runs on the
// recognized operating system.
[FAMILY_WINDOWS, FAMILY_UNIX, FAMILY_MAC].each { osName ->

    // Create task.
    tasks.create(osName) {
        description "Run when OS is ${osName}"

        // Add condition to check operating system.
        onlyIf { isFamily(osName) }

        doLast {
            println "Execute task '${it.name}'"
        }
    }

    // Add task as dependency for the os task.
    os.dependsOn osName
}


task osInfo {
    description 'Show information about the operating system'
    doLast {
        println "Family:       ${OS_NAME}"
        println "Version:      ${OS_VERSION}"
        println "Architecture: ${OS_ARCH}"
    }
}

Let's run the os and osInfo tasks on MacOS:

$ gradle os osInfo
mac
Execute task 'mac'
:unix
Execute task 'unix'
:windows SKIPPED
:os
:osInfo
Family:       mac os x
Version:      10.12.3
Architecture: x86_64

BUILD SUCCESSFUL

Total time: 0.697 secs

Written with Gradle 3.3.

January 16, 2017

Groovy Goodness: Uncapitalize Strings

Since Groovy 2.4.8 we can use the uncapitalize method on CharSequence objects. The capitalize method was already available for a long time, but now we have the opposite as well.

In the following example we see that the uncapitalize method only replaces the first letter of a String value to lower case:

assert 'Groovy'.uncapitalize() == 'groovy'
assert 'MrHaki'.uncapitalize() == 'mrHaki'

String message = 'Groovy Rocks!'
assert message.uncapitalize() == 'groovy Rocks!'

Written with Groovy 2.4.8.

January 2, 2017

Awesome Asciidoctor: Using Filename Starting With Dot As Block Title

Adding a block title in Asciidoctor is easily done by adding a line at the top of the block that starts with a dot (.). The text following the dot is then used as the title of the block. But if the text of the title itself starts with a dot (.) Asciidoctor get's confused. For example if we want to use a filename that starts with a dot (.filename) we must use different syntax to set the block title with the filename.

In the next Ascciidoc markup sample we use different ways to set the block title for a code block with a filename that starts with a dot. First we use the title attribute for the block. Another solution is to use the Unicode value for the dot. Next we enclose the filename in back ticks (`) which also formats the filename with a monotype font. We can also separate the first dot with the dotted filename with the document attribute {blank}. Also we can define the dot as document attribute and use it in the title. And finally we can define the filename via a document attribute and reference the document attribute in the block title:

= Filenames starting with dot (.)

Several samples showing how to set block title when title starts with dot (`.`).

Code block title is filename that starts with dot (`.`), which confuses the parser:

[source,json]
// Title cannot be parsed correctly
// because of the 2 dots.
..eslintrc
----
{
    "key": "value"
}
----

Using explicit title attribute:

// Instead of using . notation
// for block title, we use the
// explicit block attribute
// title definition.
[source,json,title='.eslintrc']
----
{
    "key": "value"
}
----

Use Unicode value for dot:

[source,json]
// Use hexadecimal Unicode replacement for
// starting dot (.) in filename.
.&#x002E;eslintrc
// (Or with decimals: .&#46;eslintrc)
----
{
    "key": "value"
}
----

Format filename as code:

[source,json]
// Put filename between back ticks (`)
// and title is recognized again and
// nicely formatted with monotype font.
.`.eslintrc`
----
{
    "key": "value"
}
----

Using `\{blank}` document attribute to separate
title dot and filename:

[source,json]
// Separate title and filename with
// {blank} document attribute.
.{blank}.eslintrc
----
{
    "key": "value"
}
----

Using document attribute to define dot and use with filename:

[source,json]
// Section title is also parsed correctly
// if we use a document attribute
// to reflect dot.
:dot: .
.{dot}eslintrc
----
{
    "key": "value"
}
----

Using document attribute to set filename:

[source,json]
// Section title is also parsed correctly
// if we use a document attribute
// with the filename.
:snippetFilename: .eslintrc
.{snippetFilename}
----
{
    "key": "value"
}
----

[source,json]
// We can re-use the same document attribute
// for other code sections.
:snippetFilename: .jslintrc
.{snippetFilename}
----
{
    "key": "value"
}
----

When we generate a HTML version of this markup we get the following result:

Written with Asciidoctor 1.5.4

December 20, 2016

Gradle Goodness: Run Task Ignoring Up-to-date Checks

Gradle builds are fast because Gradle supports incremental tasks. This means Gradle can determine if input or output of task has changed, before running the task. If nothing has changed a task is marked a up-to-date and the task is not executed, otherwise the task is executed. If we want execute a task even if it is up-to-date we must use the command line option --rerun-tasks.

In the following example we run the assemble task for a simple Java project, and we see all tasks are executed. When we invoke the assemble task again we see the tasks are all up-to-date:

$ gradle assemble

:compileJava
:processResources
:classes
:jar
:assemble

BUILD SUCCESSFUL

Total time: 1.765 secs
$ gradle assemble

:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:jar UP-TO-DATE
:assemble UP-TO-DATE

BUILD SUCCESSFUL

Total time: 0.715 secs
$

To run all tasks without an up-to-date check we use the option --rerun-tasks:

$ gradle --rerun-tasks assemble
:compileJava
:processResources
:classes
:jar
:assemble

BUILD SUCCESSFUL

Total time: 1.037 secs
$

Written with Gradle 3.2.1.

December 19, 2016

Spring Sweets: Add (Extra) Build Information To Info Endpoint

With Spring Boot Actuator we get some useful endpoints in our application to check on our application when it is running. One of the endpoints is the /info endpoint. We can add information about our application if Spring Boot finds a file META-INF/build-info.properties in the classpath of our application. With the Gradle Spring Boot plugin we can generate the build-info.properties file. When we apply the Gradle Spring Boot plugin to our project we get a Gradle extension springBoot in our build file. With this extension we can configure Spring Boot for our project. To generate project information that is used by the /info endpoint we must add the method statement buildInfo() inside the springBoot extension. With this method statement the Gradle Spring Boot plugin generates a file build/main/resources/META-INF/build-info.properties..

// File: build.gradle
plugins {
    id 'org.springframework.boot' version '1.4.2.RELEASE'
}
...
springBoot {
    // This statement tells the Gradle Spring Boot plugin
    // to generate a file 
    // build/resources/main/META-INF/build-info.properties
    // that is picked up by Spring Boot to display
    // via /info endpoint.
    buildInfo()
}
...

Let's run our application and send a request for /info:

$ http -b localhost:8080/info
{
    "build": {
        "artifact": "spring-boot-sample",
        "group": "mrhaki.spring",
        "name": "sample-mrhaki",
        "time": 1482139076000,
        "version": "0.3.0"
    }
}
$

To override the default properties or to add new properties we must provide a configuration closure to the buildInfo method. If we a built-in key as the name of the property it is overridden with a new value, otherwise the key is added as a new property. In the following example we add some extra properties and override the properties time and name:

// File: build.gradle
...
springBoot {
    buildInfo {
        // Generate extra build info.
        additionalProperties = [
                by: System.properties['user.name'],
                operatingSystem: "${System.properties['os.name']} (${System.properties['os.version']})",
                continuousIntegration: System.getenv('CI') ? true: false,
                machine: InetAddress.localHost.hostName,
                // Override buildInfo property time
                time: buildTime(),
                // Override name property
                name: 'sample-springboot-app'
        ]
    }
}

def buildTime() {
    final dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ssZ")
    dateFormat.timeZone = TimeZone.getTimeZone('GMT')
    dateFormat.format(new Date())
}
...

We restart the application and invoke the /info endpoint to get more results for the build:

$ http -b localhost:8080/info
{
    "build": {
        "artifact": "spring-boot-sample",
        "by": "mrhaki",
        "continuousIntegration": "false",
        "group": "mrhaki.spring",
        "machine": "mrhaki-laptop-2015.local",
        "name": "sample-springboot-app",
        "operatingSystem": "Mac OS X (10.12.2)",
        "time": "2016-12-19 09:16:50+0000",
        "version": "0.3.0"
    }
}
$

Written with Spring Boot 1.4.2.RELEASE.