5.7 Dependency Resolution 2.4.4

See the light - agile, industrial strength, rapid web application development made easy

(Quick Reference) # 5.7 Dependency Resolution - Reference Documentation Authors: Graeme Rocher, Peter Ledbrook, Marc Palmer, Jeff Brown, Luke Daley, Burt Beckwith, Lari Hotari Version: 2.4.4 ## Table of Contents ## 5.7 Dependency Resolution Grails features a dependency resolution DSL that lets you control how plugins and JAR dependencies are resolved. You can choose to use Aether (since Grails 2.3) or Apache Ivy as the dependency resolution engine. Aether is the dependency resolution library used by the Maven build tool, so if you are looking for Maven-like behavior then Aether is the better choice. Ivy allows more flexibility if you wish to resolve jars from flat file systems or none HTTP repositories. Aether is the default dependency resolution engine for Grails applications since Grails 2.3. As of Grails 2.4 the Ivy resolver is considered deprecated and no longer maintained. It is recommended all users switch to using Aether. To configure which dependency resolution engine to use you can specify the `grails.project.dependency.resolver` setting in `grails-app/conf/BuildConfig.groovy`. The default setting is shown below:
    grails.project.dependency.resolver = "maven" // or ivy
You can then specify a `grails.project.dependency.resolution` property inside the `grails-app/conf/BuildConfig.groovy` file that configures how dependencies are resolved:
    grails.project.dependency.resolution = {
       // config here
    }
The default configuration looks like the following:

    grails.servlet.version = "3.0" // Change depending on target container compliance (2.5 or 3.0)
    grails.project.class.dir = "target/classes"
    grails.project.test.class.dir = "target/test-classes"
    grails.project.test.reports.dir = "target/test-reports"
    grails.project.work.dir = "target/work"
    grails.project.target.level = 1.6
    grails.project.source.level = 1.6
    //grails.project.war.file = "target/${appName}-${appVersion}.war"grails.project.fork = [
        // configure settings for compilation JVM, note that if you alter the Groovy version forked compilation is required
        //  compile: [maxMemory: 256, minMemory: 64, debug: false, maxPerm: 256, daemon:true],    // configure settings for the test-app JVM, uses the daemon by default
        test: [maxMemory: 768, minMemory: 64, debug: false, maxPerm: 256, daemon:true],
        // configure settings for the run-app JVM
        run: [maxMemory: 768, minMemory: 64, debug: false, maxPerm: 256, forkReserve:false],
        // configure settings for the run-war JVM
        war: [maxMemory: 768, minMemory: 64, debug: false, maxPerm: 256, forkReserve:false],
        // configure settings for the Console UI JVM
        console: [maxMemory: 768, minMemory: 64, debug: false, maxPerm: 256]
    ]grails.project.dependency.resolver = "maven" // or ivy
    grails.project.dependency.resolution = {
        // inherit Grails' default dependencies
        inherits("global") {
            // specify dependency exclusions here; for example, uncomment this to disable ehcache:
            // excludes 'ehcache'
        }
        log "error" // log level of Ivy resolver, either 'error', 'warn', 'info', 'debug' or 'verbose'
        checksums true // Whether to verify checksums on resolve
        legacyResolve false // whether to do a secondary resolve on plugin installation, not advised and here for backwards compatibility    repositories {
            inherits true // Whether to inherit repository definitions from plugins        grailsPlugins()
            grailsHome()
            mavenLocal()
            grailsCentral()
            mavenCentral()
            // uncomment these (or add new ones) to enable remote dependency resolution from public Maven repositories
            //mavenRepo "http://repository.codehaus.org"
            //mavenRepo "http://download.java.net/maven/2/"
        }    dependencies {
            // specify dependencies here under either 'build', 'compile', 'runtime', 'test' or 'provided' scopes e.g.
            runtime 'mysql:mysql-connector-java:5.1.24'
            compile 'org.springframework.integration:spring-integration-core:2.2.5.RELEASE'
        }    plugins {
            // plugins for the build system only
        }
    }
