Defining dependencies

We learned how to use dependency configurations to group together dependencies; we saw how we must define repositories so dependencies can be resolved, but we haven't yet learned how to define the actual dependencies. We define dependencies in our build project with the dependencies{} script block. We define a closure to pass to the dependencies{} script block, with the configuration of the dependency.

We can define different types of dependencies. The following table shows the types we can use:

Dependency type

Method

Description

External module dependency

-

A dependency on an external module or library in a repository.

Project dependency

project()

Dependency on another Gradle project.

File dependency

files(),

fileTree()

Dependency on a collection of files on the local computer.

Client module dependency

module()

A dependency on an external module where the artifacts are stored in a repository but the meta information about the module is in the build file. We can override meta information using this type of dependency.

Gradle API dependency

gradleApi()

Dependency on the Gradle API of the current Gradle version. We use this dependency when we develop Gradle plugins and tasks.

Local Groovy dependency

localGroovy()

Dependency on the Groovy libraries used by the current Gradle version. We use this dependency when we develop Gradle plugins and tasks.

Using external module dependencies

The most used dependency is the external module dependency. We can define a module dependency in different ways. For example, we can use arguments to set a group name, module name, and revision of the dependency. Or, we can use the String notation to set the group name, module name, and revision in a single string. We always assign a dependency to a specific dependency configuration. The dependency configuration must be defined by ourselves or by a plugin we have applied to our project.

In the following example build file, we will use the Java plugin, so we get a compile and runtime dependency configuration. We will also assign several external module dependencies to each configuration using the different syntax rules:

apply plugin: 'java'

repositories {
    mavenCentral()
}

dependencies {
    compile group: 'org.springframework', name: 'spring-core', version: '3.1.1.RELEASE'
    
    runtime 'org.springframework:spring-aop:3.1.1.RELEASE'
}

Remember that a Gradle build file is a Groovy script file, so we can define variables to set values and use them in the dependencies{} script block configuration closure. If we rewrite the previous build file, we get:

apply plugin: 'java'

repositories {
    mavenCentral()
}

ext {
    springVersion = '3.1.1.RELEASE'
    springGroup = 'org.springframework'
}

dependencies {
    compile group: springGroup, name: 'spring-core', version: springVersion

    runtime "$springGroup:spring-aop:$springVersion"
}

Gradle will look for the descriptor file in the Maven central repository. If the file is found, the artifact of the module and the dependencies of the module are downloaded and made available to the dependency configuration

To see the dependencies and the transitive dependencies, we invoke the built-in task dependencies. We get the following output:

$ gradle –q dependencies

compile - Classpath for compiling the main sources.
--- org.springframework:spring-core:3.1.1.RELEASE [default]
     +--- org.springframework:spring-asm:3.1.1.RELEASE [compile,master,runtime]
     --- commons-logging:commons-logging:1.1.1 [compile,master,runtime]

runtime - Classpath for running the compiled main classes.
+--- org.springframework:spring-core:3.1.1.RELEASE [default]
|    +--- org.springframework:spring-asm:3.1.1.RELEASE [compile,master,runtime]
|    --- commons-logging:commons-logging:1.1.1 [compile,master,runtime]
--- org.springframework:spring-aop:3.1.1.RELEASE [default]
     +--- org.springframework:spring-core:3.1.1.RELEASE [compile,runtime,master] (*)
     +--- org.springframework:spring-asm:3.1.1.RELEASE [compile,master,runtime] (*)
     +--- aopalliance:aopalliance:1.0 [compile,master,runtime]
     --- org.springframework:spring-beans:3.1.1.RELEASE [compile,master,runtime]
          --- org.springframework:spring-core:3.1.1.RELEASE [compile,master,runtime] (*)

(*) - dependencies omitted (listed previously)

To only download the artifact of an external dependency and not the transitive dependencies, we can set the property transitive to false, for the dependency. We can set the property with a closure or as an extra property in the argument list:

