In one of my previous post I wrote that using development frameworks pays off and it is generally worth investing your time in learning how to use them. I was also clear that learning process is not easy and you could lose some hair from your head or simply go mad.
I would like to present an example how easily you can get lost using Spring Framework together with Struts 2 and Maven. The problem I'm going to present is often referred as a JAR Hell. I will present ideas how to cope with that.
In the following paragraphs I'm going to present libraries dependency problems I encountered integrating Spring Framework with Struts2. I will also present how I discovered what the real problem is and how I solved it.
In one of my projects I use Spring integration with Struts2. In order to use this integration I have to add following dependency to pom.xml:
dependencyentries with one (full Spring package with all components - it's about 2.8 MB):
Here is my full pom.xml I'm using in the example.
I built the project and my tests were OK - I was happy. Unfortunately when I started developing next feature I created new Spring-based unit test i.e. (please refer to Spring documentation for details):
That's pretty strange one :) And the whole build process was OK when launched by Maven!
I checked the Spring Forum and I found what causes this problem: So basically, just make sure you are using spring.jar and spring-test.jar from 2.5 RC1, and that should do the trick.
But Hey! I'm using Spring 2.5.5! WTF? After some brainstorming with myself I checked my project's build path and I found something strange - in my classpath there were Spring libraries spring-beans, spring-core, etc. with version 2.0.5 (yes - spring-2.5.5.jar was also there). It took me some time and brain-effort to identify my enemy. I checked struts2-spring-plugin POM. Everything became clear - this plugin imported Spring JARs in different versions than those I needed.
There are two solutions to this problem.
First one is to define Spring dependencies as separate modules i.e. this way. Maven will not import old JARs because you explicitly define which version you want.
Disadvantage of this solution is that you will have to know which components are used in runtime by your system - it's not always obvious at the beginning and you will have to understand many runtime exceptions before you get the correct dependency configuration. It's also possible that you will not set dependency for all Spring modules imported by Struts2 and in your classpath you will have almost all JARs with version let's say 2.5.5 but still some Spring modules will be imported with version 2.0.1.
The other one
The second solution is to define Spring dependency this way. With this solution you have to exclude problematic dependencies from
This way you tell Maven that you only want
struts2-spring-plugin and you don't need it's dependencies to be resolved automatically.
I think I don't have to describe disadvantages of this solution - anyway this is my preferred way of doing this.
I'm not going to throw away Spring and Struts2 integration because I have some problems with it. OK - I lost some significant amount of time on investigation the problem and finding the solution but I now know that I have to careful with Maven2 dependencies. Even if you depend on some concrete version of some framework Maven will automatically download and add missing dependencies. The problem is that it can make real mess in your classpath adding unnecessary JARs and it will be difficult to find the problem occurring in runtime.
The truth is that even with tools that manage software dependencies for you you may encounter some problems like the one I described. Managing dependencies is hard and I have no simple answer how to do it right at once. When you develop Java project you should use Maven-like tool but it still is not perfect (and probably will never be). The good idea in general is to version libraries you use (JARs, DLLs, whatever) and to put the used version in the file name (Maven does that automatically).
It's not very helpful tip but you should be careful :) and most of the time know what dependencies will be included with the next library you're going to use. You have to check for possible conflicts and resolve them by removing unnecessary dependencies.
I know it doesn't help much but that's the way it is - dependency management is hard. Full stop.