Writing Gradle Plugins

07 December 2016 ~ blog, groovy, gradle

In my last post, Gradle: A Gentle Introduction, I discussed the basics of Gradle and how to get up and running quickly. Now, I am going to dive into the deeper part of the pool and talk about how to write your own Gradle plugins.

First, we need a project to work with. Let’s say that we want to add a custom banner to our build output - who doesn’t love banners? Something like:

  _______ _            ____        _ _     _
 |__   __| |          |  _ \      (_) |   | |
    | |  | |__   ___  | |_) |_   _ _| | __| |
    | |  | '_ \ / _ \ |  _ <| | | | | |/ _` |
    | |  | | | |  __/ | |_) | |_| | | | (_| |_ _ _
    |_|  |_| |_|\___| |____/ \__,_|_|_|\__,_(_|_|_)

We need to create a directory named banner-build and then create a build.gradle file in it with the following starting content:

build.gradle
plugins {
    id 'groovy'
}

We just need a basic starting point. Run ./gradle wrapper --gradle-version=3.2 to generate the wrapper and we are ready to start (we can run /gradlew from here on out).

Now, in order to write out a banner we need to create a custom task that will render it for us:

task banner {
    doFirst {
        if( !project.hasProperty('noBanner') ){
            file('banner.txt').eachLine { line->
                logger.lifecycle line
            }
        }
    }
}

gradle.startParameter.taskNames = [':banner'] + gradle.startParameter.taskNames

This task will add our action to the top of the execution list (the startPrameter modification makes it always run) so that if the noBanner property is not specified, our banner will be loaded from the specified file and displayed to the output log.

We will read our banner from a file, banner.txt in the root of the project - so we will need to create that with the banner content from above. Then, when you run ./gradlew build you will see something like the following:

> ./gradlew build
:banner
  _______ _            ____        _ _     _
 |__   __| |          |  _ \      (_) |   | |
    | |  | |__   ___  | |_) |_   _ _| | __| |
    | |  | '_ \ / _ \ |  _ <| | | | | |/ _` |
    | |  | | | |  __/ | |_) | |_| | | | (_| |_ _ _
    |_|  |_| |_|\___| |____/ \__,_|_|_|\__,_(_|_|_)
:compileJava UP-TO-DATE
:compileGroovy UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:jar
:assemble
:compileTestJava UP-TO-DATE
:compileTestGroovy UP-TO-DATE
:processTestResources UP-TO-DATE
:testClasses UP-TO-DATE
:test UP-TO-DATE
:check UP-TO-DATE
:build

BUILD SUCCESSFUL

Total time: 0.559 secs

Notice also, that we can turn off the banner, passing the -PnoBanner option on the command line or as a property in your gradle.properties file, if you have one - if you run under one of those conditions, the banner will not be printed.

At this point, we have accomplished our original goal and we can go on with our lives…​ until the next project comes along and you need the same sort of functionality. You could just copy and paste this code into your project, but you don’t do that…​ right? That’s where plugins come into play; they allow us to share functionality across different project builds.

To create the plugin, first we need a separate Gradle project for it; create a directory (outside of the one for our demo project), called banner-plugin and add a build.gradle file to it with:

banner-plugin/build.gradle
plugins {
    id 'groovy'
    id 'java-gradle-plugin'
}

version = "0.1.0"
group = "com.stehno.gradle"

sourceCompatibility = 8
targetCompatibility = 8

repositories {
    jcenter()
}

dependencies {
    compile gradleApi()
    compile localGroovy()

    testCompile('org.spockframework:spock-core:1.0-groovy-2.4') {
        exclude module: 'groovy-all'
    }
}

and run gradle wrapper --gradle-version=3.2 in it to generate our wrapper. The build file for a plugin project is a standard Gradle build file, but with the java-gradle-plugin plugin to provide extra tools needed for plugins, as well as dependencies for the Gradle API and it’s associated Groovy distribution. With plugins, the project name is used as part of the unique plugin ID, so it’s generally a good practice to be explicit about the project name using a settings.gradle file:

banner-plugin/settings.gradle
rootProject.name = 'banner-plugin'

The last piece of plugin-specific configuration is the plugin properties file, which is a file in the resources/META-INF/gradle-plugins directory named <group>.<name>.properties, for this example:

banner-plugin/src/main/resources/META-INF/gradle-plugins/com.stehno.gradle.banner-plugin.properties
implementation-class=com.stehno.gradle.banner.BannerPlugin

Now we can create the basic skeleton for our plugin, which is an implementation of the Gradle Plugin<Project> interface:

banner-plugin/src/main/groovy/com/stehno/gradle/banner/BannerPlugin.groovy
package com.stehno.gradle.banner

import org.gradle.api.Plugin
import org.gradle.api.Project

class BannerPlugin implements Plugin<Project> {

    @Override void apply(final Project project) {
        // your config here...
    }
}

This is the main entry point for our plugin. When it is "applied" to the project, the apply(Project) method will be called. If we do a clean build of the project at this point, it will pass, but it does nothing. We need to transfer our functionality (the banner task) from our original build.gradle file to the plugin. Let’s create the plugin task skeleton:

banner-plugin/src/main/groovy/com/stehno/gradle/banner/BannerTask.groovy
package com.stehno.gradle.banner

import org.gradle.api.DefaultTask
import org.gradle.api.tasks.TaskAction

class BannerTask extends DefaultTask {

}

and give it something to do:

@TaskAction
void displayBanner(){
    logger.lifecycle 'Doing something!'
}

Once we have a task, we need to wire it into the plugin so that it is applied to the project. Change the apply(Project) method of our BannerPlugin class to the following:

@Override void apply(final Project project) {
    project.task 'banner', type:BannerTask

    project.gradle.startParameter.taskNames = [':banner'] + project.gradle.startParameter.taskNames
}

This will apply our new task and then cause it to be called whenever the build is run. Now, how do we check our progress? We could build the plugin and deploy it to our original project but that would be quite a lot of round-trip time every time we wanted to test a change, but there is no need for that, Gradle provides a rich test framework which works well with Spock. Let’s create a Spock test for our task:

banner-plugin/src/test/groovy/com/stehno/gradle/banner/BannerTaskSpec.groovy
package com.stehno.gradle.banner

import spock.lang.Specification
import org.junit.Rule
import org.junit.rules.TemporaryFolder
import org.gradle.testkit.runner.BuildResult
import org.gradle.testkit.runner.BuildTask
import org.gradle.testkit.runner.GradleRunner
import org.gradle.testkit.runner.TaskOutcome

class BannerTaskSpec extends Specification {

    @Rule TemporaryFolder projectRoot = new TemporaryFolder()

    def 'simple run'(){
        given:
        File buildFile = projectRoot.newFile('build.gradle')
        buildFile.text = '''
            plugins {
                id 'groovy'
                id 'com.stehno.gradle.banner-plugin'
            }
        '''.stripIndent()

        projectRoot.newFile('banner.txt').text = 'Awesome Banner!'

        when:
        BuildResult result = GradleRunner.create()
            .withPluginClasspath()
            .withProjectDir(projectRoot.root)
            .withArguments('clean build'.split(' '))
            .build()

        then:
        println result.output
    }
}

It’s a bit of code, but it’s not too bad once you dig in. We have a standard Spock test, with a TemporaryFolder rule - this will be our test project directory. Then, we create a build.gradle file for our test with our plugin and the groovy plugin, similar to what our original Gradle file looked like. Next, we use the GradleRunner to create and configure a Gradle environment using our file, which is then executed as a build. The results are then printed out to the command line. If you run ./gradlew test on the project now and view the test output (in the report standard out), you will see:

:banner
Doing something!
:clean UP-TO-DATE
:compileJava UP-TO-DATE
:compileGroovy UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:jar
:assemble
:compileTestJava UP-TO-DATE
:compileTestGroovy UP-TO-DATE
:processTestResources UP-TO-DATE
:testClasses UP-TO-DATE
:test UP-TO-DATE
:check UP-TO-DATE
:build

BUILD SUCCESSFUL

Total time: 2.019 secs

where we can see our output and we have a way to quickly test our new task. So, moving onward, we need to add the real functionality to our task. Update the displayBanner() method to:

@TaskAction
void displayBanner(){
    if( !project.hasProperty('noBanner') ){
        project.file('banner.txt').eachLine { line->
            logger.lifecycle line
        }
    }
}

Notice that we prefixed project. before the file() call since we are no longer directly in the "project" scope, but other than that this code was copied right from our original build file. If you run the test, you see our message in the test output:

:banner
Awesome banner!
:clean UP-TO-DATE
:compileJava UP-TO-DATE
:compileGroovy UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:jar
:assemble
:compileTestJava UP-TO-DATE
:compileTestGroovy UP-TO-DATE
:processTestResources UP-TO-DATE
:testClasses UP-TO-DATE
:test UP-TO-DATE
:check UP-TO-DATE
:build

BUILD SUCCESSFUL

Total time: 2.019 secs

Our test is good, but it doesn’t really verify anything, it just prints out the build output. Let’s make it verify that the build passed and that our expected message is in the output - the then: block becomes:

then:
result.tasks.every { BuildTask task ->
    task.outcome == TaskOutcome.SUCCESS || task.outcome == TaskOutcome.UP_TO_DATE
}

result.output.contains('Awesome Banner!')

The test will no longer generate the build output to the command line, but we are actually verifying the expected behavior.

We can test the noBanner property support as well, but we should also refactor the test a bit so that shared code is reused - now our test looks like:

banner-plugin/src/test/groovy/com/stehno/gradle/banner/BannerTaskSpec.groovy
package com.stehno.gradle.banner

import spock.lang.Specification
import org.junit.Rule
import org.junit.rules.TemporaryFolder
import org.gradle.testkit.runner.BuildResult
import org.gradle.testkit.runner.BuildTask
import org.gradle.testkit.runner.GradleRunner
import org.gradle.testkit.runner.TaskOutcome

class BannerTaskSpec extends Specification {

    @Rule TemporaryFolder projectRoot = new TemporaryFolder()

    private File buildFile

    def setup(){
        buildFile = projectRoot.newFile('build.gradle')
        buildFile.text = '''
            plugins {
                id 'groovy'
                id 'com.stehno.gradle.banner-plugin'
            }
        '''.stripIndent()

        projectRoot.newFile('banner.txt').text = 'Awesome Banner!'
    }

    def 'simple run'(){
        when:
        BuildResult result = GradleRunner.create()
            .withPluginClasspath()
            .withProjectDir(projectRoot.root)
            .withArguments('clean build'.split(' '))
            .build()

        then:
        println result.output
        buildPassed result

        result.output.contains('Awesome Banner!')
    }

    def 'simple run with status hidden'(){
        when:
        BuildResult result = GradleRunner.create()
            .withPluginClasspath()
            .withProjectDir(projectRoot.root)
            .withArguments('clean build -PnoBanner'.split(' '))
            .build()

        then:
        buildPassed result

        !result.output.contains('Awesome Banner!')
    }

    private boolean buildPassed(final BuildResult result){
        result.tasks.every { BuildTask task ->
            task.outcome == TaskOutcome.SUCCESS || task.outcome == TaskOutcome.UP_TO_DATE
        }
    }
}

Mostly I just extracted the setup code and the buildPassed check, then added a test for the noBanner property support.

Wouldn’t it be nice to make the banner file location configurable? Gradle plugins have a "extension" construct that allows for rich configuration of plugins by adding functionality to the Gradle DSL. For our plugin, we would like to support something like the following:

banner {
    enabled = true
    location = file('banner.txt')
}

which would be used to toggle the banner display on and off and also provide a means of configuring the banner file location. This structure and both of its properties are optional, but allow additional configuration. Adding them to the plugin is fairly simple. The extension itself is just a POGO class, which for our case would be:

banner-plugin/src/main/groovy/com/stehno/gradle/banner/BannerExtension.groovy
package com.stehno.gradle.banner

class BannerExtension {

    boolean enabled = true
    File location
}

To register the extension with the plugin, you add the following to the first line of the BannerPlugin apply(Project) method:

project.extensions.create('banner', BannerExtension)

The last part of adding the extension support is to have the task actually make use of it. The displayBanner method of the task will look like the following when we are done:

@TaskAction
void displayBanner(){
    BannerExtension extension = project.extensions.getByType(BannerExtension)

    boolean enabled = project.hasProperty('bannerEnabled') ? project.property('bannerEnabled').equalsIgnoreCase('true') : extension.enabled

    File bannerFile = project.hasProperty('bannerFile') ? new File(project.property('bannerFile')) : (extension.location ?: project.file('banner.txt'))


    if( enabled ){
        bannerFile.eachLine { line->
            logger.lifecycle line
        }
    }
}

I modified the noBanner property and converted it to a flag so that now you would pass in -PbannerEnabled=false to disable it. I also added a means of configuring the banner file from the command line or via the extension, with the default still being banner.txt. The CLI and settings properties will override the extension values if they are present. We need to modify the 'simple run with status hidden' test to handle the new parameter:

def 'simple run with status hidden'(){
    when:
    BuildResult result = GradleRunner.create()
        .withPluginClasspath()
        .withProjectDir(projectRoot.root)
        .withArguments('clean build -PbannerEnabled=false'.split(' '))
        .build()

    then:
    buildPassed result

    !result.output.contains('Awesome Banner!')
}

Now, if you run the tests, everything still passes - so the defaults work as expected. Let’s add some tests using the extension to override the file location.

def 'extension run'(){
    setup:
    buildFile.text = '''
        plugins {
            id 'groovy'
            id 'com.stehno.gradle.banner-plugin'
        }

        banner {
            location = file('other-banner.txt')
        }
    '''.stripIndent()

    when:
    BuildResult result = GradleRunner.create()
        .withPluginClasspath()
        .withProjectDir(projectRoot.root)
        .withArguments('clean build'.split(' '))
        .build()

    then:
    buildPassed result

    result.output.contains('Awesome-er Banner!')
}

In this test we have to override the default build file we created in setup. I also added the creation of the other banner file in the setup method:

projectRoot.newFile('other-banner.txt').text = 'Awesome-er Banner!'

Now, run the tests again and see that our extension works as expected.

With our newly minted Gradle plugin we should be able to use it in our original project as a local test before deployment. An easy way to do this is to publish it to your local maven repository and then configure the other project to use it. In the plugin project, add id 'maven-publish' to the plugins block, which will allow us to publish to the local maven repo. Then run ./gradlew publishToMavenLocal, which does what it says.

In the original external build.gradle file we need to add bootstrapping code to bring in the local plugin and also remove the old banner task. The updated build.gradle file will look like this:

build-banner/build.gradle
buildscript {
    repositories {
        mavenLocal()
    }
    dependencies {
        classpath "com.stehno.gradle:banner-plugin:0.1.0"
    }
}

plugins {
    id 'groovy'
}

apply plugin: "com.stehno.gradle.banner-plugin"

Notice that we are pulling the plugin from the local maven repository. If you run the build now, you get your expected banner:

> ./gradlew build
:banner
  _______ _            ____        _ _     _
 |__   __| |          |  _ \      (_) |   | |
    | |  | |__   ___  | |_) |_   _ _| | __| |
    | |  | '_ \ / _ \ |  _ <| | | | | |/ _` |
    | |  | | | |  __/ | |_) | |_| | | | (_| |_ _ _
    |_|  |_| |_|\___| |____/ \__,_|_|_|\__,_(_|_|_)
:build

BUILD SUCCESSFUL

Total time: 0.543 secs

However, we should be able to use a different banner file. Create another banner file as flag.txt (with whatever you want in it) and configure the build to use it by adding:

banner {
    location = file('flag.txt')
}

to the bottom of the build file. Now, with my new version, I get:

> ./gradlew build
:banner
This is GRADLE!!!
:build

BUILD SUCCESSFUL

Total time: 0.474 secs

We can also disable the banner via config, set enabled = false in the extension code, and it will not appear. But, you can force it on the command line by adding -PbannerEnabled=true.

From here, you can distribute your plugin to friends and coworkers as long as you have some shared repository that you can point them to, but what if you came up with something cool enough to share to a larger audience? For that you want to publish to the http://plugins.gradle.com repo, which is what is used by the plugins block of the build.gradle file. I won’t go too far down that path in this post, but basically you will need to add the id 'com.gradle.plugin-publish' version '0.9.4' plugin to the plugin project, which will handle the actual publishing for you once you configure it for your project. In our case this would be something like:

pluginBundle {
    website = 'http://yourdomain.com/banner-plugin'
    vcsUrl = 'https://github.com/cjstehno/banner-plugin'
    description = 'Gradle plugin to add a fancy banner to your build log.'
    tags = ['gradle', 'groovy']

    plugins {
        webpreviewPlugin {
            id = 'com.stehno.gradle.banner-plugin'
            displayName = 'Gradle Build Banner Plugin'
        }
    }
}

Once you have that in place and have signed up with the plugins portal (free) you run ./gradlew publishPlugins and if all goes well, you have a publicly available plugin.

This tutorial has really only scratched the surface of plugin development, there is a lot more there to work with and most of it is well documented in the Gradle User Guide or through some Google searches. It’s a powerful framework and well worth spending the time to learn if you are working in Gradle.

Gradle: A Gentle Introduction

02 November 2016 ~ blog, groovy, gradle

The Gradle build tool has become widely-used over the past few years, but there are still a lot of developers who are unfamiliar with it, and like any new framework or technology it is easier to get started with some guidance. Hopefully this will provide a nice jump start into doing some actual work with Gradle. With that being said, let’s dig in!

I will forgo installing Gradle - you can read about how to do that for your platform in the Gradle documentation. Let’s assume you have Gradle installed, preferably a current version. If you run gradle --version you should see something like:

------------------------------------------------------------
Gradle 3.1
------------------------------------------------------------

Build time:   2016-09-19 10:53:53 UTC
Revision:     13f38ba699afd86d7cdc4ed8fd7dd3960c0b1f97

Groovy:       2.4.7
Ant:          Apache Ant(TM) version 1.9.6 compiled on June 29 2015
JVM:          1.8.0_102 (Oracle Corporation 25.102-b14)
OS:           Linux 4.8.0-26-generic amd64

First, create a directory for your project and cd into it:

mkdir hellogradle
cd hellogradle

Every Gradle project needs at least a build.gradle file so we will start with the minimal requirement. Create the following file in your project directory:

build.gradle
plugins {
    id 'groovy'
}

repositories {
    jcenter()
}

dependencies {
    compile 'org.codehaus.groovy:groovy-all:2.4.6'
}

The plugins block is used to specify the Gradle plugins used in the build; in this case we just need groovy since we are making a Groovy project. The groovy plugin extends the java plugin so we get its functionality as well.

The repositories block specifies which repositories are available for resolving dependency artifacts - in most cases jcenter() (the Bintray repository) is enough to start with.

Lastly, the dependencies block is where the project dependencies are defined as <configuration> '<group>:<artifact>:<version>'.

At this point you have a working Gradle project. You can build it:

gradle clean build

You should see something like the following:

> hellogradle gradle clean build
:clean
:compileJava UP-TO-DATE
:compileGroovy UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:jar
:assemble
:compileTestJava UP-TO-DATE
:compileTestGroovy UP-TO-DATE
:processTestResources UP-TO-DATE
:testClasses UP-TO-DATE
:test UP-TO-DATE
:check UP-TO-DATE
:build

BUILD SUCCESSFUL

Total time: 0.492 secs

You can see that it is already doing quite a bit for so few lines of build code. You can run gradle tasks to see a list of the tasks available to your project.

So far, we have been running against my local version of Gradle. One of the nice features of Gradle is the wrapper functionality. The wrapper allows the project to specify the version of Gradle it should be built under; this code is then checked into your source control system so that a new developer can checkout the project and build it with the correct version of Gradle without it being installed on their system.

Add the following to the bottom of the build.gradle file:

task wrapper(type: Wrapper) {
    gradleVersion = '3.1'
}

Then, whenever you add the wrapper or change the supported version, you need to execute the gradle wrapper task to regenerate the configuration. Once the wrapper is in place, you will want to execute all your Gradle tasks using it rather than your local installation. You do this using the gradlew or gradlew.bat scripts provided in the root of your project. Now let’s do a clean build again with the wrapper:

> hellogradle ./gradlew clean build
:clean
:compileJava UP-TO-DATE
:compileGroovy UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:jar
:assemble
:compileTestJava UP-TO-DATE
:compileTestGroovy UP-TO-DATE
:processTestResources UP-TO-DATE
:testClasses UP-TO-DATE
:test UP-TO-DATE
:check UP-TO-DATE
:build

BUILD SUCCESSFUL

Total time: 0.678 secs

We end up with the same result as before.

This project doesn’t do anything at this point - there is no code. Let’s add some Groovy code; create the directories for src/main/groovy/demo and then add the file:

HelloGradle.groovy
package demo

class HelloGradle {

    String greet(final String name){
        "Hello, ${name ?: 'Gradle'}!"
    }
}

This code simply says hello to the name passed in as an argument, or Gradle by default. Now we will need to unit test our work, so let’s add support for the Spock testing framework. Add the following to your dependencies closure:

testCompile 'org.spockframework:spock-core:1.0-groovy-2.4'

We now have Spock available, so let’s write a unit test for our code. Create the test directories: src/test/groovy/demo and then create the file:

HelloGradleSpec.groovy
package demo

import spock.lang.Specification
import spock.lang.Unroll

class HelloGradleSpec extends Specification {

    private final HelloGradle greeter = new HelloGradle()

    @Unroll def 'say hello #name'(){
        expect:
        greeter.greet(name) == result

        where:
        name    | result
        null    | 'Hello, Gradle!'
        ''      | 'Hello, Gradle!'
        'Chris' | 'Hello, Chris!'
    }
}

This test will verify that our greeter returns the expected values for null-ish inputs as well as when a name is provided. I won’t go into the details of the Spock test at this point. Now, when you build the project, you will also run the tests by default:

> hellogradle ./gradlew clean build
:clean
:compileJava UP-TO-DATE
:compileGroovy
:processResources UP-TO-DATE
:classes
:jar
:assemble
:compileTestJava UP-TO-DATE
:compileTestGroovy
:processTestResources UP-TO-DATE
:testClasses
:test
:check
:build

BUILD SUCCESSFUL

Total time: 1.789 secs

Notice :test near the bottom. Gradle also provides an HTML report of your test results. The report will be generated in the build/reports directory and will look something like the following image:

gradle test report

Now that we have a test, it might be nice to have some idea of our test coverage. Gradle provides a plugin for the jacoco code coverage library. You can add the plugin by adding id 'jacoco' to the plugins block of your build.gradle file, which allows you to run:

./gradlew clean build jacocoTestReport

to build the project with tests and a generated test coverage report. Again, the report is generated in the build/reports directory - it will look something like:

gradle coverage report

The coverage report allows you to drill down into the source code and see what is and is not covered by your tests.

Testing your code is nice, but you need a way to run your application outside of testing. Let’s first add a main method to our Groovy code:

static void main(args){
    println new HelloGradle().greet(args ? args[0] : null)
}

Nothing fancy, just instantiate the HelloGradle class and call the greet(String) method with the first argument, if there is one. To make the project runnable, we need to add the application plugin and specify a "main class". To do this:

  • Add id 'application' to the plugins block

  • Add group = 'demo' to give the project an artifact group

  • Add version = '0.0.1' to give your project a version

  • Add mainClassName = 'demo.HelloGradle' to the build.gradle file outside of other configuration blocks.

With that, you now have a new task run which will run the application for you:

> hellogradle ./gradlew run
:compileJava UP-TO-DATE
:compileGroovy
:processResources UP-TO-DATE
:classes
:run
Hello, Gradle!

BUILD SUCCESSFUL

Total time: 1.526 secs

It also generates .tar and .zip distributions of the project which contain starter scripts and all required dependencies to deploy and run your application outside of the project itself.

Code quality analysis tools are also available as Gradle plugins. A common one for Groovy development is CodeNarc which runs quality rules against your code to generate a report of possible issues. We can add this to the project by adding id 'codenarc' to the plugins block and adding some additional config to build.gradle:

codenarcMain {
    ignoreFailures false
    configFile file('config/codenarc-main.rules')

    maxPriority1Violations 0
    maxPriority2Violations 5
    maxPriority3Violations 10
}

codenarcTest {
    ignoreFailures true
    configFile file('config/codenarc-test.rules')
}

Which configures a different rules and criteria for main source code vs test source code. The main and test rule sets are based on their suggested configurations, personal preference and experience - I generally use the files from my Vanilla project (main, test) for simplicity. This configuration will fail the build when the violation thresholds are exceeded for the main classes, but will simply report on the violations for test classes. The build will now run the codenarc checks when a build is executed.

The build will let you know if violations were found, and in any case will generate a report in the build/reports/codenarc directory. The report will look something like the following:

gradle codenarc report

At this point, we have a Gradle-based Groovy project with portable support for building, testing, coverage, code quality and application run/deployment, all with a few dozen lines of understandable code. While there is a lot more you can and should do with Gradle, this is a good starting point. From here, you should read through their documentation in general or touch on topics as you need them to figure out how to do something. Also Google is your best reference for finding how-tos or 3rd-party plugins; however, there is an official plugin repository that is starting to catch on.

Once you get the hang of it Gradle is hard to let go of due to its compact code, expressiveness and flexibility without the pains and rigor of older tools, like Maven and Ant.

Gradle Natives Plugin Update

19 September 2016 ~ blog, java, groovy, gradle

A few years ago I wrote a post about my Gradle-Natives plugin, called "Going Native with Gradle". The plugin was the result of some failed attempts at game programming and it pretty much stopped there; however, it seems there are some users who found it useful. In the years since it was written, it sat and got buggy and then recently just became useless due to external library changes and the rigidity of the plugin functionality. Tryign to be a good open source citizen, I figured it would be a good time to do some updates that will hopefully keep the plugin viable for a while.

With the new release, I figured it would be good to go back to the original post and attempt a similar example. Using the example code from the LWJGL Getting Started Guide we have:

import org.lwjgl.*;
import org.lwjgl.glfw.*;
import org.lwjgl.opengl.*;

import static org.lwjgl.glfw.Callbacks.*;
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.system.MemoryUtil.*;

public class HelloWorld {

	// The window handle
	private long window;

	public void run() {
		System.out.println("Hello LWJGL " + Version.getVersion() + "!");

		try {
			init();
			loop();

			// Free the window callbacks and destroy the window
			glfwFreeCallbacks(window);
			glfwDestroyWindow(window);
		} finally {
			// Terminate GLFW and free the error callback
			glfwTerminate();
			glfwSetErrorCallback(null).free();
		}
	}

	private void init() {
		// Setup an error callback. The default implementation
		// will print the error message in System.err.
		GLFWErrorCallback.createPrint(System.err).set();

		// Initialize GLFW. Most GLFW functions will not work before doing this.
		if ( !glfwInit() )
			throw new IllegalStateException("Unable to initialize GLFW");

		// Configure our window
		glfwDefaultWindowHints(); // optional, the current window hints are already the default
		glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); // the window will stay hidden after creation
		glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); // the window will be resizable

		int WIDTH = 300;
		int HEIGHT = 300;

		// Create the window
		window = glfwCreateWindow(WIDTH, HEIGHT, "Hello World!", NULL, NULL);
		if ( window == NULL )
			throw new RuntimeException("Failed to create the GLFW window");

		// Setup a key callback. It will be called every time a key is pressed, repeated or released.
		glfwSetKeyCallback(window, (window, key, scancode, action, mods) -> {
			if ( key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE )
				glfwSetWindowShouldClose(window, true); // We will detect this in our rendering loop
		});

		// Get the resolution of the primary monitor
		GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
		// Center our window
		glfwSetWindowPos(
			window,
			(vidmode.width() - WIDTH) / 2,
			(vidmode.height() - HEIGHT) / 2
		);

		// Make the OpenGL context current
		glfwMakeContextCurrent(window);
		// Enable v-sync
		glfwSwapInterval(1);

		// Make the window visible
		glfwShowWindow(window);
	}

	private void loop() {
		// This line is critical for LWJGL's interoperation with GLFW's
		// OpenGL context, or any context that is managed externally.
		// LWJGL detects the context that is current in the current thread,
		// creates the GLCapabilities instance and makes the OpenGL
		// bindings available for use.
		GL.createCapabilities();

		// Set the clear color
		glClearColor(1.0f, 0.0f, 0.0f, 0.0f);

		// Run the rendering loop until the user has attempted to close
		// the window or has pressed the ESCAPE key.
		while ( !glfwWindowShouldClose(window) ) {
			glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear the framebuffer

			glfwSwapBuffers(window); // swap the color buffers

			// Poll for window events. The key callback above will only be
			// invoked during this call.
			glfwPollEvents();
		}
	}

	public static void main(String[] args) {
		new HelloWorld().run();
	}

}