apply plugin: 'java'

repositories {
    mavenCentral()
}

dependencies {
    // Configure transitive property with closure.
    compile('org.slf4j:slf4j-simple:1.6.4') {
        transitive = false
    }
    
    // Or we can use the transitive property
    // as method argument.
    compile group: 'org.slf4j', name: 'slf4j-simple', version: '1.6.4', transitive: false
}

We can also exclude some transitive dependencies, with the exclude() method. Gradle will look at the descriptor file of the module and exclude any dependencies that we have added with the exclude() method.

For example, in the following build file we exclude the transitive dependency org.slf4j:sl4j-api:

apply plugin: 'java'

repositories {
    mavenCentral()
}

dependencies {
    // Configure transitive property with closure.
    compile('org.slf4j:slf4j-simple:1.6.4') {
        exclude 'org.slf4j:slf4j-api'
    }
}

To only get an artifact of an external module dependency we can use the "artifact-only" notation. We must also use this notation when a repository doesn't have a module descriptor file and we want to get the artifact. We must add an @ symbol before the extension of the artifact. Gradle will not look at the module descriptor file, if available, when we use this notation:

apply plugin: 'java'

repositories {
    mavenCentral()
}

dependencies {
    // Use artifact-only notation with @ symbol.
    runtime('org.slf4j:slf4j-simple:1.6.4@jar')

    // Or we can use the ext property
    // as method argument.
    runtime group: 'org.slf4j', name: 'slf4j-simple', version: '1.6.4', ext: 'jar
}

We can even set the transitive behavior on a complete configuration. Each configuration has a property transitive. We can set the value to true or false to change the transitive behavior for each dependency we define in the configuration. In the following sample build file, we set the transitive property on the runtime configuration:

apply plugin: 'java'

repositories {
    mavenCentral()
}

dependencies {
 compile('org.slf4j:slf4j-simple:1.6.4')
}

configurations.compile.transitive = false

In a Maven repository, we can use classifiers for a dependency. For example, the module descriptor file defines the classifiers jdk16 and jdk15 for different JDK versions of the library. We can use the classifier in a Gradle dependency definition to select the dependency with the given classifier:

apply plugin: 'java'

repositories {
    mavenCentral()
}

dependencies {
    // Use artifact-only notation with @ symbol 
    // together with classifier jdk16.
    compile('sample:simple:1.0:jdk16@jar')

    // Or we can use the classifier property
    // as method argument.
    compile group: 'sample', name: 'simple', version: '1.0', classifier: 'jdk16'
}

The module descriptor of a module in a Maven repository can only have one artifact, but in an Ivy repository, we can define multiple artifacts for a single module. Each set of artifacts is grouped together in a configuration. The default configuration contains all artifacts belonging to the module. If we don't specify the configuration property when we define the dependency for an Ivy module, the default configuration is used. We must specify the configuration property if we want to use artifacts belonging to that specific configuration:

apply plugin: 'java'

repositories {
    ivy {
        url = 'http://intranet/custom'
        ivyPatterns '[module]/[revision]/ivy.xml'
        artifactPatterns '[module]/[revision]/[artifact](.[ext])'
    }
}

dependencies {
    // Use configuration property in method arguments.
    testCompile group: 'sample', name: 'logging', version: '1.0', configuration: 'test'

    // Or we use a closure to set the property.
    testCompile('sample:logging:1.0') {
        configuration = 'test
    }
}

Using project dependencies

Gradle projects can be dependent on each other. To define such a dependency we use the project() method and use the name of the other project as an argument. Gradle will look for a default dependency configuration in that project and use that as a dependency. We can use the configuration property to use different dependency configurations as a dependency for each project:

apply plugin: 'java'

dependencies {
    compile project(':projectA')

    compile project(':projectB') {
        configuration = 'compile'    }
}

Using file dependencies

