1 of 78

Sean Sullivan

Community Over Code

September 2025

Dependency Management

for Java applications

2 of 78

About me

Portland Oregon

Java since 1996

open source contributor

3 of 78

Outdated libraries

on your

production classpath

What is the worst

that could happen?

4 of 78

5 of 78

2017 US House committee

Equifax CEO

US Rep Greg Walden

6 of 78

2017 US House committee

US Rep Greg Walden

“the Apache Struts software

which contained the vulnerability

that led to this breach

was running

on the Equifax system”

7 of 78

Java

development

8 of 78

Java dependency

conflicts

9 of 78

Gradle blog

November 2019

“The larger the project and its dependency graph, the harder it is to maintain”

10 of 78

“Dependency issues

can cause

many problems”

Gradle blog

November 2019

11 of 78

“If you are lucky,

you would get a

compile time error”

Gradle blog

November 2019

12 of 78

“it is common to only see problems

occurring when executing tests

or even

at production runtime”

Gradle blog

November 2019

13 of 78

NoClassDefFoundError

ClassNotFoundException

14 of 78

NoSuchMethodError

UnsatisfiedLinkError

15 of 78

Let’s talk about dependency

resolution

16 of 78

dependencies {

implementation(“foo:liba:1.5.2”)

implementation(“foo:libz:0.2.1”)

implementation(“com.google.guava:guava:28.2”)

}

17 of 78

liba

1.5.2

app

1.0.0

libz

0.2.1

guava

19.0

guava

33.4.8

guava

28.2

18 of 78

liba

1.5.2

app

1.0.0

libz

0.2.1

guava

19.0

guava

33.4.8

guava

28.2

19 of 78

Maven:

“nearest wins”

Gradle:

“highest version wins”

guava

28.2

guava

33.4.8

20 of 78

Jake Wharton - March 2024

https://jakewharton.com/nonsensical-maven-is-still-a-gradle-problem/

21 of 78

“Maven’s dependency

resolution strategy

is objectively bonkers”

Jake Wharton - March 2024

https://jakewharton.com/nonsensical-maven-is-still-a-gradle-problem/

22 of 78

Java classpath

23 of 78

what Java libraries do you have

in production

right now?

24 of 78

do you have outdated libraries in production?

25 of 78

do you have SNAPSHOT libraries in production?

26 of 78

Microservice

app:1.5.2

sharedlib:1.8.3

swagger-annotations:2.2.31-SNAPSHOT

27 of 78

  • hundreds of libraries on the runtime classpath

  • open source libraries + internal libraries

  • Java, Kotlin, Scala

Modern Java applications

28 of 78

Let’s add one more Java library

Java library

29 of 78

30 of 78

Dependency Hell

31 of 78

Dependency Hell

is a

common problem

32 of 78

Dependency Hell

@ gilt.com (2015)

33 of 78

Dependency Hell

@ Netflix (2017)

34 of 78

Gradle’s optimistic dependency resolution may inadvertently upgrade dependencies, causing compatibility issues.

35 of 78

Taming dependency hell

36 of 78

Pin dependency

to a specific version?

37 of 78

configurations.all {

resolutionStrategy {

force 'com.example:foobar:0.9.2'

}

}

38 of 78

Mike McGarr

Netflix, 2017

39 of 78

Google JLBP

“Google Best Practices for Java Libraries are rules that minimize problems for consumers of interconnected Java libraries“

jlbp.dev

40 of 78

JLBP-1

Minimize Dependencies

“Scrutinize all dependency additions”

41 of 78

JLBP-1

Minimize Dependency Scope

“When you do add a dependency, keep it scoped as narrowly as possible”

42 of 78

JLBP-1

“Prefer JDK classes where available”

“For any given functionality, pick exactly one library”

43 of 78

JLBP-1

Separate the tool classpath from the product classpath

44 of 78

JLBP-11

Keep dependencies up to date

45 of 78

JLBP-11

“Release no later than 6 weeks after any of your dependencies releases a higher version”

46 of 78

JLBP-11

“Staying up to date is also important to ensure that security fixes are rolled out promptly”

47 of 78

JLBP-15

Publish a BOM for multi-module projects

48 of 78

JLBP-16

Ensure upper version alignment of dependencies for consumers

49 of 78

JLBP-16

“The version of each dependency added to the classpath should the highest version in the dependency tree”

50 of 78

Common problems

with Java dependencies

51 of 78

Compilation failure

[ERROR] bad class file: /Users/skywalker/.m2/repository/org/apache/iceberg/iceberg-api/1.9.2/iceberg-api-1.9.2.jar(org/apache/iceberg/IcebergBuild.class)

[ERROR] class file has wrong version 55.0, should be 52.0

52 of 78

class file has

wrong version 61.0,

should be 52.0

53 of 78

Dependency misalignment

jackson-databind:2.19.2

jackson-core:2.19.0

54 of 78

Scala sadness

jackson-module-scala_2.12-2.19.2.jar

jackson-module-scala_2.13-2.19.2.jar

🚩 what if both of these jars are on the classpath? 🚩

55 of 78

  • dependencyConvergence
  • requireUpperBoundDeps
  • banDuplicateClasses

Maven Enforcer plugin

56 of 78

Gradle Enforcer plugin

57 of 78

Gradle Enforcer plugin

✅ DependencyConvergence

58 of 78

Let’s talk about OpenRewrite

59 of 78

OpenRewrite recipes

  • AddDependency
  • RemoveDependency
  • ChangeDependency
  • UpgradeDependencyVersion

60 of 78

Final thoughts

61 of 78

  • Build often
  • Release often
  • Ownership
  • consider OpenRewrite for complex migrations

62 of 78

Questions?

63 of 78

The End

64 of 78

Bonus

65 of 78

Let’s talk about Netty

66 of 78

Netty dependencies

  • some Netty artifacts are platform dependent

  • use artifact classifiers

67 of 78

Example: artifact <classifier>

Linux x86

68 of 78

Linux ARM 64

Example: artifact <classifier>

69 of 78

Devnexus 2021

Taming Java Dependencies @ Google

Stephanie Wang

70 of 78

JConf 2022 : Dependency management

Roberto Perez Alcolea

71 of 78

David Handermann [ exceptionfactory.com ]

72 of 78

Let’s talk about JCenter

73 of 78

JCenter repository

end-of-life

74 of 78

75 of 78

“At the end of the sunset, all JCenter requests will automatically be redirected to Maven Central and served from there.”

76 of 78

Forcing gradle to check

for updated versions

./gradlew build --refresh-dependencies

77 of 78

78 of 78