Skip to main content

Maven Mythbusters - Maven automatically updates for every build

Posted by johnsmart on January 6, 2010 at 11:36 PM PST

Maven seems to be one of those topics that brings out passion in many developers. Apparently, some developers love it, and find it a highly valuable and time-saving tool, whereas others hate it with a passion. (Of course there are still others who just want to get on with the job, but those ones usually keep quiet on the blogosphere). Every once in a while someone comes out with a blog entry explaining in more or less detail what they dislike so much about Maven. Sometimes these articles contain constructive criticism that allows Maven to evolve in the right direction. That's great. Sometimes they contain inaccuracies or misunderstandings about how Maven works. Sometimes they are just downright wrong. But they nevertheless represent a perception of Maven in parts of the Java community. So in this series of articles, I want to take a look at some of the common myths and ideas that circulate about Maven, and see how they stand up to the light of scientific examination.

Myth Number 1: Maven automatically checks for, and downloads, updates at every build

The first myth we will tackle involves Maven's network habits. Indeed, there seems to be a widely spread idea about Maven that it slows down your build with excessive network access. Here is quote from a recent blog entry illustrating and propagating this idea:

"Maven is broken and wrong if it thinks nothing of slowing down every build by connecting to the network and checking every dependency for any updates, and automatically downloading them"

Interesting. Indeed, it would be a grievous fault! Let's see how this idea stands up to the facts.

Actually, this idea is flat out wrong. In fact, Maven only checks for SNAPSHOT updates once a day by default, and even this is configurable. Maven 3 takes things even further: automatic updates will be turned off by default - you will have to explicitly ask for updates (using the -U option).

Maven doesn't need to check for core plugin updates at all - since Maven 2.0.9, the versions of the core plugins are bound to the version of Maven you are using, unless you explicitly tell it otherwise. So no updates here either.

However, like snapshots, Maven will check for plugin updates once a day if you don't provide a version of your plugin. So provide versions for your plugins, or accept the overhead of some network network access once every 24 hours. But it is recommended practice (and common sense, really) to specify the version number of any plugins you use in your build. If you do have explicit plugin version numbers for non-lifecycle plugins, it won't need to check for plugin updates either.

So in theory, this myth should be well and truly busted. However, true to MythBuster tradition, we'll check this hypothesis with a few tests. First, let's try with a simple multi-module project. To make things interesting, I've deleted a few directories from my local repository to force Maven to download some stuff initially:


$ mvn clean verify
[INFO] Scanning for projects...
[INFO] Reactor build order:
[INFO]   Tweeter
[INFO]   Tweeter domain model
[INFO]   Tweeter service layer
[INFO]   Tweeter web application
[INFO] ------------------------------------------------------------------------
[INFO] Building Tweeter
[INFO]    task-segment: [clean, verify]
[INFO] ------------------------------------------------------------------------
[INFO] [clean:clean {execution: default-clean}]
Downloading: http://localhost:8081/nexus/content/groups/public/org/easyb/easyb/
0.9.6...
downloaded  (easyb-0.9.6.pom)
Downloading: http://localhost:8081/nexus/content/groups/public/org/easyb/easyb/
0.9.6...
downloaded  (easyb-0.9.6.jar)
[INFO] [easyb:test {execution: default}]
...
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO] ------------------------------------------------------------------------
[INFO] Tweeter ............................................... SUCCESS [4.434s]
[INFO] Tweeter domain model .................................. SUCCESS [9.724s]
[INFO] Tweeter service layer ................................. SUCCESS [1.722s]
[INFO] Tweeter web application ............................... SUCCESS [30.865s]
[INFO] ------------------------------------------------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 47 seconds
[INFO] Finished at: Tue Jan 05 12:14:12 NZDT 2010
[INFO] Final Memory: 63M/123M
[INFO] ------------------------------------------------------------------------
2010-01-05 12:14:13.588::INFO:  Shutdown hook executing
2010-01-05 12:14:13.090:/tweeter-web:INFO:  Closing Spring root WebApplicationContext
2010-01-05 12:14:13.092::INFO:  Shutdown hook complete

That downloaded the easyb plugin because it didn't have it locally. Fair enough, that's what its supposed to do. To boot, it downloads dependencies in parallel when it can, so it's pretty fast. What Maven does downloads, it needs to build your application, and it does it only once. Not once per project, but once, period. But back to the subject in question: now let's rerun to see if it tries to download any updates.


