Debugging Maven and Spring
I wanted to share an error I received with the following configuration
New application using
- Maven 2.0.4
- Eclipse 3.1.2
- Spring 2.0
- Spring-ldap 1.1
For a bunch of reasons - mainly because my company needed to standardize development lifecycle, release management and deployment - I need to use Maven 2.0.4.
I took the sample code included in the spring-ldap distribution, and created an Eclipse project. Using the Maven plugin for Eclipse. Everything would compile fine, but when I would run "mvn test" on the command line, I sporadically get this error:
Results :
[surefire] Tests run: 4, Failures: 0, Errors: 4
Error creating bean with name 'com.example.PersonDaoSpringLdapTest': Unsatisfied dependency expressed through bean property 'personDao': Set this property value or disable dependency checking for this bean.
Hmm, let me clean my Eclipse project and then run "mvn clean" and let's see what happens.
Results :
[surefire] Tests run: 4, Failures: 0, Errors: 0
Hmm. I didn't change anything. Anyway, I did some more coding and then ran the mvn test again:
Results :
[surefire] Tests run: 4, Failures: 0, Errors: 4
Error creating bean with name 'com.example.PersonDaoSpringLdapTest': Unsatisfied dependency expressed through bean property 'personDao': Set this property value or disable dependency checking for this bean.
Oh, c'mon now, what's going on! Being that there was a little lull at work and I was 100% on this project without being spread to thin on other projects, I dedicated an inordinate amount of time to debugging this - in total about 14 hours (ok, with email and lunch padding the time a little).
So I broke all the code down to the bare minimum and still got these errors. Back and forth, clean and test, I could never get a reproducible condition. Argh!!!! Google searches on the "Error creating..." message above never really revealed much.
Without bogging you down (as if I haven't already) with debugging details, here's what I found.
It hit me during a long walk that there is some class-loading conflict.
Using spring's AbstractDependencyInjectionSpringContextTests class for loading spring files, I was wondering whether maven was having a problem finding the file
protected String[] getConfigLocations() {
return new String[] {
"classpath:/**/applicationContext-springldap.xml"
};
}
Here are the conditions:
- If no file is found, you will not get an error saying "file not found", and instead will get the "Error creating bean..." error.
- If the file is found, everything should work
To alleviate this, try using more defined criteria for finding the file
protected String[] getConfigLocations() {
return new String[] {
"classpath:/com/example/applicationContext-springldap.xml"
};
}
Now, if the file is not found, you will get this (note, I intentionally renamed the file:
IOException parsing XML document from class path resource [comm/example/applicationContext-springldap.xml]; nested exception is java.io.FileNotFoundException: class path resource [comm/example/applicationContext-springldap.xml] cannot be opened because it does not exist
Ok, so I began to realize that Maven did something with "resources". After never getting very far with Maven (see many of my previous posts), I forgot that Maven used this src/main/resources directory to store configuration files like the Spring xml file.
Going back and using Clean in eclipse, then mvn clean, my tests again failed. Looking in target/classes, I realized that it was not finding my applicationContext-springldap.xml file.
I looked in the project properties under "build path" in eclipse and expected to see the default project/bin directory set up for classes. No! After enabling the project for Maven using the plugin, apparently it changes it from project/bin to project/test-classes. Argh! Ok, so I switched it to project/bin.
Now I've got the class loading separate between eclipse and maven so there should be no interference. In my src/main/java, I kept the applicationContext-springldap.xml amongst the java classes because well ... that's how example was packaged. For compilation, Eclipse brings this xml file to project/bin, but Maven doesn't.
In order for the Spring config file to be loaded, you need to put the Spring file in src/main/resources. And if you want to still use this:
protected String[] getConfigLocations() {
return new String[] {
"classpath:/com/example/applicationContext-springldap.xml"
};
}
Then your file needs to be in src/main/resources/com/example/applicationContext-springldap.xml.
After doing this, all is well. It turns out the error had nothing to do with Spring-Ldap, as I originally thought.
Sorry for being long-winded, but I wanted to give the error message some context, since context is the one thing I couldn't get in my builds or in any google searching.
