1. Introduction Enterprise Groovy Gradle Plugin

One of the biggest complaints about Groovy is that it’s a dynamically compiled language, and that its optional static compilation feels bolted on. The Enterprise Groovy Plugin looks to fix this, by making static compilation the default, and gives you a configuration for optional enforcement. Groovy is a very powerful, and expressive language, and there may be times/places/companies, that want to take advantage of that power, but restrict it, because they have a large team, or have junior developers, etc. This is Where Enterprise Groovy comes in, giving you the tools to rein in some of the dynamic power, but whitelist it where it is needed.

2. Version History

  • 1.0.5

    • demus-nine submitted a fix for an errant space in one of the template filenames names.

  • 1.0.4

    • Providing proper fall backs for if the conventions aren’t present or if you set an override and it is not present.

  • 1.0.3

    • Updated some error handing. Has some issues with 1.0.2, so just bumped to 1.0.3

  • 1.0.1

    • Fixed an issue with a transient dependency when used in a library, that was retrieved with an @Grab.

  • 1.0

    • Fixed loop hole for disabling dynamic compilation by disallowing @CompileStatic(TypeCheckingMode.SKIP) in addition to @CompileDynamic.

    • Getting more of the configuration to the console task.

    • Fixing some typos, and updating documentation.

  • 1.0.RC4

    • Fixed issue getting config to the AST transform, using a custom compiler script.

    • Fixed issue, where Enterprise Groovy becomes a transient dependency.

    • Fixed issues with Gradle 5 not being able to use the plugin DSL.

    • Updated the documentation.

  • 1.0.RC3

    • Scripts like those from a Groovy shell will be skipped automatically for static compilation. This is because there is no way currently to get the configuration during compilation from the script.

    • Changing the plugin to add the Enterprise Groovy library to the project, using implementation, rather, then compile, to avoid introducing transient dependencies.

  • 1.0.RC2

    • Fixing some issues related to Gradle 5, and not being able to find the config.

    • Fixing an issue with the Groovy Console also related to Gradle 5. If the property sourceSets is not available then the Groovy Console will not be available, see the getting started section for more details.

  • 1.0.RC1

    • Initial Release with compile static by default and configuration for enforcement.

3. Getting Started

To get started, install the Enterprise Groovy plugin, in your build.grade:

Using the plugins DSL:

plugins {
  id "enterprise.groovy.plugin" version "1.0.3"
}

Using legacy plugin application:

buildscript {
  repositories {
    maven {
      url "https://plugins.gradle.org/m2/"
    }
  }
  dependencies {
    classpath "com.virtualdogbert:enterprise-groovy-plugin:1.0.3"
  }
}

Then run one of the setup Gradle tasks setupEnterpriseGroovyConventions or setupEnterpriseGroovyGrailsConventions. This will provide you with a conventions.groovy file in the root of your project, that you can use to configure the Enterprise Groovy Plugin.

If you apply the Enterprise Groovy plugin to an existing project, you may have a lot of compilation errors based on static compilation. To start if you have a lot of classes that break, you may want to add them temporarily, to the whitelist, and iteratively upgrade them, to be statically compilable.

3.1. Example applications

Here is an example app with commented out code that will cause the build to fail, because of the static compilation, or rules set in the conventions.groovy:

Here is another application which has a different setup, and was used to debug some issues:

4. Configuration

The generated configuration, which will be generated in the root of your project, and be called conventions.groovy. This configuration is actually a custom compilation script. For more information about custom compilation scripts, see the Custom Compiler Script section. You can change the location of the configuration, by setting the following property, in gradle.properties:

compilationScript = conventions.groovy

If you don’t set up a configuration, the default configuration will be applied, which you can see below.

4.1. Default Configuration

If during the setup you choose setupEnterpriseGroovyConventions you will get a conventions.groovy like this:

Map conventions = [
        disable                     : false,
        whiteListScripts            : true,

        disableDynamicCompile       : false,
        dynamicCompileWhiteList     : [],

        compileStaticExtensions     : [],
        limitCompileStaticExtensions: false,

        defAllowed                  : true,
        skipDefaultPackage          : false
]

System.setProperty('enterprise.groovy.conventions', "conventions=${conventions.inspect()}")
  • disable - This disables the Enterprise Groovy plugin, so it won’t add static compilation, or do any compile-time checks.

  • whiteListScripts - This will disable automatic static compilation for dynamic scripts. These scripts could be DSLs used by a framework or if you use a Groovy Shell in your code.

  • disableDynamicCompile- This disables the use of @CompileDynamic and @CompileStatic(TypeCheckingMode.SKIP). If true and @CompileDynamic or @CompileStatic(TypeCheckingMode.SKIP) is present a compilation error will be thrown.

  • dynamicCompileWhiteList - A list of file names, package names, or partial names for whitelisting classes that will not be statically compiled by default, and won’t be subject to any of the Enterprise Groovy Rules.

  • compileStaticExtensions - A list of Compilation extensions to be applied to the static compilation. These can be used to either make the static compilation, more, or less strict.

  • limitCompileStaticExtensions - if true then only the compileStaticExtensions specified can be used. So if you manually use a @CompileStatic Annotation, you wouldn’t be able to use any extensions, beyond the ones listed.

  • defAllowed - If the def keyword is allowed for properties/fields, method returns or method parameters. If you want to restrict def within methods, take a look at the "Taking it a step further" section.

  • skipDefaultPackage - If set true this will whitelist any classes in the default package.