If we put this in a simple Gradle project with build.gradle as:

plugins {
    id 'com.stehno.natives' version '0.2.4'
    id 'java'
    id 'application'
}

version = "0.0.1"
group = "com.stehno"
mainClassName = 'hello.HelloWorld'

sourceCompatibility = 8
targetCompatibility = 8

repositories {
    jcenter()
}

dependencies {
    compile 'org.lwjgl:lwjgl:3.0.0'
    compile 'org.lwjgl:lwjgl-platform:3.0.0:natives-windows'
    compile 'org.lwjgl:lwjgl-platform:3.0.0:natives-linux'
    compile 'org.lwjgl:lwjgl-platform:3.0.0:natives-osx'
}

task wrapper(type: Wrapper) {
    gradleVersion = "2.14"
}

We can view the native libraries for all platforms using ./gradlew listNatives:

:listNatives
Native libraries found for configurations (compile, runtime)...
 - lwjgl-platform-3.0.0-natives-linux.jar:
        [LINUX] libjemalloc.so
        [LINUX] liblwjgl.so
        [LINUX] libglfw.so
        [LINUX] libopenal.so
 - lwjgl-platform-3.0.0-natives-osx.jar:
        [MAC] liblwjgl.dylib
        [MAC] libjemalloc.dylib
        [MAC] libglfw.dylib
        [MAC] libopenal.dylib
 - lwjgl-platform-3.0.0-natives-windows.jar:
        [WINDOWS] lwjgl.dll
        [WINDOWS] lwjgl32.dll
        [WINDOWS] OpenAL.dll
        [WINDOWS] jemalloc.dll
        [WINDOWS] glfw.dll
        [WINDOWS] glfw32.dll
        [WINDOWS] jemalloc32.dll
        [WINDOWS] OpenAL32.dll

