Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Better Dependency Management for Gradle

DZone's Guide to

Better Dependency Management for Gradle

· Java Zone
Free Resource

Are you joining the containers revolution? Start leveraging container management using Platform9's ultimate guide to Kubernetes deployment.

Written by Andy Wilkinson, on the Spring blog

Maven’s dependency management includes the concept of a bill-of-materials (bom). A bom is a special kind of pom that is used to control the versions of a project’s dependencies and provides a central place to define and update those versions.

A number of Spring projects including Spring Framework, Spring Cloud, Spring Boot, and the Spring IO Platform provide boms to make things easier for Maven users. Unfortunately, things haven’t been quite so easy if you’re using Gradle.

Dependency management in Gradle

Gradle’s dependency management uses a ResolutionStrategy to take control of a project’s dependency versions. This offers a lot of power and flexibility but doesn’t provide a way to reuse the dependency management that’s already been declared in a Maven bom. As a result, you have to do so manually. Depending on the bom, this can easily equate to tens of additional lines in your build.gradle script just to reuse some existing configuration.

Reusing a bom in Gradle

One of Gradle’s key strengths is that it can be easily extended and its behaviour customized through the use of plugins. We’ve taken advantage of this and written adependency management plugin for Gradle. This plugin allows you to use a Maven bom to control your build’s dependencies in a handful of lines:

plugins {
    id "io.spring.dependency-management" version "0.4.0.RELEASE"
}

dependencyManagement {
     imports {
          mavenBom 'io.spring.platform:platform-bom:1.1.1.RELEASE'
     }
}

With this configuration in place you can declare dependencies on anything in the bom without specifying a version:

dependencies {
    compile 'org.springframework:spring-core'
}

The imported bom will control the version of the dependency. It will also control the version of its transitive dependencies if they’re listed in the bom.

Exclusions in Gradle

Gradle can retrieve dependencies from a Maven repository and it uses the metadata in Maven pom files to do so. However, rather than obeying Maven’s rules, it applies its own, subtly different semantics to the metadata. One area where this can cause problems is with the exclusion of transitive dependencies. This is best illustrated with a simple example.

Imagine a module that depends on a couple of Spring Framework modules,spring-core and spring-beans, and that uses SLF4J rather than Commons Logging. The dependencies in its pom would look something like this:

<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-core</artifactId>
	<version>4.1.4.RELEASE</version>
	<exclusions>
		<exclusion>
			<groupId>commons-logging</groupId>
			<artifactId>commons-logging</artifactId>
		</exclusion>
	</exclusions>
</dependency>
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-beans</artifactId>
	<version>4.1.4.RELEASE</version>
</dependency>
<dependency>
	<groupId>org.slf4j</groupId>
	<artifactId>jcl-over-slf4j</artifactId>
	<version>1.7.10</version>
</dependency>

If a Maven build depends on this module its dependency tree will look like this:

\- com.example:my-library:jar:0.0.1-SNAPSHOT:compile
   +- org.springframework:spring-core:jar:4.1.4.RELEASE:compile
   +- org.springframework:spring-beans:jar:4.1.4.RELEASE:compile
   \- org.slf4j:jcl-over-slf4j:jar:1.7.10:compile
      \- org.slf4j:slf4j-api:jar:1.7.10:compile

commons-logging isn’t listed as the only module that depends upon it isspring-core where it has been excluded.

The dependency tree of the equivalent Gradle build looks like this:

\--- com.example:my-library:0.0.1-SNAPSHOT
     +--- org.springframework:spring-core:4.1.4.RELEASE
     |    \--- commons-logging:commons-logging:1.2
     +--- org.springframework:spring-beans:4.1.4.RELEASE
     |    \--- org.springframework:spring-core:4.1.4.RELEASE (*)
     \--- org.slf4j:jcl-over-slf4j:1.7.10
          \--- org.slf4j:slf4j-api:1.7.10

Despite the exclusion, commons-logging is listed this time. This can be problematic as it leaves your classpath polluted with dependencies that should not be there. You can work around the problem by manually configuring the required exclusions in your Gradle build, but first of all you have to know what the exclusions should be, and then you have to go through the tedious and error-prone process of configuring them.

Honoring a pom’s exclusions

The dependency management plugin changes Gradle’s handling of a pom’s exclusions so that they behave as they do in Maven. With the plugin applied to the example project, it no longer pulls in commons-logging:

\--- com.example:my-library:0.0.1-SNAPSHOT
     +--- org.springframework:spring-core:4.1.4.RELEASE
     +--- org.springframework:spring-beans:4.1.4.RELEASE
     |    \--- org.springframework:spring-core:4.1.4.RELEASE
     \--- org.slf4j:jcl-over-slf4j:1.7.10
          \--- org.slf4j:slf4j-api:1.7.10

Learning more

In addition to the features described above, the plugin has support for working with a bom’s properties (both overriding them and using them in your Gradle build), automatically including dependency management metadata in Gradle-generated pom files, and more. Take a look at the README for further details.

The plugin is Apache-licensed and is on GitHub. GitHub’s also used for issue tracking. Feature suggestions, pull requests, and bug reports are always welcome.

Using Containers? Read our Kubernetes Comparison eBook to learn the positives and negatives of Kubernetes, Mesos, Docker Swarm and EC2 Container Services.

Topics:

Published at DZone with permission of Pieter Humphrey, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}