← Back to Advanced Java Course | Chapter 12: Build Tools | Lesson 4 of 5

Java Dependency Management

Dependency management covers declaring direct dependencies, understanding the transitive ones they pull in, controlling their scope, and resolving version conflicts between competing requirements.

What is a Dependency?

A dependency is an external library a project needs to compile or run, declared in the build file with coordinates identifying exactly which library and version to download from a repository like Maven Central.

Example: What is a Dependency?

java
public class Main {
	public static void main(String[] args) {
		String coordinates = "com.google.guava:guava:32.1.0"; // groupId:artifactId:version
		System.out.println(coordinates);
	}
}

Direct vs Transitive Dependencies

A direct dependency is one explicitly listed in the build file, while a transitive dependency is one pulled in automatically because a direct dependency itself depends on it, often resulting in far more libraries on the classpath than were ever directly declared.

Example: Direct vs Transitive Dependencies

java
public class Main {
	public static void main(String[] args) {
		String direct = "junit:junit:4.13"; // explicitly listed
		String transitive = "hamcrest-core"; // pulled in automatically because junit depends on it
		System.out.println(direct + " brings in " + transitive);
	}
}

Dependency Scopes

Dependency scopes control when and where a dependency is available -- compile scope is available everywhere, test scope only during testing, and provided scope assumes the runtime environment already supplies the library.

Example: Dependency Scopes

java
public class Main {
	public static void main(String[] args) {
		String compileScope = "compile"; // available everywhere
		String testScope = "test"; // only during testing
		String providedScope = "provided"; // runtime environment already supplies it
		System.out.println(compileScope + " " + testScope + " " + providedScope);
	}
}

Resolving Version Conflicts

Version conflicts happen when two dependencies transitively require different versions of the same library, and build tools resolve this automatically using rules like nearest-wins, though dependencyManagement can pin an exact version explicitly.

Example: Resolving Version Conflicts

java
public class Main {
	public static void main(String[] args) {
		String pinned = "<dependencyManagement>...<version>2.0</version></dependencyManagement>"; // pins the exact version
		System.out.println(pinned);
	}
}

Excluding Dependencies

A transitive dependency can sometimes be undesirable, such as an unwanted embedded server or a conflicting logging library, and both Maven and Gradle support explicitly excluding specific transitive dependencies from a declared dependency.

Example: Excluding Dependencies

java
public class Main {
	public static void main(String[] args) {
		String exclusion = "<exclusions><exclusion><artifactId>unwanted-logger</artifactId></exclusion></exclusions>";
		System.out.println(exclusion);
	}
}
🔒

Chapter Quiz — Complete all 5 topics to unlock

0/5 topics done

Complete these topics first:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.