The details of the above will be explained in the next few sections. ## 5.7.1 Configurations and Dependencies Grails features five dependency resolution configurations (or 'scopes'): `build`: Dependencies for the build system only `compile`: Dependencies for the compile step `runtime`: Dependencies needed at runtime but not for compilation (see above) `test`: Dependencies needed for testing but not at runtime (see above) `provided`: Dependencies needed at development time, but not during WAR deployment `optional` (Aether only): Dependencies considered optional and not required for the execution of the application or plugin Within the `dependencies` block you can specify a dependency that falls into one of these configurations by calling the equivalent method. For example if your application requires the MySQL driver to function at `runtime` you can specify that like this:
    runtime 'com.mysql:mysql-connector-java:5.1.16'
This uses the string syntax: `group:name:version`. If you are using Aether as the dependency resolution library, the Maven pattern of:
    <groupId>:<artifactId>[:<extension>[:<classifier>]]:<version>
You can also use a Map-based syntax:
    runtime group: 'com.mysql',
            name: 'mysql-connector-java',
            version: '5.1.16'
Possible settings to the map syntax are: `group` - The group / organization (or groupId in Maven terminology) `name` - The dependency name (or artifactId in Maven terminology) `version` - The version of the dependency `extension` (Aether only) - The file extension of the dependency `classifier` - The dependency classifier `branch` (Ivy only) - The branch of the dependency `transitive` (Ivy only) - Whether the dependency has transitive dependencies As you can see from the list above some dependency configuration settings work only in Aether and some only in Ivy. Multiple dependencies can be specified by passing multiple arguments:

    runtime 'com.mysql:mysql-connector-java:5.1.16',
            'net.sf.ehcache:ehcache:1.6.1'// Orruntime(
        [group:'com.mysql', name:'mysql-connector-java', version:'5.1.16'],
        [group:'net.sf.ehcache', name:'ehcache', version:'1.6.1']
    )
### Disabling transitive dependency resolution By default, Grails will not only get the JARs and plugins that you declare, but it will also get their transitive dependencies. This is usually what you want, but there are occasions where you want a dependency without all its baggage. In such cases, you can disable transitive dependency resolution on a case-by-case basis:

    runtime('com.mysql:mysql-connector-java:5.1.16',
            'net.sf.ehcache:ehcache:1.6.1') {
        transitive = false
    }// Or
    runtime group:'com.mysql',
            name:'mysql-connector-java',
            version:'5.1.16',
            transitive:false
