If you need to build a runnable spring-based JAR using maven, there could be some problems in the spring's configuration parsing. You know, to build a runnable JAR we have to include in the JAR all the dependencies, and Maven can help a lot in this, for example using the maven-assembly-plugin.
Here is a sample configuration of such plugin:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> <version>2.2-beta-5</version> <configuration> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> <archive> <manifest> <mainClass>fully.qualified.name.of.MainClass</mainClass> </manifest> </archive> </configuration> </plugin>
The plugin works well, but if you have more than the simple spring-core dependency, than you could have an Exception like:
Exception in thread "main" org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Unable to locate Spring NamespaceHandler for XML schema namespace [http://www.springframework.org/schema/security]
The problem is that spring uses in each module's JAR two meta files:
- META-INF/spring.handlers
- META-INF/spring.schemas
such files are used in conjuction with configurations' XML Schemas to validate the application configuration even if the application is executed off-line. Because each Spring module brings these files, when the assemply plugin runs, it simply overwrites multiple times such files in the META-INF/ directory of the resulting JAR.
As result, we have that some configurations can't be validated and so the BeanDefinitionParsingException is thrown.
To avoid the problem we can use the maven-shade-plugin that performs some transformations to the resulting JAR's files. Here is an example configuration:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>1.4</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>fully.qualified.name.of.MainClass</mainClass> </transformer> <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer"> <resource>META-INF/spring.handlers</resource> </transformer> <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer"> <resource>META-INF/spring.schemas</resource> </transformer> </transformers> </configuration> </execution> </executions> </plugin>
As you can see we are specifying something more than the MainClass: we are also saying that when spring.handlers and spring.schemas files are found, their contents must be appended to already existing files in the META-INF directory.
Running the maven package goal, we'll now get a working spring-based runnable JAR!