We can add dependencies using FileCollection. We can use the methods file(), files(), and fileTree() to add dependencies to a configuration. The dependency must be resolved to an actual artifact.

The following example uses file dependencies for the compile configuration:

apply plugin: 'java'

dependencies {
    compile files('spring-core.jar', 'spring-aap.jar')
    compile fileTree(dir: 'deps', include: '*.jar')
}

Using client module dependencies

Normally, Gradle will use a descriptor XML file for dependencies found in the repository to see which artifacts and optional transitive dependencies need to be downloaded. But those descriptor files can be misconfigured, and so we may want to override the descriptors ourselves to ensure the dependencies are correct. To do this we must use the module() method to define the transitive dependencies of a dependency. Gradle will then use our own configuration and not the one provided by the module in a repository:

apply plugin: 'java'

ext {
    springGroup = 'org.springframework'
    springRelease = '3.1.1.RELEASE'
}
dependencies {
    compile module("$springGroup:spring-context:$springRelease") {
        dependency("$springGroup:spring-aop:$springRelease") {
            transitive = false
        }
    }
}

Using Gradle and Groovy dependencies

When we develop Grails plugins and tasks, we can define a dependency on the Gradle API and the Groovy libraries used by the current Gradle version. We can use the methods gradleApi() and localGroovy() to do this.

The following example defines the dependencies in the compile dependency configuration of a project:

apply plugin: 'groovy'

// Dependency configuration for developing
// Gradle plugins and tasks with Groovy.
dependencies {
    // Gradle API available for compile task.
    compile gradleApi()

    // Groovy libraries used by Gradle version.
    groovy localGroovy()
}

Accessing configuration dependencies

We can access the dependencies for a dependency configuration in a build file or task through the configurations property of the Project object. We can use the dependencies() and allDependencies() methods to get a reference to the dependencies:

apply plugin: 'java'

repositories {
    mavenCentral()
}

dependencies {
    runtime "org.springframework:spring-aop:3.1.1.RELEASE"
}

task 'dependencyInfo' << {
    println "-- Runtime dependencies --"
    configurations.runtime.dependencies.each {
        println "${it.group}:${it.name}:${it.version}"
    }

    println "-- Runtime allDependencies --"
    configurations.runtime.allDependencies.each {
        println "${it.group}:${it.name}:${it.vesion}"
    }
}

Setting dynamic versions

Until now, we have set a version for a dependency explicitly with a complete version number. To set a minimum version number, we can use a special dynamic version syntax. For example, to set the dependency version to a minimum of 2.1 for a dependency, we use a version value 2.1.+. Gradle will resolve the dependency to the latest version after version 2.1, or to version 2.1 itself. In the following example, we will define a dependency on a spring-core version of at least 3.1:

apply plugin: 'java'

repositories {
    mavenCentral()
}

dependencies {
    compile group: 'org.springframework', name: 'spring-core', version: '3.1.+'
}

We can also reference the latest released version of a module with latest.integration. We can also set a version range with a minimum and maximum version number. The following table shows the ranges we can use:

Range

Description

[1.0, 2.0]

All versions greater than or equal to 1.0 and lower than or equal to 2.0

[1.0, 2.0[

All versions greater than or equal to 1.0 and lower than 2.0

]1.0, 2.0]

All versions greater than 1.0 and lower than or equal to 2.0

]1.0, 2.0[

All versions greater than 1.0 and lower than 2.0

[1.0, )

All versions greater than or equal to 1.0

]1.0, )

All versions greater than 1.0

(, 2.0]

All versions lower than or equal to 2.0