### Excluding specific transitive dependencies A far more common scenario is where you want the transitive dependencies, but some of them cause issues with your own dependencies or are unnecessary. For example, many Apache projects have 'commons-logging' as a transitive dependency, but it shouldn't be included in a Grails project (we use SLF4J). That's where the `excludes` option comes in:

    runtime('com.mysql:mysql-connector-java:5.1.16',
            'net.sf.ehcache:ehcache:1.6.1') {
        excludes "xml-apis", "commons-logging"
    }// Or
    runtime(group:'com.mysql', name:'mysql-connector-java', version:'5.1.16') {
        excludes([ group: 'xml-apis', name: 'xml-apis'],
                 [ group: 'org.apache.httpcomponents' ],
                 [ name: 'commons-logging' ])
As you can see, you can either exclude dependencies by their artifact ID (also known as a module name) or any combination of group and artifact IDs (if you use the Map notation). You may also come across `exclude` as well, but that can only accept a single string or Map:
    runtime('com.mysql:mysql-connector-java:5.1.16',
            'net.sf.ehcache:ehcache:1.6.1') {
        exclude "xml-apis"
    }
### Dependency Management (Aether Only) If you are using Aether then you can take advantage of Maven's notion of Dependency Management. To do so you use a `management` block, for example:
    management {
       dependency "commons-logging:commons-logging:1.1.3"
    }
The above declaration will force all any transitive dependencies on `commons-logging` to use the 1.1.3 version without you having to declare an explicit dependency on `commons-logging` yourself. In addition to the version, you can also control the scope and exclusion rules of a dependency. ### Where are the JARs? With all these declarative dependencies, you may wonder where all the JARs end up. They have to go somewhere after all. By default Grails puts them into a directory, called the dependency cache, that resides on your local file system at `user.home/.grails/ivy-cache` or `user.home/.m2/repository` when using Aether. You can change this either via the `settings.groovy` file:
    grails.dependency.cache.dir = "${userHome}/.my-dependency-cache"
or in the dependency DSL:
    grails.project.dependency.resolution = {
        …
        cacheDir "target/ivy-cache"
        …
    }
The `settings.groovy` option applies to all projects, so it's the preferred approach. ## 5.7.2 Dependency Repositories #### Remote Repositories Initially your BuildConfig.groovy does not use any remote public Maven repositories. There is a default `grailsHome()` repository that will locate the JAR files Grails needs from your Grails installation. To use a public repository, specify it in the `repositories` block:
    repositories {
        mavenCentral()
    }
In this case the default public Maven repository is specified. You can also specify a specific Maven repository to use by URL:
    repositories {
        mavenRepo "http://repository.codehaus.org"
    }
and even give it a name:
    repositories {
        mavenRepo name: "Codehaus", root: "http://repository.codehaus.org"
    }
so that you can easily identify it in logs. #### Offline Mode There are times when it is not desirable to connect to any remote repositories (whilst working on the train for example!). In this case you can use the `offline` flag to execute Grails commands and Grails will not connect to any remote repositories:
    grails --offline run-app
Note that this command will fail if you do not have the necessary dependencies in your local Maven cache You can also globally configure offline mode by setting `grails.offline.mode` to `true` in `~/.grails/settings.groovy` or in your project's `BuildConfig.groovy` file:
    grails.offline.mode=true
To specify your local Maven cache (`~/.m2/repository`) as a repository:
    repositories {
        mavenLocal()
    }
#### Authentication with Aether To authenticate with Aether you can either define the credentials on the repository definition:
    mavenRepo(url:"http://localhost:8082/myrepo") {
        auth username: "foo", password: "bar"
    }
Or you can specify an `id` on the repository:
    mavenRepo(id:'myrepo', url:"http://localhost:8082/myrepo")
And then declare your credentials in `USER_HOME/.grails/settings.groovy`:
    grails.project.dependency.authentication = {
        credentials {
            id = "myrepo"
            username = "admin"
            password = "password"
        }
    }
#### Authentication with Ivy If your repository requires authentication you can configure this using a `credentials` block:
    credentials {
        realm = ".."
        host = "localhost"
        username = "myuser"
        password = "mypass"
    }
This can be placed in your `USER_HOME/.grails/settings.groovy` file using the `grails.project.ivy.authentication` setting:
    grails.project.ivy.authentication = {
        credentials {
            realm = ".."
            host = "localhost"
            username = "myuser"
            password = "mypass"
        }
    }
## 5.7.3 Debugging Resolution If you are having trouble getting a dependency to resolve you can enable more verbose debugging from the underlying engine using the `log` method:
    // log level of the Aether or Ivy resolver, either 'error', 'warn',
    // 'info', 'debug' or 'verbose'
    log "warn"
A common issue is that the checksums for a dependency don't match the associated JAR file, and so Ivy rejects the dependency. This helps ensure that the dependencies are valid. But for a variety of reasons some dependencies simply don't have valid checksums in the repositories, even if they are valid JARs. To get round this, you can disable Ivy's dependency checks like so:
    grails.project.dependency.resolution = {
        …
        log "warn"
        checksums false
        …
    }
This is a global setting, so only use it if you have to. ## 5.7.4 Inherited Dependencies By default every Grails application inherits several framework dependencies. This is done through the line:
    inherits "global"
Inside the `BuildConfig.groovy` file. To exclude specific inherited dependencies you use the `excludes` method:
    inherits("global") {
        excludes "oscache", "ehcache"
    }
## 5.7.5 Providing Default Dependencies Most Grails applications have runtime dependencies on several jar files that are provided by the Grails framework. These include libraries like Spring, Sitemesh, Hibernate etc. When a war file is created, all of these dependencies will be included in it. But, an application may choose to exclude these jar files from the war. This is useful when the jar files will be provided by the container, as would normally be the case if multiple Grails applications are deployed to the same container. The dependency resolution DSL provides a mechanism to express that all of the default dependencies will be provided by the container. This is done by invoking the `defaultDependenciesProvided` method and passing `true` as an argument:

    grails.project.dependency.resolution = {    defaultDependenciesProvided true // all of the default dependencies will
                                         // be "provided" by the container    inherits "global" // inherit Grails' default dependencies    repositories {
            grailsHome()
            …
        }
        dependencies {
            …
        }
    }
