3.7 Dependency Resolution - Reference Documentation
Authors: Graeme Rocher, Peter Ledbrook, Marc Palmer, Jeff Brown, Luke Daley, Burt Beckwith
Version: null
Table of Contents
3.7 Dependency Resolution
Grails features a dependency resolution DSL that lets you control how plugins and JAR dependencies are resolved.You specify agrails.project.dependency.resolution property inside the grails-app/conf/BuildConfig.groovy file that configures how dependencies are resolved:grails.project.dependency.resolution = {
// config here
}grails.project.class.dir = "target/classes" grails.project.test.class.dir = "target/test-classes" grails.project.test.reports.dir = "target/test-reports" //grails.project.war.file = "target/${appName}-${appVersion}.war"grails.project.dependency.resolution = { // inherit Grails' default dependencies inherits("global") { // uncomment to disable ehcache // excludes 'ehcache' } log "warn" repositories { grailsPlugins() grailsHome() grailsCentral() // uncomment these to enable remote dependency resolution // from public Maven repositories //mavenCentral() //mavenLocal() //mavenRepo "http://snapshots.repository.codehaus.org" //mavenRepo "http://repository.codehaus.org" //mavenRepo "http://download.java.net/maven/2/" //mavenRepo "http://repository.jboss.com/maven2/" } dependencies { // specify dependencies here under either 'build', 'compile', // 'runtime', 'test' or 'provided' scopes eg. // runtime 'mysql:mysql-connector-java:5.1.16' } plugins { compile ":hibernate:$grailsVersion" compile ":jquery:1.6.1.1" compile ":resources:1.0" build ":tomcat:$grailsVersion" } }
3.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
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'
group:name:version. You can also use a Map-based syntax:runtime group: 'com.mysql',
name: 'mysql-connector-java',
version: '5.1.16'group corresponds to an artifact's groupId and name corresponds to its artifactId.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:falseExcluding 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 theexcludes 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' ])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"
}Using Ivy module configurations
If you use Ivy module configurations and wish to depend on a specific configuration of a module, you can use thedependencyConfiguration method to specify the configuration to use.provided("my.org:web-service:1.0") { dependencyConfiguration "api" }
"default" will be used (which is also the correct value for dependencies coming from Maven style repositories).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 atuser.home/.grails/ivy-cache. You can change this either via the settings.groovy file:grails.dependency.cache.dir = "${userHome}/.my-dependency-cache"grails.project.dependency.resolution = {
…
cacheDir "target/ivy-cache"
…
}settings.groovy option applies to all projects, so it's the preferred approach.
3.7.2 Dependency Repositories
Remote Repositories
Initially your BuildConfig.groovy does not use any remote public Maven repositories. There is a defaultgrailsHome() 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()
}ebr() method:repositories {
ebr()
}repositories {
mavenRepo "http://repository.codehaus.org"
}repositories {
mavenRepo name: "Codehaus", root: "http://repository.codehaus.org"
}Controlling Repositories Inherited from Plugins
A plugin you have installed may define a reference to a remote repository just as an application can. By default your application will inherit this repository definition when you install the plugin.If you do not wish to inherit repository definitions from plugins then you can disable repository inheritance:repositories {
inherit false
}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 theoffline 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 Ivy cacheYou 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=trueLocal Resolvers
If you do not wish to use a public Maven repository you can specify a flat file repository:repositories {
flatDir name:'myRepo', dirs:'/path/to/repo'
}~/.m2/repository) as a repository:repositories {
mavenLocal()
}Custom Resolvers
If all else fails since Grails builds on Apache Ivy you can specify an Ivy resolver:/* * Configure our resolver. */ def libResolver = new org.apache.ivy.plugins.resolver.URLResolver() ['libraries', 'builds'].each { libResolver.addArtifactPattern( "http://my.repository/${it}/" + "[organisation]/[module]/[revision]/[type]s/[artifact].[ext]") libResolver.addIvyPattern( "http://my.repository/${it}/" + "[organisation]/[module]/[revision]/[type]s/[artifact].[ext]") }libResolver.name = "my-repository" libResolver.settings = ivySettingsresolver libResolver
import org.apache.ivy.plugins.resolver.SshResolver … repositories { ... def sshResolver = new SshResolver( name: "myRepo", user: "username", host: "dev.x.com", keyFile: new File("/home/username/.ssh/id_rsa"), m2compatible: true) sshResolver.addArtifactPattern( "/home/grails/repo/[organisation]/[artifact]/" + "[revision]/[artifact]-[revision].[ext]") sshResolver.latestStrategy = new org.apache.ivy.plugins.latest.LatestTimeStrategy() sshResolver.changingPattern = ".*SNAPSHOT" sshResolver.setCheckmodified(true) resolver sshResolver }
grails -classpath /path/to/jsch compile|run-app|etc.
CLASSPATH environment variable but be aware this it affects many Java applications. An alternative on Unix is to create an alias for grails -classpath ... so that you don't have to type the extra arguments each time.Authentication
If your repository requires authentication you can configure this using acredentials block:credentials {
realm = ".."
host = "localhost"
username = "myuser"
password = "mypass"
}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"
}
}3.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 thelog method:// log level of Ivy resolver, either 'error', 'warn',
// 'info', 'debug' or 'verbose'
log "warn"grails.project.dependency.resolution = {
…
log "warn"
checksums false
…
}3.7.4 Inherited Dependencies
By default every Grails application inherits several framework dependencies. This is done through the line:inherits "global"BuildConfig.groovy file. To exclude specific inherited dependencies you use the excludes method:inherits("global") { excludes "oscache", "ehcache" }
3.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 thedefaultDependenciesProvided 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 {
…
}
}defaultDependenciesProvidedmust come beforeinherits, otherwise the Grails dependencies will be included in the war.
3.7.6 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
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
3.7.7 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 theexport property of the dependency:test('org.spockframework:spock-core:0.5-groovy-1.8') {
export = false
}test group: 'org.spockframework', name: 'spock-core',
version: '0.5-groovy-1.8', export: falseYou can useexported = falseinstead ofexport = 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"
}excludes method, effectively excluding the javassist library as a dependency.
3.7.8 Maven Integration
When using the Grails Maven plugin, Grails' dependency resolution mechanics are disabled as it is assumed that you will manage dependencies with Maven'spom.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
..
}pom true tells Grails to parse Maven's pom.xml and load dependencies from there.
3.7.9 Deploying to a Maven Repository
If you use Maven to build your Grails project, you can use the standard Maven targetsmvn install and mvn deploy.
If not, you can deploy a Grails project or plugin to a Maven repository using the maven-publisher 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
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
Themaven-install command will install the Grails project or plugin artifact into your local Maven cache:grails maven-install
maven-deploy
Themaven-deploy command will deploy a Grails project or plugin into a remote Maven repository:grails maven-deploy
<distributionManagement> configuration within a pom.xml or that you specify the id of the remote repository to deploy to:grails maven-deploy --repository=myRepo
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")
}<remoteRepository id="myRepo" url="scp://localhost/www/repository"> <authentication username="..." privateKey="${user.home}/.ssh/id_dsa"/> </remoteRepository>
remoteRepository(id: "myRepo", url: "scp://localhost/www/repository") { authentication username: "...", privateKey: "${userHome}/.ssh/id_dsa" }
grails maven-deploy --repository=myRepo --protocol=webdav
- 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 thepom.xml file. To change the version you can run the set-version command:grails set-version 0.2
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 thegroupId and version are taken from the following properties in the *GrailsPlugin.groovy descriptor:String groupId = 'myOrg' String version = '0.1'
FeedsGrailsPlugin the artifactId will be "feeds". If your plugin does not specify a groupId then this defaults to "org.grails.plugins".
3.7.10 Plugin Dependencies
As of Grails 1.3 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 {
…
}
…
}org.grails.plugins is used. 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"
}
}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
}plugins {
runtime(':weceem:0.8') {
transitive = false
}
runtime ':searchable:0.5.4' // specifies a fixed searchable version
}