and we can build and run the HelloWorld application with ./gradlew clean build run, which begs the question of whether or not this plugin is needed, since at this point the application works and we have not used the plugin at all. I will leave that to developers who actually work with this stuff and may use the plugin - I am just updating the existing functionality.

You can inlude the native libraries in the build using ./gradlew clean build includeNatives which will unpack the native libraries into the project build directory.

There are still a number of configuration options available through the natives DSL extension, such as including and excluding libraries, as well as limiting the scan to certain configurations and platforms, but I will leave those for the official documentation. Without any additional configuration you get all of the native libraries from the compile and runtime configurations for all platforms unpacked into the build/natives directory.

This plugin is still pretty raw, but hopefully it is useful enough to make some developers lives easier.

HTTP Builder NG for Groovy and Java

18 September 2016 ~ blog, groovy

The HttpBuilder project has been a go-to library for the simplification of HTTP requests for years; however, development on the project has stalled and seemingly died. A friend of mine (Dave Clark) decided to pick up where the project left off and to bring it up-to-date with modern Groovy and Java 8 support. The HTTP Builder NG project is a major update and refactor of the original project. I joined on to help with development, documentation and testing. In my opinion, this effort has brought the library back from the dead, better than ever. In this post, I will walk through accessing a simple REST service using the HttpBuilder with both Groovy and Java examples - yes, the new version of the library supports standard Java 8 coding.

