Maven by Example - 8.5. Optimizing with the Maven Dependency Plugin |
|
On larger projects, additional dependencies often tend to creep into a POM as the number of dependencies grow. As dependencies change, you are often left with dependencies that are not being used, and just as often, you may forget to declare explicit dependencies for libraries you require. Because Maven 2.x includes transitive dependencies in the compile scope, your project may compile properly but fail to run in production. Consider a case where a project uses classes from a widely used project such as Jakarta Commons BeanUtils. Instead of declaring an explicit dependency on BeanUtils, your project simply relies on a project like Hibernate that references BeanUtils as a transitive dependency. Your project may compile successfully and run just fine, but if you upgrade to a new version of Hibernate that doesn’t depend on BeanUtils, you’ll start to get compile and runtime errors, and it won’t be immediately obvious why your project stopped compiling. Also, because you haven’t explicitly listed a dependency version, Maven cannot resolve any version conflicts that may arise. A good rule of thumb in Maven is to always declare explicit dependencies for classes referenced in your code. If you are going to be importing Commons BeanUtils classes, you should also be declaring a direct dependency on Commons BeanUtils. Fortunately, via bytecode analysis, the Maven Dependency plugin is able to assist you in uncovering direct references to dependencies. Using the updated POMs we previously optimized, let’s look to see if any errors pop up: $ mvn dependency:analyze [INFO] Scanning for projects... [INFO] Reactor build order: [INFO] Chapter 8 Simple Parent Project [INFO] Chapter 8 Simple Object Model [INFO] Chapter 8 Simple Weather API [INFO] Chapter 8 Simple Persistence API [INFO] Chapter 8 Simple Command Line Tool [INFO] Chapter 8 Simple Web Application [INFO] Chapter 8 Parent Project [INFO] Searching repository for plugin with prefix: 'dependency'. ... [INFO] ----------------------------------------------------- [INFO] Building Chapter 8 Simple Object Model [INFO]task-segment: [dependency:analyze] [INFO] ----------------------------------------------------- [INFO] Preparing dependency:analyze [INFO] [resources:resources] [INFO] Using default encoding to copy filtered resources. [INFO] [compiler:compile] [INFO] Nothing to compile - all classes are up to date [INFO] [resources:testResources] [INFO] Using default encoding to copy filtered resources. [INFO] [compiler:testCompile] [INFO] Nothing to compile - all classes are up to date [INFO] [dependency:analyze] [WARNING] Used undeclared dependencies found: [WARNING]javax.persistence:persistence-api:jar:1.0:compile [WARNING] Unused declared dependencies found: [WARNING]org.hibernate:hibernate-annotations:jar:3.3.0.ga:compile [WARNING]org.hibernate:hibernate:jar:3.2.5.ga:compile [WARNING]junit:junit:jar:3.8.1:test ... [INFO] ----------------------------------------------------- [INFO] Building Chapter 8 Simple Web Application [INFO]task-segment: [dependency:analyze] [INFO] ----------------------------------------------------- [INFO] Preparing dependency:analyze [INFO] [resources:resources] [INFO] Using default encoding to copy filtered resources. [INFO] [compiler:compile] [INFO] Nothing to compile - all classes are up to date [INFO] [resources:testResources] [INFO] Using default encoding to copy filtered resources. [INFO] [compiler:testCompile] [INFO] No sources to compile [INFO] [dependency:analyze] [WARNING] Used undeclared dependencies found: [WARNING]org.sonatype.mavenbook.optimize:simple-model:jar:1.0:compile [WARNING] Unused declared dependencies found: [WARNING]org.apache.velocity:velocity:jar:1.5:compile [WARNING]javax.servlet:jstl:jar:1.1.2:compile [WARNING]taglibs:standard:jar:1.1.2:compile [WARNING]junit:junit:jar:3.8.1:test In the truncated output just shown, you can see the output of the
$ mvn dependency:tree [INFO] Scanning for projects... [INFO] Searching repository for plugin with prefix: 'dependency'. [INFO] ----------------------------------------------------- [INFO] Building Chapter 8 Simple Object Model [INFO]task-segment: [dependency:tree] [INFO] ----------------------------------------------------- [INFO] [dependency:tree] [INFO] org.sonatype.mavenbook.optimize:simple-model:jar:1.0 [INFO] +- org.hibernate:hibernate-annotations:jar:3.3.0.ga:compile [INFO] | \- javax.persistence:persistence-api:jar:1.0:compile [INFO] +- org.hibernate:hibernate:jar:3.2.5.ga:compile [INFO] | +- net.sf.ehcache:ehcache:jar:1.2.3:compile [INFO] | +- commons-logging:commons-logging:jar:1.0.4:compile [INFO] | +- asm:asm-attrs:jar:1.5.3:compile [INFO] | +- dom4j:dom4j:jar:1.6.1:compile [INFO] | +- antlr:antlr:jar:2.7.6:compile [INFO] | +- cglib:cglib:jar:2.1_3:compile [INFO] | +- asm:asm:jar:1.5.3:compile [INFO] | \- commons-collections:commons-collections:jar:2.1.1:compile [INFO] \- junit:junit:jar:3.8.1:test [INFO] ----------------------------------------------------- [INFO] BUILD SUCCESSFUL [INFO] ----------------------------------------------------- From this output, we can see that the If you look at the How did the Maven Dependency plugin uncover these issues? How does
In contrast, the list of unused, declared dependencies is a little
trickier to validate, and less useful than the “used, undeclared
dependencies.” For one, some dependencies are used only at runtime or
for tests, and they won’t be found in the bytecode. These are pretty
obvious when you see them in the output; for example, JUnit appears in
this list, but this is expected because it is used only for unit
tests. You’ll also notice that the Velocity and Servlet API
dependencies are listed in this list for the Be careful when removing any unused, declared dependencies unless you have very good test coverage, or you might introduce a runtime error. A more sinister issue pops up with bytecode optimization. For example, it is legal for a compiler to substitute the value of a constant and optimize away the reference. Removing this dependency will cause the compile to fail, yet the tool shows it as unused. Future versions of the Maven Dependency plugin will provide better techniques for detecting and/or ignoring these types of issues. You should use the |