(, 2.0[

All versions lower than 2.0

The following example build file will use version 3.0.7.RELEASE as the latest release, which is greater than 3.0 and less than 3.1:

apply plugin: 'java'

repositories {
    mavenCentral()
}

dependencies {
    compile group: 'org.springframework', name: 'spring-core', version: '[3.0, 3.1['
}

Resolving version conflicts

If we have a project with a lot of dependencies and those dependencies have transitive dependencies, version conflicts can easily arise. If one module has a dependency on sample:logging:1.0 and another on sample:logging:2.0, Gradle will, by default, use the newest version number.

To change the default behavior, we set the resolutionStrategy property of a dependency configuration. We can instruct Gradle to fail the build if a conflict arises. This is very useful for debugging version conflicts.

In the following example build file, we instruct Gradle to fail the build if a version conflicts arises for all configurations:

apply plugin: 'java'

configurations.all {
    resolutionStrategy {
        failOnVersionConflict()
    }
}

To force a certain version number to be used for all dependencies (even transitive dependencies), we can use the force() method of resolutionStrategy. With this method we can make sure that, for a given module, the preferred version is always used:

apply plugin: 'java'

configurations.compile {
    resolutionStrategy {
        force 'org.springframework:spring-core:3.1.0.RELEASE'
    }
}

Adding optional ANT tasks

We can re-use existing ANT (Another Neat Tool) tasks in Gradle build files. Gradle uses Groovy's AntBuilder for ANT integration. But, if we want to use an optional ANT task we must do something extra, because the optional tasks and their dependencies are not in the Gradle classpath. Luckily, we only have to define our dependencies for the optional task in the build.gradle file, and we can then define and use the optional ANT task.

In the following sample, we are using the scp ANT optional task. We define a new configuration with the name sshAntTask and assign the dependencies to this configuration. Then, we can define the task and set the classpath property to the classpath of the configuration. We use the asPath property to convert the configuration classpath for the ANT task. In the sample, we also see how we can ask for user input when the script is run. The passphrase for the ssh keyfile is a secret and we don't want to keep it in a file somewhere, so we ask the user for it. The Java method System.console() returns a reference to the console, and with the readPassword() method, we can get the value for the passphrase:

// We define a new configuration with the name 'sshAntTask'.
// This configuration is used to define our dependencies.
configurations {
    sshAntTask
}

repositories.mavenCentral()

// Assign dependencies to the sshAntTask configuration.
dependencies {
    sshAntTask 'org.apache.ant:ant-jsch:1.7.1', 'jsch:jsch:0.1.29'
}

// Sample task which uses the scp ANT optional task.
task update {
    description = 'Update files on remote server.'

    // Get passphrase from user input.
    def console = System.console()
    def passphrase = console.readPassword('%s: ', 'Please enter the passphrase for the keyfile')
        
    // Redefine scp ANT task, with the classpath property set to our newly defined
    // sshAntTask configuration classpath.
    ant.taskdef(name: 'scp', classname: 'org.apache.tools.ant.taskdefs.optional.ssh.Scp',
            classpath: configurations.sshAntTask.asPath)
            
    // Invoke the scp ANT task. (Use gradle -i update to see the output of the ANT task.)
    ant.scp(todir: 'mrhaki@servername:/home/mrhaki',
            keyfile: '${user.home}/.ssh/id_rsa', 
            passphrase: passphrase as String, // Use phassphrase entered by the user.
            verbose: 'true') {
        fileset(dir: 'work') {
            include(name: '**/**')
        }
    }           
}

Using dependency configurations as files

Each dependency configuration implements the FileCollection interface of Gradle. This means we can use a configuration reference if we need a list of files somewhere. The files that make up the resolved dependency configuration are then used.

Let's create a new build file and use a dependency configuration as the value for the from() method. We create a new task of type Copy and copy all dependencies of a new configuration, springLibs, to a directory:

repositories.mavenCentral()

configurations {
    springLibs
}

dependencies {
    springLibs 'org.springframework:spring-web:3.1.1.RELEASE'
}

task copyCompileDeps(type: Copy) {
    from configurations.springLibs
    into "$buildDir/compileLibs"
}
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.16.137.38