Maven has been the default Java build tool since 2004. It downloads dependencies for you and makes every project look the same, which is boring but useful when you're switching between codebases. Every Java shop uses the same directory structure, so you always know where to find shit.
The pom.xml File (Your New Best Friend and Worst Enemy)
Everything in Maven revolves around the pom.xml file - an XML configuration that tells Maven what your project is and how to build it. This file contains:
- Project coordinates: GroupId, ArtifactId, and Version (the holy trinity of Maven)
- Dependencies: All the libraries you need (and their transitive dependencies you don't want)
- Build settings: Plugins that actually do the work
- Random metadata: That nobody reads but Maven requires anyway
The pom.xml approach means you describe what you want instead of writing build scripts. When it works, it's fine. When it breaks, you'll be staring at XML trying to figure out what went wrong. The POM reference docs help when things break, and Sonatype's guide covers publishing requirements.
Standard Project Layout (Finally, Some Sanity)
Maven enforces a standard directory layout that every Java project follows. No more guessing where the source code lives:
src/main/java/ # Your actual Java code lives here
src/main/resources/ # Config files, properties, anything non-Java
src/test/java/ # Unit tests (that you definitely write, right?)
src/test/resources/ # Test config files
target/ # Maven dumps all generated stuff here
This structure is the same across every Maven project. Walk into any Java shop and you'll immediately know where everything is. It's boring but incredibly useful when you're not the one who wrote the project.
Build Phases (The Magic Incantations)
Maven has three build lifecycles, but you'll mainly care about one:
- Default lifecycle: Compiles, tests, and packages your code
- Clean lifecycle: Deletes the target directory when things get weird
- Site lifecycle: Generates docs that nobody reads
The default lifecycle has phases like validate
, compile
, test
, package
, verify
, install
, and deploy
. Run mvn package
and Maven automatically runs compile and test first. It's actually pretty smart about dependencies between phases, though it will happily run tests that take 20 minutes every time you want to create a JAR.
Dependency Management (When It Works)
Maven's dependency management system handles the nightmare of JAR file management. Maven automatically:
- Resolves transitive dependencies: Downloads all required libraries, including their dependencies
- Manages version conflicts: Uses dependency mediation to resolve version conflicts
- Handles different scopes: Supports compile, test, runtime, and provided scopes
- Integrates with repositories: Connects to Maven Central and other repositories with basically everything you'll ever need
This works great until you hit dependency hell - when two libraries need different versions of the same thing and Maven picks the wrong one. You'll end up running mvn dependency:tree
and staring at 47 different versions of slf4j wondering why your app won't start. Maven caches everything in ~/.m2/repository
which grows to several GB and occasionally corrupts, forcing you to delete it and re-download everything.
Common dependency problems that will ruin your day:
- Jackson conflicts: Spring Boot 3.1.5 brings Jackson 2.15.2, your legacy library needs 2.12.1, runtime fails with
NoSuchMethodError
- Logging nightmares: slf4j-api 1.7.36, logback-classic 1.4.14, log4j-core 2.19.0, and commons-logging 1.2 all fighting each other until nothing logs
- Version mismatches: Library A wants Guava 31.1-jre, library B wants Guava 28.2-android, Maven picks 30.1.1-jre and breaks both
- Transitive bloat: Add
spring-boot-starter-web
, suddenly you have 47 dependencies including 3 different JSON parsers and a YAML library you never asked for
When dependencies break, use `dependency:tree` to see what's happening, `dependency:analyze` to find unused libraries, and the versions plugin to update everything. Baeldung's dependency guide explains how to exclude transitive dependencies.
Why Everyone Still Uses Maven
Maven is everywhere in enterprise Java because it's been around since 2004 and changing build tools is career suicide. I've watched three separate teams burn 6 months trying to migrate to Gradle - first team gave up when their CI randomly started failing with "Gradle daemon disappeared" errors, second couldn't get the Spring Boot plugin working with their custom deployment scripts, third one reverted after the gradle daemon started eating 4GB of RAM during builds and Jenkins started killing processes.
Your IDE already knows Maven. Your deployment scripts know Maven. That contractor who left 2 years ago wrote everything assuming Maven. The inertia is real.
Enterprises love Maven because it's boring and predictable. Your project will build exactly the same way in 5 years, assuming Oracle doesn't change their licensing again and your company doesn't decide to "go cloud native" and rewrite everything in Go.
Maven 4 (Coming Any Decade Now)
The Maven team has been working on Maven 4.0 since Java 8 was considered "modern". It's been in RC phase longer than some developers have been alive. Promises include:
- Better performance: 20% faster builds (we'll see)
- Improved BOM support: Because managing 200 versions manually wasn't fun enough
- Java 17+ requirement: Finally dropping Java 8 support, only 5 years after everyone else
- Consumer POM: Cleaner dependency declarations that will break existing tooling
Maven 4 claims backward compatibility with Maven 3, but we all know how that goes. Half your plugins will break, the other half will just stop working for mysterious reasons.
Will it ship this year? Maybe. Will your company upgrade within 3 years of release? Probably not. Enterprise Java shops are still running Maven 3.6.3 from 2019 and complaining about "stability".