First, we need a REST service to work with. I have thrown together a simple set of endpoints using the Spark Web Framework to make a "message of the day" service. There are three endpoints:

  • GET /message - retrieves the current stored message

  • POST /message - saves the text field of the JSON body content as the new message

  • DELETE /message - deletes the current message

There is not much to it, but it should be enough to play with. You can find the code in the [repo for this post](https://github.com/cjstehno/httpb-demo). Startup the server by running:

./gradlew run

In the root of the project. The server will be running on http://localhost:4567.

Let’s start off by retrieving the current message from the server. We need a base configured HttpBuilder object to make requests from:

HttpBuilder http = HttpBuilder.configure {
    request.uri = 'http://localhost:4567'
}

Then, we need to make a GET request to the /message path:

def result = http.get {
    request.uri.path = '/message'
}

When you run this code, you will get the following:

[text:n/a, timestamp:2016-09-16T12:47:55+0000]

which is a Map of the parsed JSON data coming back from the server - the HttpBuilder recognizes the application/json response content and parses it for you. In this case all we really want is the text, so let’s transform the response data a bit:

String text = http.get(String){
    request.uri.path = '/message'
    response.success { FromServer from, Object body->
        body.text
    }
}

We have added an expected result type of String and a response.success() handler. This handler will be called when a successful response code is received (code < 400). When it is called it will pull the text field out of our body object, which in this case, is the already-parsed JSON data. The return value from the success() method is returned as the result - the text of the current message. When you run this version of the code you get the current message text:

n/a

This is the default "empty" message content. How do we update the message to something more interesting? The service exposes POST /message which will take the text field of the request body content and use it as the new message. We can write a POST request just as easily as our GET request:

String updated = http.post(String) {
    request.uri.path = '/message'
    request.contentType = 'application/json'
    request.body = { text 'HttpBuilder is alive!' }
    response.success { FromServer from, Object body ->
        body.text
    }
}

Again, we will expect the text of the new message back from the server, but this time we are calling the post() method with a JSON content type. Note that our body content is using the Groovy JsonBuilder closure format, it could have just as easily been a Map of the data to be encoded. Similar to the response decoding, the request body is automatically encoded based on the content type.

If you run the code now, you will get:

HttpBuilder is alive!

You could also call the get() method again and verify that it is the current message.

As a final example with our service, let’s call the DELETE /message endpoint to reset the message back to it’s "empty" state. A DELETE request is just as simple:

String deleted = http.delete(String){
    request.uri.path = '/message'
    response.success { FromServer from, Object body ->
        body.text
    }
}

The result will be the new message after deletion:

n/a

which is the "empty" state.

One thing we notice now that we have written all of the verb calls is that there are a lot of similarities between them. They all call the same path and they all handle the successful response content in the same manner. I am not a fan of duplication, so we can move the common configuration up into the main configure method:

HttpBuilder http = HttpBuilder.configure {
    request.uri = 'http://localhost:4567/message'
    response.success { FromServer from, Object body ->
        body.text
    }
}

and our verb methods, now contain only what they need to do their work:

String message = http.get(String) {}

String updated = http.post(String) {
    request.contentType = 'application/json'
    request.body = { text 'HttpBuilder is alive!' }
}

String deleted = http.delete(String) {}

Nice and clean. Now wait, I know, I promised something similar in plain old Java, well Java 8 anyway…​ ok, you can do the same operations in Java with a fairly similar expressiveness:

HttpBuilder http = HttpBuilder.configure(config -> {
    config.getRequest().setUri("http://localhost:4567/message");
    config.getResponse().success(new BiFunction<FromServer, Object, String>() {
        @Override public String apply(FromServer fromServer, Object body) {
            return ((Map<String, Object>) body).get("text").toString();
        }
    });
});

String message = http.get(String.class, config -> {});

System.out.println("Starting content: " + message);

// update the content

String updated = http.post(String.class, config -> {
    config.getRequest().setContentType("application/json");
    config.getRequest().setBody(singletonMap("text", "HttpBuilder works from Java too!"));
});

System.out.println("Updated content: " + updated);

// delete the content

String deleted = http.delete(String.class, config -> {});

System.out.println("Post-delete content: " + deleted);

Notice that the Java 8 lambdas make the syntax about as simple as the Groovy DSL. When you run this version of the client you get:

Starting content: n/a
Updated content: HttpBuilder works from Java too!
Post-delete content: n/a

In Java or Groovy, the library makes HTTP interactions much easier to work with. Check out the project and feel free to submit bug reports and feature requests, or even suggested details to be documented.

ND4J Matrix Math

12 August 2016 ~ blog, groovy

In my last post (Commons Math - RealMatrix), I discussed the matrix operations support provided by the Apache Commons Math API. In doing my research I also stumbled on a library that is much closer in functionality to the Python NumPy library (commonly used in Machine Learning examples). The ND4J library is a scientific computing library for the JVM, meant to be used in production environments, which means routines are designed to run fast with minimum RAM requirements.

The main draw I had at this point was that their support for array-style element-by-element operations was much deeper than the matrix operations provided by the Apache Commons Math API and much closer to what I was seeing in the Python code I was working with, which makes conversion simpler.

With NumPy in Python you can multiply two arrays such that the result is the multiplication of each value of the array by the corresponding value in the second array. This is not so simple with matrices (as shown in my last post). With ND4J, it becomes much simpler:

def arrA = Nd4j.create([1.0, 2.0, 3.0] as double[])
def arrB = Nd4j.create([2.0, 4.0, 6.0] as double[])
def arrC = arrA.mul(arrB)
println "$arrA + $arrB = $arrC"

will result in:

[1.00, 2.00, 3.00] * [2.00, 4.00, 6.00] = [ 2.00,  8.00, 18.00]

which is as we would expect from the Python case. ND4J also has the ability to do two-dimensional (matrix-style) arrays:

def matA = Nd4j.create([
    [1.0, 2.0, 3.0] as double[],
    [4.0, 5.0, 6.0] as double[]
] as double[][])
println "Matrix: $matA\n"

which will produce:

Matrix: [[1.00, 2.00, 3.00],
 [4.00, 5.00, 6.00]]

All of the other mathematical operations I mentioned in the previous post are available and with data structures that feel a lot more rich and refined for general use. This is barely scratching the surface of the available functionality. Also, the underlying code is native-based and has support for running on CUDA cores for higher performance. This library is definitely one to keep in mind for cases when you have a lot of array and matrix-based operations.

Apache Commons Math - RealMatrix

11 August 2016 ~ blog, groovy

I have been reading Machine Learning in Action, which is a great book; however, all of the examples are in Python. While Python seems like a decent language, it is not one of my primary languages. With that in mind, I have been converting the Python examples into Groovy so that a few months from now when I come back and try to understand what I learned, I will be able to decipher the code.

What I have found is that, at least in the examples for this book, there are numerous Matrix-based operations. My Linear Algebra was a long time ago, but I think I remember some of the basics; however, it’s nice to have a Java-based implementation in the Apache Commons Math RealMatrix implementations (there are others but this is what I have been focussing on). It took me a little time to get back up to speed, especially since the Python examples will have something like:

someMatrix = someMatrix * anotherMatrix + thirdMatrix * number

where the resulting matrix is the product of two matrices added to the product of a matrix and a scalar number. Conceptually, this boils down to:

  1. Multiply someMatrix by anotherMatrix

  2. Multiply every element of thirdMatrix by the scalar number value

  3. Add every element of the matrix in step 1 with the element at the same position of the matrix from step 2.

Not hard to grasp, and not even all that hard to code; however, this is something I’d rather push off to someone else’s implementation instead of writing it myself. That is where the Commons Math library comes into play. The RealMatrix interface defines matrix support for double values - there is also a more flexible FieldMatrix<T> interface, but double values work well as an example. Let’s start by setting up a simple Groovy script for playing with matrices. Create a file named matrix-math.groovy and add the following to it:

matrix-math.groovy
@Grapes(
   @Grab('org.apache.commons:commons-math3:3.6.1')
)

import org.apache.commons.math3.linear.*

def mat = new Array2DRowRealMatrix(4,3)

println mat

This script will download the artifacts for the Apache Commons Math library and create a simple RealMatrix with 4 rows and 3 columns. It will then be printed to the console. When you run it, you should see

Array2DRowRealMatrix{{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0}}

which represents our empty 4x3 matrix. While this is not a bad representation, it would be nicer if we could get a better representation of the rows and columns of data for our poor human eyes. The library provides a RealMatrixFormat for this. Add the following to the script:

def formatter = new RealMatrixFormat('{', '}', '{', '}', ',\n ', ',\t')

println formatter.format(mat)

Note that the println line replaces the existing one. Now we get a better, more human-readable representation:

{{0,    0,      0},
 {0,    0,      0},
 {0,    0,      0},
 {0,    0,      0}}

Interesting so far, but we would really like some data. With the existing matrix, you can add data in rows or columns by index, similar to an array:

mat.setRow(0, [1.0, 2.0, 3.0] as double[])
mat.setColumn(1, [9.0, 8.0, 7.0, 6.0] as double[])

Now when you run the code, notice that you get the first row and the second column populated with the provided data:

{{1,    9,      3},
 {0,    8,      0},
 {0,    7,      0},
 {0,    6,      0}}

Also notice that the column data overwrote the row data we set for the second column (index 1). In our row data it was 2.0, but the 9.0 value from the column was applied after and is the final value. The other main method of creating a matrix is by providing the data directly in the constructor. Say we want to create a matrix with the same dimensions, but with a sequential collection of values, such as:

1  2  3
4  5  6
7  8  9
10 11 12

You can do the following in the code:

def seqMat = new Array2DRowRealMatrix([
    [1.0, 2.0, 3.0] as double[],
    [4.0, 5.0, 6.0] as double[],
    [7.0, 8.0, 9.0] as double[],
    [10.0, 11.0, 12.0] as double[]
] as double[][])

println formatter.format(seqMat)

This code creates a matrix with an array of arrays, where the inner arrays are the rows of data. When printed out, you get the following:

{{1,    2,      3},
 {4,    5,      6},
 {7,    8,      9},
 {10,   11,     12}}

Now, let’s do some operations on our matrices. You can do common math operations on two matrices. Adding two matrices:

def sum = mat.add(seqMat)
println formatter.format(sum)

This gives you the element-by-element sum of the values and yields:

{{2,    11,     6},
 {4,    13,     6},
 {7,    15,     9},
 {10,   17,     12}}

Subtracting one matrix from another:

def diff = seqMat.subtract(mat)
println formatter.format(diff)

Gives:

{{0,    -7,     0},
 {4,    -3,     6},
 {7,    1,      9},
 {10,   5,      12}}

Multiplication of matrices is not what you might intuitively think it is, unless you are up on your Linear Algebra. Since there are whole wiki pages devoted to Matrix Multiplication, I won’t go into it here beyond stating that it can be done when you have square matrices (ours are not). Not being a tutorial on Linear Algebra, I am going to leave it at that. You can also multiply a matrix by a scalar number:

def prod = mat.scalarMultiply(2)
println formatter.format(prod)

Which multiplies every element by the given value and results in:

{{2,    18,     6},
 {0,    16,     0},
 {0,    14,     0},
 {0,    12,     0}}

Similarly, there is a scalarAdd(double) method.

Other useful operations may be performed on matrices. You can "transpose" the matrix:

def trans = seqMat.transpose()
println formatter.format(trans)

This rotates the values of the matrix to turn rows into columns, as in our example:

{{1,    2,      3},
 {4,    5,      6},
 {7,    8,      9},
 {10,   11,     12}}

becomes

{{1,    4,      7,      10},
 {2,    5,      8,      11},
 {3,    6,      9,      12}}

There are a handful of other built-in operations available to matrices that are probably useful if you know what you are doing, but at this point, I do not. Another useful construct is the set of "walker" methods that allow you to walk through the elements of the matrix in various ways, allowing you to modify the elements or simply read them. Let’s take our initial matrix as an example and multiply every element by 2.0 both in place and in an external collection.

For the in-place modification we need a RealMatrixChangingVisitor

class MultiplicationVisitor extends DefaultRealMatrixChangingVisitor {

    double factor

    double visit(int row, int column, double value){
        value * factor
    }
}

mat.walkInOptimizedOrder(new MultiplicationVisitor(factor:2.0))
println formatter.format(mat)

This visitor simply multiplies each value by the provided factor and returns it, which will update the value in the matrix. The resulting matrix has the following:

{{2,    18,     6},
 {0,    16,     0},
 {0,    14,     0},
 {0,    12,     0}}

You can also walk a matrix without the ability to change the internal values. This requires a RealMatrixPreservingVisitor:

class CollectingVisitor extends DefaultRealMatrixPreservingVisitor {

    List values = []

    void visit(int row, int column, double value){
        values << value
    }
}

def collectingVisitor = new CollectingVisitor()
mat.walkInOptimizedOrder(collectingVisitor)
println collectingVisitor.values

In this case, the values are collected into a list and no matrix value is modified. You get the following result:

[2.0, 18.0, 6.0, 0.0, 16.0, 0.0, 0.0, 14.0, 0.0, 0.0, 12.0, 0.0]

This contains a list of all the values from our original matrix after the previous visitor has modified it.

Matrix operations can seem quite complicated; however, they are not bad with a helpful library. So far the Commons Math API seems pretty useful for these more advanced math concepts.

The entire script for this tutorial is provided below for completeness:

matrix-math.groovy
@Grapes(
   @Grab('org.apache.commons:commons-math3:3.6.1')
)

import org.apache.commons.math3.linear.*

def formatter = new RealMatrixFormat('{', '}', '{', '}', ',\n ', ',\t')

def mat = new Array2DRowRealMatrix(4,3)
mat.setRow(0, [1.0, 2.0, 3.0] as double[])
mat.setColumn(1, [9.0, 8.0, 7.0, 6.0] as double[])

println formatter.format(mat)
println()

def seqMat = new Array2DRowRealMatrix([
    [1.0, 2.0, 3.0] as double[],
    [4.0, 5.0, 6.0] as double[],
    [7.0, 8.0, 9.0] as double[],
    [10.0, 11.0, 12.0] as double[]
] as double[][])

println formatter.format(seqMat)
println()

def sum = mat.add(seqMat)
println formatter.format(sum)
println()

def diff = seqMat.subtract(mat)
println formatter.format(diff)
println()

def prod = mat.scalarMultiply(2)
println formatter.format(prod)
println()

def trans = seqMat.transpose()
println formatter.format(trans)
println()

class MultiplicationVisitor extends DefaultRealMatrixChangingVisitor {

    double factor

    double visit(int row, int column, double value){
        value * factor
    }
}

mat.walkInOptimizedOrder(new MultiplicationVisitor(factor:2.0))
println formatter.format(mat)
println()

class CollectingVisitor extends DefaultRealMatrixPreservingVisitor {

    List values = []

    void visit(int row, int column, double value){
        values << value
    }
}

def collectingVisitor = new CollectingVisitor()
mat.walkInOptimizedOrder(collectingVisitor)
println collectingVisitor.values
println()

Gradle Dependencies Behind the Wall

10 July 2016 ~ blog, groovy, gradle

Some companies like to take full control of their build environments and disallow builds that pull artifacts from external sources so that only approved internal artifact repositories are used containing only approved artifacts. While the validity of this is debatable, it exists and in my experience tends to add roadblocks to development, especially when working with new frameworks and libraries.

Consider the scenario where you are working on a poject that uses a newer version of the Spring Framework than has been previously used in the company. Now you need to get the new Spring artifacts into your approved repository, which requires an issue ticket of some sort and at least one or two architects to approve it. I am sure I am not shocking you when I say that Spring has numerous dependencies if you are doing anything interesting with it and they are all transient. How do you get a list of the dependencies that you need to have added without an arduous catalogging of artifacts and their dependencies or numerous iterations of the list-ticket-approval work flow( which is not generally speedy)? You write a Gradle plugin to do it for you.

I have added a checkAvailability task to my Dependency Checker Plugin. This task allows you to do your development work using the standard jcenter or mavenCentral artifact repositories so that you can get things working, but when you are ready to lock down your dependencies you can run:

./gradlew checkAvailability -PrepoUrls=http://artifacts.mycompany.com/repository

Which will list out the dependencies missing from the specified repository without affecting your build. The reported console entries will look something like:

Availability check for (commons-lang:commons-lang:2.1.2): FAILED

You can provide additional configuration to futher configure the task:

checkAvailability {
    repoUrls = ['http://artifacts.mycompany.com/repository']
    configurations = ['runtime']
    ignored = ['com.something:thingifier:1.2.3']
    failOnMissing = true
}

This configuration will specify the default repoUrls to be used, which may still be overridden on the command line. The configurations property allows you to limit the dependency configurations searched (to only runtime in this case). The ignored property allows specified artifacts to be ignored even if they are missing. And finally, the failOnMissing property will cause the build to fail when set to true after reporting all the missing dependencies - the default is false so that it will only list the status of the dependencies and allow the build to continue.

Now, armed with a full list of the dependencies missing from your internal artifact repository, you can create your issue ticket and get the approvals once and get back to actual work faster.

Custom Spring Boot Shell Banner

25 March 2016 ~ blog, groovy, spring

I did a Groovy User Group talk recently related to my Spring Boot Remote Shell blog post and while putting the talk together I stumbled across a bug in the integration between Spring Boot and the Crash shell (see Spring-Boot-3988). The custom banner you can add to your Spring Boot application (as /resources/banner.txt) is not applied by default to your crash shell, so you get the boring Spring logo every time you startup the shell. I had worked with the Crash shell previously and I remember that the banner was customizable so I did a little digging and figured out how to code a work-around - I also added this information to the bug ticket; I considered contributing a pull request, but I am not sure how this would be coded into the default application framework.

The work-around is pretty simple and straight-forward if you have worked with the crash shell before. You use their method of customization and then have it pull in your Spring Boot custom banner. In your /src/main/resources/commands directory you add a login.groovy file, which Crash will load with every shell connection. The file allows the customization of the banner and the prompt. We can then load our spring banner from the classpath. The basic code is as follows:

login.groovy
welcome = { ->
    def hostName;
    try {
        hostName = java.net.InetAddress.getLocalHost().getHostName();
    } catch (java.net.UnknownHostException ignore) {
        hostName = 'localhost';
    }

    String banner = YourApplication.getResourceAsStream('/banner.txt').text

    return """
${banner}
Logged into $hostName @ ${new Date()}
"""
}

prompt = { ->
    return "% ";
}

It’s a silly little thing to worry about, but sometimes it’s the little things that make an application feel more like your own.

I have created a pull request in the spring-boot project to address this issue…​ we’ll see what happens.

Groovy Dependency Injection

19 March 2016 ~ blog, groovy

Dependency Injection frameworks were a dime a dozen for a while - everybody had their own and probably a spare just in case. For the most part the field has settled down to a few big players, the Spring Framework and Google Guice are the only two that come to mind. While both of these have their pluses and minuses, they both have a certain level of overhead in libraries and understanding. Sometimes you want to throw something together quickly or you are in a scenario where you can’t use one of these off the shelf libraries. I had to do this recently and while I still wanted to do something spring/guice-like, I could not use either of them, but I did have Groovy available.

Note
I want to preface the further discussion here to say that I am not suggesting you stop using Spring or Guice or whatever you are using now in favor of rolling your own Groovy DI - this is purely a sharing of information about how you can if you ever need to.

Let’s use as an example a batch application used to process some game scores and report on the min/max/average values. We will use a database (H2) just to show a little more configuration depth and I will use the TextFileReader class from my Vanilla project to keep things simple and focussed on DI rather than logic.

First, we need the heart of our DI framework, the configuration class. Let’s call it Config; we will also need a means of loading external configuration properties and this is where our first Groovy helper comes in, the ConfigSlurper. The ConfigSlurper does what it sounds like, it slurps up a configuration file with a Groovy-like syntax and converts it to a ConfigObject. To start with, our Config class looks something like this:

class Config {
    private final ConfigObject config

    Config(final URL configLocation) {
        config = new ConfigSlurper().parse(configLocation)
    }
}

The backing configuration file we will use, looks like this:

inputFile = 'classpath:/scores.csv'

datasource {
    url = 'jdbc:h2:mem:test'
    user = 'sa'
    pass = ''
}

This will live in a file named application.cfg and as can be seen, it will store our externalized config properties.

Next, let’s configure our DataSource. Both Spring and Guice have a similar "bean definition" style, and what I am sure is based on those influences, I came up with something similar here:

@Memoized(protectedCacheSize = 1, maxCacheSize = 1)
DataSource dataSource() {
    JdbcConnectionPool.create(
        config.datasource.url,
        config.datasource.user,
        config.datasource.pass
    )
}

Notice that I used the @Memoized Groovy transformation annotation. This ensures that once the "bean" is created, the same instance is reused, and since I will only ever have one, I can limit the cache size and make sure it sicks around. As an interesting side-item, I created a collected annotation version of the memoized functionality and named it @OneInstance since @Singleton was alread taken.

@Memoized(protectedCacheSize = 1, maxCacheSize = 1)
@AnnotationCollector
@interface OneInstance {}

It just keeps things a little cleaner:

@OneInstance DataSource dataSource() {
    JdbcConnectionPool.create(
        config.datasource.url,
        config.datasource.user,
        config.datasource.pass
    )
}

Lastly, notice how the ConfigObject is used to retrieve the configuration property values, very clean and concise.

Next, we need to an input file to read and a TextFileReader to read it so we will configure those as well.

@OneInstance Path inputFilePath() {
    if (config.inputFile.startsWith('classpath:')) {
        return Paths.get(Config.getResource(config.inputFile - 'classpath:').toURI())
    } else {
        return new File(config.inputFile).toPath()
    }
}

@OneInstance TextFileReader fileReader() {
    new TextFileReader(
        filePath: inputFilePath(),
        firstLine: 2,
        lineParser: new CommaSeparatedLineParser(
            (0): { v -> v as long },
            (2): { v -> v as int }
        )
    )
}

I added a little configuration sugar so that you can define the input file as a classpath file or an external file. The TextFileReader is setup to convert the data csv file as three columns of data, an id (long), a username (string) and a score (int). The data file looks like this:

# id,username,score
100,bhoser,4523
200,ripplehauer,235
300,jegenflur,576
400,bobknows,997

The last thing we need in the configuration is our service which will do that data management and the stat calculations, we’ll call it the StatsService:

@TypeChecked
class StatsService {

    private Sql sql

    StatsService(DataSource dataSource) {
        sql = new Sql(dataSource)
    }

    StatsService init() {
        sql.execute('create table scores (id bigint PRIMARY KEY, username VARCHAR(20) NOT NULL, score int NOT NULL )')
        this
    }

    void input(long id, String username, int score) {
        sql.executeUpdate(
            'insert into scores (id,username,score) values (?,?,?)',
            id,
            username,
            score
        )
    }

    void report() {
        def row = sql.firstRow(
            '''
            select
                count(*) as score_count,
                avg(score) as average_score,
                min(score) as min_score,
                max(score) as max_score
            from scores
            '''
        )

        println "Count  : ${row.score_count}"
        println "Min    : ${row.min_score}"
        println "Max    : ${row.max_score}"
        println "Average: ${row.average_score}"
    }
}

I’m just going to dump it out there since it’s mostly SQL logic to load the data into the table and then report the stats out to the standard output. We will wire this in like the others in Config:

@OneInstance StatsService statsService() {
    new StatsService(dataSource()).init()
}

With that, our configuration is done. Now we need to use it in an application, which we’ll call Application:

class Application {

    static void main(args){
        Config config = Config.fromClasspath('/application.cfg')

        StatsService stats = config.statsService()
        TextFileReader reader = config.fileReader()

        reader.eachLine { Object[] line->
            stats.input(line[0], line[1], line[2])
        }

        stats.report()
    }
}

We instantiate a Config object, call the bean accessor methods and use the beans to do the desired work. I added the fromClasspath(String) helper method to simplify loading config from the classpath.

Like I said, this is no fulltime replacement for a real DI framework; however, when I was in a pinch, this came in pretty handy and worked really well. Also, it was easy to extend the Config class in the testing source so that certain parts of the configuration could be overridden and mocked as needed during testing.

Note
The demo code for this post is on GitHub: cjstehno/groovy-di.

Dependency Duplication Checking

12 March 2016 ~ blog, groovy, gradle

Sometimes it takes a critical mass threshold of running into the same issue repeatedly to really do something about it. How often, when working with a dependency manager like Gradle or Maven, have you run into some runtime issue only to find that it was caused by a build dependency that you had two (or more) different versions of at runtime? More often than you would like, I am sure. It can be a real surprise when you actually go digging into your aggregated dependency list only to find out you have more than one duplicate dependency just waiting to become a problem.

What do I mean by duplicate dependency? Basically, it’s just what it sounds like. You have two dependencies with different versions. Something like:

org.codehaus.groovy:groovy-all:2.4.4
org.codehaus.groovy:groovy-all:2.4.5

Most likely, your project defines one of them and some other dependency brought the other along for the ride. It is usually pretty easy to resolve these extra dependencies; in Gradle you can run the dependency task to see which dependency is bringing the extra library in:

./gradlew dependencies > deps.txt

I like to dump the output to a text file for easier viewing. Then, once you find the culprit, you can exclude the transitive dependency:

compile( 'com.somebody:coollib:2.3.5' ){
    exclude group:'org.codehaus.groovy', module:'groovy-all'
}

Then you can run the dependency task again to ensure that you got of it. Generally, this is a safe procedure; however, sometimes you get into a situation where different libraries depend on different versions that have significant code differences - that’s when the fun begins and it usually ends in having to up or down-grade various dependencies until you get a set that works and is clean.

What is the problem with having multiple versions of the same library in your project? Sometimes nothing, sometimes everything. The classloader will load whichever one is defined first in the classpath. If your project needs a class Foo with a method bar() and the version you expect to use has it but the previous version does not, bad things can happen at runtime.

Ok, now we know generally how to solve the multiple dependency problem, we’re done right? Sure, for a month or so. Unless your project is done and no longer touched, new dependencies and duplicates will creep in over time. I did this duplicataion purge on a project at work a few months ago and just last week I took a peek at the aggregated dependency list and was truely not so shocked to see three duplicated libraries. One of which was probably the cause of some major performance issues we were facing. That’s what inspired me to solve the problem at least to the point of letting you know when duplications creep in.

I created the dependency-checker Gradle plugin. It is available in the Gradle Plugin Repository. At this point, it has one added task, checkDependencies which, as the name suggests, searches through all the dependencies of the project to see if you have any duplicates within a configuration. If it finds duplicates, it will write them to the output log and fail the build.

Currently, you need to run the task for the checking to occur. I would like to get it to run with the default check task, or build task, but the code I had for that was not working - later version I guess. You can add that functionality into your own build by adding one or two lines to your build.gradle file:

tasks.check.dependsOn checkDependencies
tasks.build.dependsOn checkDependencies

These will make the appropriate tasks depend on the dependency check so that it will be run with every build - that way you will know right away that you have a potential problem.

I did take a tour around Google and the plugin repository just to make sure there was nothing else providing this functionality - so hopefully I am not duplicating anyone else’s work.

Vanilla TextFileReader/Writer

06 March 2016 ~ blog, groovy, vanilla

Something I have found myself doing quite often over my whole career as a developer is reading and writing simple text file data. Whether it is a quick data dump or a data set to be loaded from a 3rd party, it is something I end up doing a lot and usually it is something coded mostly from scratch since, surprisingly enough, there are very few tools available for working with formatted text files. Sure, there are a few for CSV, but quite often I get a reqest to read or write a format that is kind of similar to CSV, but just enough different that it breaks a standard CSV parser for whatever reason. Recently, I decided to add some utility components to my Vanilla project with the aim of making these readers and writers simpler to build.

Let’s start off with the com.stehno.vanilla.text.TextFileWriter and say we have a data source of Person objects in our application that the business wants dumped out to a text file (so they can import it into some business tools that only ever seem capable of importing simple text files). In the application, the data structure looks something like this:

class Person {
    String firstName
    String middleName
    String lastName
    int age
    float height
    float weight
}

with the TextFileWriter you need to define a LineFormatter which will be used to format the generated lines of text, one per object written. The LineFormatter defines two methods, String formatComment(String) for formatting a comment line, and String formatLine(Object) for formatting a data line. A simple implementation is provided, the CommaSeparatedLineFormatter will generate comment lines prefixed with a # and will expect a Collection object to be formatted and will format it as a CSV line.

The available implementation will not work for our case, so we will need to define our own LineFormatter. We want the formatted data lines to be of the form:

# Last-Name,First-Name-Middle-Initial,Attrs
Smith,John Q,{age:42, height:5.9, weight:230.5}

Yes, that’s a bit of a convoluted format, but I have had to generate worse. Our LineFormatter ends up being something like this:

class PersonLineFormatter implements LineFormatter {

    @Override
    String formatComment(String text) {
        "# $text" (1)
    }

    @Override
    String formatLine(Object object) {
        Person person = object as Person
        "${person.lastName},${person.firstName} ${person.middleName[0]},{age:${person.age}, height:${person.height}, weight:${person.weight}}" (2)
    }
}
  1. We specify the comment as being prefixed by a # symbol.

  2. Write out the Person object as the formatted String

We see that implementing the LineFormatter keeps all the application specific logic isolated from the common operation of actually writing the file. Now we can use our formatter as follows:

TextFileWriter writer = new TextFileWriter(
    lineFormatter: new PersonLineFormatter(),
    filePath: new File(outputDir, 'people.txt')
)

writer.writeComment('Last-Name,First-Name-Middle-Initial,Attrs')

Collection<Person> people = peopleDao.listPeople()

people.each { Person p->
    writer.write(p)
}

This will write out the text file in the desired format with very little new coding required.

Generally, writing out text representations of application data is not really all that challenging, since you have access to the data you need and some control over the formatting of the objects to be represented. The real challenge is usually going in the other direction, when you are reading in a data file from some external source, this is where the com.stehno.vanilla.text.TextFileReader becomes useful.

Let’s say you receive a request to import the data file we described above, maybe it was generated by the same business tools I mentioned earlier. We have something like this:

# Last-Name,First-Name-Middle-Initial,Attrs
Smith,John Q,{age:42, height:5.9, weight:230.5}
Jones,Robert M,{age:38, height:5.6, weight:240.0}
Mendez,Jose R,{age:25, height:6.1, weight:232.4}
Smalls,Jessica X,{age:30, height:5.5, weight:175.2}

The TextFileReader requires a LineParser to parse the input file lines into objects; it defines three methods, boolean parseable(String) which is used to determine whether or not the line should be parsed, Object[] parseLine(String) which is used to parse the line of text, and Object parseItem(Object, int) which is used to parse an individual element of the comma-separated line. There is a default implementation provided, the CommaSeparatedLineParser will parse simple comma-separated lines of text into arrays of Objects based on configured item converters; however, this will not work in the case of our file since there are commas in the data items themselves (the JSON-like format of the last element). So we need to implement one. Our LineParser will look something like the following:

class PersonLineParser implements LineParser {

    boolean parsable(String line){
        line && !line.startsWith(HASH) (1)
    }

    Object[] parseLine(String line){ (2)
        int idx = 0
        def elements = line.split(',').collect { parseItem(it, idx++) }

        [
            new Person(
                firstName:elements[1][0],
                middleName:elements[1][1],
                lastName:elements[0],
                age:elements[2],
                height:elements[3],
                weight:elements[4],
            )
        ] as Object[]
    }

    // Smith,John Q,{age:42, height:5.9, weight:230.5}
    // 0    ,1     ,2      ,3          ,4
    Object parseItem(Object item, int index){ (3)
        switch(index){
            case 0:
                return item as String
            case 1:
                return item.split(' ')
            case 2:
                return item.split(':')[1] as int
            case 3:
                return item.split(':')[1] as float
            case 4:
                return item.split(':')[1][0..-2] as float
        }
    }
}
  1. We want to ignore blank lines or lines that start with a # symbol.

  2. We extract the line items and build the Person object

  3. We convert the line items to our desired types

It’s not pretty, but it does the job and keeps all the line parsing logic out of the main file loading functionality. Our code to read in the file would look somethign like:

setup:
TextFileReader reader = new TextFileReader(
    filePath: new File(inputDir, 'people.txt'),
    lineParser: new PersonLineParser(),
    firstLine: 2 (1)
)

when:
def people = []

reader.eachLine { Object[] data ->
    lines << data[0]
}
  1. We skip the first line, since it will always be the header

The provided implementations for both the LineFormatter and LineParser will not account for every scenario, but hopefully they will hit some of them and provide a guideline for implementing your own. If nothing else, these components help to streamline the readign and writing of formatted text data so that you can get it done and focus on other more challenging development tasks.


Older posts are available in the archive.