`defaultDependenciesProvided` must come before `inherits`, otherwise the Grails dependencies will be included in the war. ## 5.7.6 Snapshots and Other Changing Dependencies #### Configuration Changing dependencies Typically, dependencies are constant. That is, for a given combination of `group`, `name` and `version` the jar (or plugin) that it refers to will never change. The Grails dependency management system uses this fact to cache dependencies in order to avoid having to download them from the source repository each time. Sometimes this is not desirable. For example, many developers use the convention of a snapshot (i.e. a dependency with a version number ending in “-SNAPSHOT”) that can change from time to time while still retaining the same version number. We call this a "changing dependency". Whenever you have a changing dependency, Grails will always check the remote repository for a new version. More specifically, when a changing dependency is encountered during dependency resolution its last modified timestamp in the local cache is compared against the last modified timestamp in the dependency repositories. If the version on the remote server is deemed to be newer than the version in the local cache, the new version will be downloaded and used. Be sure to read the next section on "Dependency Resolution Caching" in addition to this one as it affects changing dependencies. All dependencies (jars and plugins) with a version number ending in `-SNAPSHOT` are implicitly considered to be changing by Grails. You can also explicitly specify that a dependency is changing by setting the changing flag in the dependency DSL (This is only required for Ivy, Aether does not support the 'changing' flag and treats dependencies that end with -SNAPSHOT as changing):
    runtime ('org.my:lib:1.2.3') {
        changing = true
    }
#### Aether and SNAPSHOT dependencies The semantics for handling snapshots when using Aether in Grails are the same as those when using the Maven build tool. The default snapshot check policy is to check once a day for a new version of the dependency. This means that if a new snapshot is published during the day to a remote repository you may not see that change unless you manually clear out your local snapshot. If you wish to change the snapshot update policy you can do so by configuring an `updatePolicy` for the repository where the snapshot was resolved from, for example:
    repositories {
        mavenCentral {
            updatePolicy "interval:1"
        }
    }
