Chapter 5. Dependency Management

When we develop our code, we usually use third-party or open source libraries. These libraries need to be available in the classpath of the compiler, otherwise we will get errors and our build will fail. Gradle provides support for dependency management, so we can define our dependencies in our build file. Gradle will then take care of the necessary configuration for our various tasks.

In this chapter, we will learn how we can use dependency management in our builds. We will see how to organize dependencies with configurations. We will also learn about repositories that host dependency artifacts, their dependencies, and how we can handle different repository layouts.

Then we will define dependencies using Gradle syntax, for modules with version information.

Dependency configuration

Java has no real support for working with versioned libraries as dependencies. We cannot express in Java whether our class depends on lib-1.0.jar or lib-2.0.jar, for example. There are some open source solutions that deal with dependencies and allow us to express whether our Java code depends on lib-1.0.jar or lib-2.0.jar. The most popular are Maven and Apache Ivy. Maven is a complete build tool and has a mechanism for dependency management. Ivy is only about dependency management.

Both tools support repositories where versioned libraries are stored, together with metadata about those libraries. A library can have dependencies on other libraries and is described in the metadata of the library. The metadata is described in descriptor XML files. Ivy fully supports Maven descriptor files and repositories; it also adds some extra functionality. So with Ivy, you get what you would with Maven, and then some more. That is why Gradle uses the Ivy API under the hood to do dependency management. Gradle also adds some extra sugar on top of Ivy, so we can define and use dependencies in a very flexible way.

In a Gradle build file, we group dependencies together in a configuration. A configuration has a name, and configurations can extend each other. With a configuration, we can make logical groups of dependencies. For example, we can create a javaCompile configuration to include dependencies needed to compile the Java code. We can add as many configurations to our build as we want to. We don't define our dependencies directly in the configuration. A configuration, as with a label, can be used when we define a dependency.

Every Gradle build has a ConfigurationContainer object. This object is accessible via the Project property containers. We can use a closure to configure the container with Configuration objects. Each Configuration object has at least a name, but we can change more properties. We can set a resolution strategy, if a configuration has version conflicts with dependencies, or we can change the visibility of a configuration so that it will not be visible outside of our project.

In the following example, we create a new configuration with the name commonsLib to hold our dependencies and a configuration mainLib that extends commonsLib. The extended configuration mainLib gets all settings and dependencies from commonsLib, and we can assign extra dependencies as well:

configurations {
    commonsLib {
        description = 'Common libraries'
    }
    mainLib {
        description = 'Main libraries'
        extendsFrom commonsLib
    }
}

println configurations['mainLib'].name
println configurations.commonsLib.name

The output of the build shows the names of the configurations:

$ gradle –q
commonsLib
mainLib

Many plugins add new configurations to ConfigurationContainer. We used the Java plugin in the previous chapter, which added four configurations to our project. With the built-in task dependencies, we can get an overview of defined dependencies and configurations for a project.

The following build script uses the Java plugin:

apply plugin: 'java'

We get the following output if we execute the dependencies task:

$ gradle –q dependencies

------------------------------------------------------------
Root project
------------------------------------------------------------

archives - Configuration for archive artifacts.
No dependencies

compile - Classpath for compiling the main sources.
No dependencies

default - Configuration for default artifacts.
No dependencies

runtime - Classpath for running the compiled main classes.
No dependencies

testCompile - Classpath for compiling the test sources.
No dependencies

testRuntime - Classpath for running the compiled test classes.
No dependencies

Notice how we already have six configurations in our project. The following table shows the configuration and which tasks use the configuration:

Configuration

Extends

Used by task

Description

compile

-

compileJava

Dependencies needed at compile time to compile the source files.

runtime

compile

-

Dependencies for runtime of the application, but not needed for compilation.

testCompile

compile

compileTestJava

Dependencies to compile test source files.

testRuntime

testCompile

test

All dependencies needed to run the tests.

archives

-

uploadArchives

Contains artifacts, such as JAR files created by the project.

default

runtime

-

Default configuration contains all runtime dependencies.

If our code has a dependency on a library, we can set the dependency with the compile configuration. The dependency is then automatically available in the runtime, testCompile, testRuntime, and default configurations.

..................Content has been hidden....................

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