$ mvn clean verify
[INFO] Scanning for projects...
[INFO] Reactor build order:
[INFO]   Tweeter
[INFO]   Tweeter domain model
[INFO]   Tweeter service layer
[INFO]   Tweeter web application
[INFO] ------------------------------------------------------------------------
[INFO] Building Tweeter
[INFO]    task-segment: [clean, verify]
[INFO] ------------------------------------------------------------------------
[INFO] [clean:clean {execution: default-clean}]
[INFO] Deleting directory /Users/johnsmart/Projects/wakaleo-training/tdd-traini
ng/lab-solutions/tweeter/target
[INFO] [easyb:test {execution: default}]
[INFO] /Users/johnsmart/Projects/wakaleo-training/tdd-training/lab-solutions/tw
eeter/src/test/easyb does not exists.  Skipping easyb testing
[INFO] [site:attach-descriptor {execution: default-attach-descriptor}]
[INFO] ------------------------------------------------------------------------
[INFO] Building Tweeter domain model
[INFO]    task-segment: [clean, verify]
[INFO] ------------------------------------------------------------------------
[INFO] [clean:clean {execution: default-clean}]
[INFO] Deleting directory /Users/johnsmart/Projects/wakaleo-training/tdd-traini
ng/lab-solutions/tweeter/tweeter-core/target
lures: 0, Errors: 0, Skipped: 0
...
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO] ------------------------------------------------------------------------
[INFO] Tweeter ............................................... SUCCESS [3.266s]
[INFO] Tweeter domain model .................................. SUCCESS [8.338s]
[INFO] Tweeter service layer ................................. SUCCESS [1.830s]
[INFO] Tweeter web application ............................... SUCCESS [20.185s]
[INFO] ------------------------------------------------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 34 seconds
[INFO] Finished at: Tue Jan 05 12:21:04 NZDT 2010
[INFO] Final Memory: 63M/123M
[INFO] ------------------------------------------------------------------------
2010-01-05 12:21:04.559::INFO:  Shutdown hook executing
2010-01-05 12:21:05.062:/tweeter-web:INFO:  Closing Spring root WebApplicationC
ontext
2010-01-05 12:21:05.064::INFO:  Shutdown hook complete

Nope, no downloads there. That went pretty well, but the example might have been a bit simple. So let's check this with a medium-size (around 32000 lines of code) real-world project (an old legacy one, to boot!):


$ mvn verify
[INFO] Scanning for projects...
[INFO] Reactor build order:
[INFO]   BNBGlobal parent module
[INFO]   BNBGlobal localization utilities
[INFO]   BNB Global Core Application
[INFO]   BNB Global Web Application
[INFO]   BNBGlobal aggregator module
[INFO] ------------------------------------------------------------------------
[INFO] Building BNBGlobal parent module
[INFO]    task-segment: [verify]
[INFO] ------------------------------------------------------------------------
[INFO] [enforcer:enforce {execution: enforce-java}]
[INFO] [site:attach-descriptor {execution: default-attach-descriptor}]
[INFO] Preparing source:jar
[WARNING] Removing: jar from forked lifecycle, to prevent recursive invocation.
[INFO] [enforcer:enforce {execution: enforce-java}]
[INFO] [source:jar {execution: default}]
[INFO] NOT adding sources to attached artifacts for packaging: 'pom'.
[INFO] ------------------------------------------------------------------------
[INFO] Building BNBGlobal localization utilities
[INFO]    task-segment: [verify]
[INFO] ------------------------------------------------------------------------
[INFO] [enforcer:enforce {execution: enforce-java}]
[INFO] [groovy:generateStubs {execution: default}]
[INFO]  No sources found for Java stub generation
[INFO] [resources:resources {execution: default-resources}]
[INFO] [compiler:compile {execution: default-compile}]
[INFO] Nothing to compile - all classes are up to date
[INFO] [groovy:compile {execution: default}]
[INFO]  No sources found to compile
[INFO] [groovy:generateTestStubs {execution: default}]
[INFO]  No sources found for Java stub generation
[INFO] [resources:testResources {execution: default-testResources}]
[INFO] Copying 24 resources
[INFO] [compiler:testCompile {execution: default-testCompile}]
[INFO] Nothing to compile - all classes are up to date
[INFO] [groovy:testCompile {execution: default}]
[INFO]  No sources found to compile
[INFO] [surefire:test {execution: default-test}]
[INFO] Surefire report directory: /Users/johnsmart/Projects/bnbglobal/bnbglobal
-l10n/target/surefire-reports

-------------------------------------------------------
T E S T S
-------------------------------------------------------
....
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO] ------------------------------------------------------------------------
[INFO] BNBGlobal parent module ............................... SUCCESS [3.378s]
[INFO] BNBGlobal localization utilities ...................... SUCCESS [15.495s]
[INFO] BNB Global Core Application ........................... SUCCESS [23.054s]
[INFO] BNB Global Web Application ............................ SUCCESS [26.336s]
[INFO] BNBGlobal aggregator module ........................... SUCCESS [0.112s]
[INFO] ------------------------------------------------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1 minute 9 seconds
[INFO] Finished at: Wed Jan 06 16:22:07 NZDT 2010
[INFO] Final Memory: 92M/179M
[INFO] ------------------------------------------------------------------------

Hmmm, no updates in sight there either. Just to make sure that my local repository manager wasn't interfering with the process, somehow, I also ran the same tests with no settings.xml in my .m2 directory, with (wait for it!) exactly the same result! So it looks like this one is well and truly busted - Maven does not check for updates, for SNAPSHOT dependencies, for plugins or for anything else, for each build. At most it checks for SNAPSHOT updates once a day. It checks for unversioned plugins once a day, and not at all for versioned plugins (a best practice). And in Maven 3, it only checks for updates if you explicitly ask it to.

Next time we'll take a look at another Maven Myth: Maven requires an internet connection to delete a directory.

(The title and some of the images of this blog were of course shamelessly stolen from the great and highly scientific MythBusters TV series.)

Related Topics >>