The above example configures an update policy that checks once a minute for changes. Note that that an `updatePolicy` like the above will seriously impact performance of dependency resolution. The possibly configuration values for `updatePolicy` are as follows: `never` - Never check for new snapshots `always` - Always check for new snapshots `daily` - Check once a day for new snapshots (the default) `interval:x` - Check once every x minutes for new snapshots #### Ivy and Changing dependencies For those used to Maven snapshot handling, if you use Aether dependency management you can expect the same semantics as Maven. If you choose to use Ivy there is a caveat to the support for changing dependencies that you should be aware of. Ivy will stop looking for newer versions of a dependency once it finds a remote repository that has the dependency. Consider the following setup:
    grails.project.dependency.resolution = {
        repositories {
            mavenLocal()
            mavenRepo "http://my.org/repo"
        }
        dependencies {
            compile "myorg:mylib:1.0-SNAPSHOT"
        }
In this example we are using the local maven repository and a remote network maven repository. Assuming that the local OI dependency and the local Maven cache do not contain the dependency but the remote repository does, when we perform dependency resolution the following actions will occur: maven local repository is searched, dependency not found maven network repository is searched, dependency is downloaded to the cache and used Note that the repositories are checked in the order they are defined in the `BuildConfig.groovy` file. If we perform dependency resolution again without the dependency changing on the remote server, the following will happen: maven local repository is searched, dependency not found maven network repository is searched, dependency is found to be the same "age" as the version in the cache so will not be updated (i.e. downloaded) Later on, a new version of `mylib 1.0-SNAPSHOT` is published changing the version on the server. The next time we perform dependency resolution, the following will happen: maven local repository is searched, dependency not found maven network repository is searched, dependency is found to newer than version in the cache so will be updated (i.e. downloaded to the cache) So far everything is working well. Now we want to test some local changes to the `mylib` library. To do this we build it locally and install it to the local Maven cache (how doesn't particularly matter). The next time we perform a dependency resolution, the following will occur: maven local repository is searched, dependency is found to newer than version in the cache so will be updated (i.e. downloaded to the cache) maven network repository is NOT searched as we've already found the dependency This is what we wanted to occur. Later on, a new version of `mylib 1.0-SNAPSHOT` is published changing the version on the server. The next time we perform dependency resolution, the following will happen: maven local repository is searched, dependency is found to be the same "age" as the version in the cache so will not be updated (i.e. downloaded) maven network repository is NOT searched as we've already found the dependency This is likely to not be the desired outcome. We are now out of sync with the latest published snapshot and will continue to keep using the version from the local maven repository. The rule to remember is this: when resolving a dependency, Ivy will stop searching as soon as it finds a repository that has the dependency at the specified version number. It will not continue searching all repositories trying to find a more recently modified instance. To remedy this situation (i.e. build against the newer version of `mylib 1.0-SNAPSHOT` in the remote repository), you can either: Delete the version from the local maven repository, or Reorder the repositories in the `BuildConfig.groovy` file Where possible, prefer deleting the version from the local maven repository. In general, when you have finished building against a locally built SNAPSHOT always try to clear it from the local maven repository. This changing dependency behaviour is an unmodifiable characteristic of the underlying dependency management system Apache Ivy. It is currently not possible to have Ivy search all repositories to look for newer versions (in terms of modification date) of the same dependency (i.e. the same combination of `group`, `name` and `version`). If you want this behavior consider switching to Aether as the dependency manager. ## 5.7.7 Dependency Reports As mentioned in the previous section a Grails application consists of dependencies inherited from the framework, the plugins installed and the application dependencies itself. To obtain a report of an application's dependencies you can run the dependency-report command:
    grails dependency-report
By default this will generate reports in the `target/dependency-report` directory. You can specify which configuration (scope) you want a report for by passing an argument containing the configuration name:
    grails dependency-report runtime
As of Grails 2.3 the `dependency-report` command will also output to the console a graph of the dependencies of an application. Example output it shown below:
    compile - Dependencies placed on the classpath for compilation (total: 73)
    +--- org.codehaus.groovy:groovy-all:2.0.6
    +--- org.grails:grails-plugin-codecs:2.3.0
    |    --- org.grails:grails-web:2.3.0
    |         --- commons-fileupload:commons-fileupload:1.2.2
    |         --- xpp3:xpp3_min:1.1.4c
    |         --- commons-el:commons-el:1.0
    |         --- opensymphony:sitemesh:2.4
    |         --- org.springframework:spring-webmvc:3.1.2.RELEASE
    |    --- commons-codec:commons-codec:1.5
    |    --- org.slf4j:slf4j-api:1.7.2
    +--- org.grails:grails-plugin-controllers:2.3.0
    |    --- commons-beanutils:commons-beanutils:1.8.3
    |    --- org.grails:grails-core:2.3.0
    ...
## 5.7.8 Plugin JAR Dependencies #### Specifying Plugin JAR dependencies The way in which you specify dependencies for a plugin is identical to how you specify dependencies in an application. When a plugin is installed into an application the application automatically inherits the dependencies of the plugin. To define a dependency that is resolved for use with the plugin but not exported to the application then you can set the `export` property of the dependency:
    compile('org.spockframework:spock-core:0.5-groovy-1.8') {
        export = false
    }
In this case the Spock dependency will be available only to the plugin and not resolved as an application dependency. Alternatively, if you're using the Map syntax:
    compile group: 'org.spockframework', name: 'spock-core',
         version: '0.5-groovy-1.8', export: false
You can use `exported = false` instead of `export = false`, but we recommend the latter because it's consistent with the Map argument. #### Overriding Plugin JAR Dependencies in Your Application If a plugin is using a JAR which conflicts with another plugin, or an application dependency then you can override how a plugin resolves its dependencies inside an application using exclusions. For example:

    plugins {
        compile(":hibernate:$grailsVersion") {
            excludes "javassist"
        }
    }dependencies {
        runtime "javassist:javassist:3.4.GA"
    }
In this case the application explicitly declares a dependency on the "hibernate" plugin and specifies an exclusion using the `excludes` method, effectively excluding the javassist library as a dependency. ## 5.7.9 Maven Integration When using the Grails Maven plugin with the Maven build tool, Grails' dependency resolution mechanics are disabled as it is assumed that you will manage dependencies with Maven's `pom.xml` file. However, if you would like to continue using Grails regular commands like run-app, test-app and so on then you can tell Grails' command line to load dependencies from the Maven `pom.xml` file instead. To do so simply add the following line to your `BuildConfig.groovy`:
    grails.project.dependency.resolution = {
        pom true
        ..
    }
The line `pom true` tells Grails to parse Maven's `pom.xml` and load dependencies from there. ## 5.7.10 Deploying to a Maven Repository If you use Maven to build your Grails project, you can use the standard Maven targets `mvn install` and `mvn deploy`. If not, you can deploy a Grails project or plugin to a Maven repository using the release plugin. The plugin provides the ability to publish Grails projects and plugins to local and remote Maven repositories. There are two key additional targets added by the plugin: maven-install - Installs a Grails project or plugin into your local Maven cache maven-deploy - Deploys a Grails project or plugin to a remote Maven repository By default this plugin will automatically generate a valid `pom.xml` for you unless a `pom.xml` is already present in the root of the project, in which case this `pom.xml` file will be used. #### maven-install The `maven-install` command will install the Grails project or plugin artifact into your local Maven cache:
    grails maven-install
In the case of plugins, the plugin zip file will be installed, whilst for application the application WAR file will be installed. #### maven-deploy The `maven-deploy` command will deploy a Grails project or plugin into a remote Maven repository:
    grails maven-deploy
It is assumed that you have specified the necessary `<distributionManagement>` configuration within a `pom.xml` or that you specify the `id` of the remote repository to deploy to:
    grails maven-deploy --repository=myRepo
The `repository` argument specifies the 'id' for the repository. Configure the details of the repository specified by this 'id' within your `grails-app/conf/BuildConfig.groovy` file or in your `$USER_HOME/.grails/settings.groovy` file:
    grails.project.dependency.distribution = {
        localRepository = "/path/to/my/local"
        remoteRepository(id: "myRepo", url: "http://myserver/path/to/repo")
    }
The syntax for configuring remote repositories matches the syntax from the remoteRepository element in the Ant Maven tasks. For example the following XML:
    <remoteRepository id="myRepo" url="scp://localhost/www/repository">
        <authentication username="..." privateKey="${user.home}/.ssh/id_dsa"/>
    </remoteRepository>
Can be expressed as:
    remoteRepository(id: "myRepo", url: "scp://localhost/www/repository") {
        authentication username: "...", privateKey: "${userHome}/.ssh/id_dsa"
    }
By default the plugin will try to detect the protocol to use from the URL of the repository (e.g. "http" from "http://.." etc.), however to specify a different protocol you can do:
    grails maven-deploy --repository=myRepo --protocol=webdav
The available protocols are: http scp scpexe ftp webdav #### Groups, Artifacts and Versions Maven defines the notion of a 'groupId', 'artifactId' and a 'version'. This plugin pulls this information from the Grails project conventions or plugin descriptor. ##### Projects For applications this plugin will use the Grails application name and version provided by Grails when generating the `pom.xml` file. To change the version you can run the `set-version` command:
    grails set-version 0.2
The Maven `groupId` will be the same as the project name, unless you specify a different one in Config.groovy:
    grails.project.groupId="com.mycompany"
##### Plugins With a Grails plugin the `groupId` and `version` are taken from the following properties in the `GrailsPlugin.groovy` descriptor:
    String groupId = 'myOrg'
    String version = '0.1'
The 'artifactId' is taken from the plugin name. For example if you have a plugin called `FeedsGrailsPlugin` the `artifactId` will be "feeds". If your plugin does not specify a `groupId` then this defaults to "org.grails.plugins". ## 5.7.11 Plugin Dependencies You can declaratively specify plugins as dependencies via the dependency DSL instead of using the install-plugin command:

    grails.project.dependency.resolution = {
        …
        repositories {
            …
        }    plugins {
            runtime ':hibernate:1.2.1'
        }    dependencies {
            …
        }
        …
    }
If you don't specify a group id the default plugin group id of `org.grails.plugins` is used. #### Latest Integration Only the Ivy dependency manager supports the "latest.integration" version. For Aether you can achieve a similar effect with version ranges. You can specify to use the latest version of a particular plugin by using "latest.integration" as the version number:
    plugins {
        runtime ':hibernate:latest.integration'
    }
#### Integration vs. Release The "latest.integration" version label will also include resolving snapshot versions. To not include snapshot versions then use the "latest.release" label:
    plugins {
        runtime ':hibernate:latest.release'
    }
The "latest.release" label only works with Maven compatible repositories. If you have a regular SVN-based Grails repository then you should use "latest.integration". And of course if you use a Maven repository with an alternative group id you can specify a group id:
    plugins {
        runtime 'mycompany:hibernate:latest.integration'
    }
#### Plugin Exclusions You can control how plugins transitively resolves both plugin and JAR dependencies using exclusions. For example:
    plugins {
        runtime(':weceem:0.8') {
            excludes "searchable"
        }
    }
Here we have defined a dependency on the "weceem" plugin which transitively depends on the "searchable" plugin. By using the `excludes` method you can tell Grails not to transitively install the searchable plugin. You can combine this technique to specify an alternative version of a plugin:
    plugins {
        runtime(':weceem:0.8') {
            excludes "searchable" // excludes most recent version
        }
        runtime ':searchable:0.5.4' // specifies a fixed searchable version
    }
You can also completely disable transitive plugin installs, in which case no transitive dependencies will be resolved:
    plugins {
        runtime(':weceem:0.8') {
            transitive = false
        }
        runtime ':searchable:0.5.4' // specifies a fixed searchable version
    }
## 5.7.12 Caching of Dependency Resolution Results As a performance optimisation, when using Ivy (this does not apply to Aether), Grails does not resolve dependencies for every command invocation. Even with all the necessary dependencies downloaded and cached, resolution may take a second or two. To minimise this cost, Grails caches the result of dependency resolution (i.e. the location on the local file system of all of the declared dependencies, typically inside the dependency cache) and reuses this result for subsequent commands when it can reasonably expect that nothing has changed. Grails only performs dependency resolution under the following circumstances: The project is clean (i.e. fresh checkout or after `grails clean`) The `BuildConfig.groovy` file has changed since the last command was run The `--refresh-dependencies` command line switch is provided to the command (any command) The `refresh-dependencies` command is the command being executed Generally, this strategy works well and you can ignore dependency resolution caching. Every time you change your dependencies (i.e. modify `BuildConfig.groovy`) Grails will do the right thing and resolve your new dependencies. However, when you have changing or dynamic dependencies you will have to consider dependency resolution caching. {info} A changing dependency is one whose version number does not change, but its contents do (like a SNAPSHOT). A dynamic dependency is one that is defined as one of many possible options (like a dependency with a version range, or symbolic version number like `latest.integration`). {info} Both changing and dynamic dependencies are influenced by the environment. With caching active, any changes to the environment are effectively ignored. For example, your project may not automatically fetch the very latest version of a dependency when using `latest.integration`. Or if you declare a `SNAPSHOT` dependency, you may not automatically get the latest that's available on the server. To ensure you have the correct version of a changing or dynamic dependency in your project, you can: clean the project run the `refresh-dependencies` command run any command with the `--refresh-dependencies` switch; or make a change to `BuildConfig.groovy` If you have your CI builds configured to not perform clean builds, it may be worth adding the `--refresh-dependencies` switch to the command you use to build your projects. | Quick Reference (hide)