4.2. Grails Configuration

If during the setup you choose setupEnterpriseGroovyGrailsConventions you will get a conventions.groovy like this:

Map conventions = [
        disable                     : false,
        whiteListScripts            : true,

        disableDynamicCompile       : false,
        dynamicCompileWhiteList     : [
                'UrlMappings',
                'Application',
                'BootStrap',
                'resources',
                'org.grails.cli'
        ],

        compileStaticExtensions     : [
                'org.grails.compiler.ValidateableTypeCheckingExtension',
                'org.grails.compiler.NamedQueryTypeCheckingExtension',
                'org.grails.compiler.HttpServletRequestTypeCheckingExtension',
                'org.grails.compiler.WhereQueryTypeCheckingExtension',
                'org.grails.compiler.DynamicFinderTypeCheckingExtension',
                'org.grails.compiler.DomainMappingTypeCheckingExtension',
                'org.grails.compiler.RelationshipManagementMethodTypeCheckingExtension'
        ],

        limitCompileStaticExtensions: false,
        defAllowed                  : false, //For controllers you can use Object in place of def, and in Domains add Closure to constraints/mappings closure fields.
        skipDefaultPackage          : true, //For GSP files
]

System.setProperty('enterprise.groovy.conventions', "conventions=${conventions.inspect()}")

These are defaults that I tested, that seem to work for Grails.

5. Custom Compiler Script

The Enterprise Groovy plugin also supports a custom compiler script, which is how it configures adding the static compilation, and the compilation checks. To customize the location of the compiler script you can set the following property in gradle.properties:

compilationScript = conventions.groovy

This is just a file path relative to the root of the project.

For more information on what you can do with a custom compiler script checkout this mrhaki blog:

Also check out the JavaDoc for the SecureASTCustomizer: SecureASTCustomizer JavaDoc

While a custom compiler script can provide functionality similar to this plugin, for compile static, it’s not as flexible, and your mileage may vary.

6. Groovy Console

The Enterprise Groovy plugin will provide a Gradle task to bring up a Groovy Console, if the project doesn’t already provide one. This can be good for playing with Groovy code, and more importantly, using the AST Browser. The AST browser, allows you to see, what the Groovy Compiler does to your code, making it less magical.

console no error

AS of the 1.0 release, the console doesn’t have access to the full conventions configuration, because of limitations between the Groovy Console, and the AST transform that drives Enterprise Groovy. For the Groovy Console it has access to the following configurations:

  • disable - Turning Enterprise Groovy on or off for the console.

  • whiteListScripts - This is overridden to be false, because everything you do in the Groovy Console is a script with no target build directory.

  • disableDynamicCompile - This will determine if you can use @CompileDynamic or @CompileStatic(TypeCheckingMode.SKIP), in the console.

  • defAllowed- This will determine if you can use def in the console.

console error

7. Taking it a step further

While with the Enterprise Groovy plugin, I could implement many rules, and you can do more with a custom compiler script, the downside to that is you will end up with a potentially slower compilation. Also, there Already exists a static checker called Code Narc:

Code Narc provides a framework for statically checking your project, and has a vast library of rules that you can choose to enable or not. While I wouldn’t suggest running this before every compile, because it would slow your compilation process down, it would be a good idea to hook this into your build process.

Eric Helgeson wrote a good article on how to use Code Narc with Grails 3 using a Gradle Plugin:

Jenn Strater also did a good talk during GR8Conf 2016:

Combining the Enterprise Groovy plugin, and the Code Narc plugin, will give you a lot of control for enforcing static compilation, and coding standards. This is not to say you shouldn’t do code reviews, because that will make sure that individuals aren’t changing the conventions.groovy/codenarc rules. If you want to be really enterprisy/restrictive, you could lock down your builds, and make them check that the conventions.groovy, hasn’t been changed, using a hash or golden file.

8. Issues and Source Code

If you have any issues with The Enterprise Groovy plugin you can report them here:

The source is also in Github, divided into two repositories, one for the plugin, and one for the library, that adds the static compilation, and checks. Pull requests are welcome:

9. Acknowledgments

With the Enterprise Groovy plugin, I’m "standing on the shoulders of giants", and would like to take the time to give a special thanks, to the people, whose work made this plugin possible:

  • Cédric Champeau(AKA melix) The original Author of @Compile Static.

  • Paul King One of the biggest contributors to the Groovy Language, who also has worked on Groovy’s static compilation.

  • Hubert Klein Ikkink(AKA mrhaki) A major player in the Groovy Community, with this tutorial blog posts: http://mrhaki.blogspot.com

  • Anyone who also worked on @CompileStatic, while I only saw Cédric, and Paul, I didn’t do an exhaustive search of all the support classes.

  • Anton Pryamostanov who tested out the earlier versions of Enterprise Groovy(RC1-RC4), which helped me figure out some gradle and configuration issues.