32

I have a Maven based Spring-WS client project that I want to package as a single jar. In eclipse, everything runs properly. When I try to package it as an executable jar, I get ClassNotFound exceptions since the Spring jars are not included in my application jar.

So I added the maven-shade-plugin to include all my dependencies in my application jar. When I look at my app jar, I see all the class files from all the dependencies included (all the library jar's are exploded).

<build>
    <plugins>
        <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <source>1.6</source>
                <target>1.6</target>
            </configuration>
        </plugin>

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>2.4</version>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                        <mainClass>com.cws.cs.Client</mainClass>
                    </manifest>
                </archive>
            </configuration>
        </plugin>

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>1.7</version>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                </execution>
            </executions>

        </plugin>
    </plugins>
</build>

My problem is that in the packaging process, my multiple spring dependencies have different META-INF/spring.schemas files that override each other. Consequently, my final jar has an incomplete spring.schemas file.

So when I try to run my executable jar, I get Spring error messages that files cannot be found since the spring.schemas file is incomplete (the Spring-WS's jar has overriden the Spring-core's spring.schemas file).

My executable jar's META-INF/spring.schemas:

http\://www.springframework.org/schema/web-services/web-services-1.5.xsd=/org/springframework/ws/config/web-services-1.5.xsd
http\://www.springframework.org/schema/web-services/web-services-2.0.xsd=/org/springframework/ws/config/web-services-2.0.xsd
http\://www.springframework.org/schema/web-services/web-services.xsd=/org/springframework/ws/config/web-services-2.0.xsd

Instead of Spring-beans.jar META-INF/spring.schemas:

http\://www.springframework.org/schema/beans/spring-beans-2.0.xsd=org/springframework/beans/factory/xml/spring-beans-2.0.xsd
http\://www.springframework.org/schema/beans/spring-beans-2.5.xsd=org/springframework/beans/factory/xml/spring-beans-2.5.xsd
http\://www.springframework.org/schema/beans/spring-beans-3.0.xsd=org/springframework/beans/factory/xml/spring-beans-3.0.xsd
http\://www.springframework.org/schema/beans/spring-beans-3.1.xsd=org/springframework/beans/factory/xml/spring-beans-3.1.xsd
http\://www.springframework.org/schema/beans/spring-beans.xsd=org/springframework/beans/factory/xml/spring-beans-3.1.xsd
http\://www.springframework.org/schema/tool/spring-tool-2.0.xsd=org/springframework/beans/factory/xml/spring-tool-2.0.xsd
http\://www.springframework.org/schema/tool/spring-tool-2.5.xsd=org/springframework/beans/factory/xml/spring-tool-2.5.xsd
http\://www.springframework.org/schema/tool/spring-tool-3.0.xsd=org/springframework/beans/factory/xml/spring-tool-3.0.xsd
http\://www.springframework.org/schema/tool/spring-tool-3.1.xsd=org/springframework/beans/factory/xml/spring-tool-3.1.xsd
http\://www.springframework.org/schema/tool/spring-tool.xsd=org/springframework/beans/factory/xml/spring-tool-3.1.xsd
http\://www.springframework.org/schema/util/spring-util-2.0.xsd=org/springframework/beans/factory/xml/spring-util-2.0.xsd
http\://www.springframework.org/schema/util/spring-util-2.5.xsd=org/springframework/beans/factory/xml/spring-util-2.5.xsd
http\://www.springframework.org/schema/util/spring-util-3.0.xsd=org/springframework/beans/factory/xml/spring-util-3.0.xsd
http\://www.springframework.org/schema/util/spring-util-3.1.xsd=org/springframework/beans/factory/xml/spring-util-3.1.xsd
http\://www.springframework.org/schema/util/spring-util.xsd=org/springframework/beans/factory/xml/spring-util-3.1.xsd

I'm stumped. I am not sure if/how I can package everything as a single executable jar. I don't know if this is a shade-plugin configuration issue, or if I am trying to do something impossible. It would not seem correct that I would have to manually create my own spring.schemas file (a concatenation of the others).

I may have jumped the gun a little. In digging up more info on the shade plugin, I noticed the AppendingTransformer that I had previously missed. However, my concern is how to know which other files are having the same problems? I've discovered/caught this particular Spring issue. I have no idea about any other libraries that may be doing something similar...

Any suggestions would be appreciated.

Eric B.
  • 23,425
  • 50
  • 169
  • 316
  • Alternative approach which works great is to place Spring jars into separate lib folder, and add this `lib` folder into class path in manifest - see André Aronsen's answer http://stackoverflow.com/a/4323501/241986 – Boris Treukhov May 09 '15 at 18:48

7 Answers7

63

You can add the following configuration so that the contents of the .schema files from all the jars get appended together.

<configuration>
  <transformers>
    <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>
gkamal
  • 20,777
  • 4
  • 60
  • 57
  • 1
    Thanks - I saw the same thing and had just edited my question to include that info. My question/problem is how to know if there are any other libraries that can be experiencing similar problems? I can't be expected to know the contents of all META-INF folders for all libs that I use... – Eric B. Jun 22 '12 at 16:50
  • There is probably no way of figuring out by analysis. The only practical option is to perform some tests, make sure it works and fix anything that is broken. – gkamal Jun 23 '12 at 13:14
  • @gkamal what does it means `get appended together` aren't files with same filename override each other when packed in a `jar`? how could different files with same name not collide in jar? – Jas Feb 10 '15 at 12:44
  • 1
    @Jas - the maven shade plugin appends the files together if the above configuration is added. – gkamal Apr 02 '15 at 07:37
7

Instead of maven-shade-plugin use onejar-maven-plugin. One-JAR lets you package a Java application together with its dependency Jars into a single executable Jar file.

amra
  • 16,125
  • 7
  • 50
  • 47
  • 3
    My problem with the one-jar plugin is that it creates a second jar in the target folder with one-jar.jar extension. Consequently, when I try to deploy the artifact, it deploys the original jar and not the one-jar. Do you know if there is a proper way to configure the pom to avoid this issue? – Eric B. Jun 26 '12 at 14:24
  • `one-jar` is a default classifier added by one-jar plugin. See http://onejar-maven-plugin.googlecode.com/svn/mavensite/usage.html Configure deployment to use that classifier http://stackoverflow.com/questions/9743574/maven-how-to-install-a-jar-with-a-classifier-and-not-install-the-default-one – amra Jun 27 '12 at 09:50
5

Yesterday I was encountered this issue too.

The solution was to prepare required files by manual concatenation and configuration of assembly plugin by this:

  <files>
    <file>
        <source>src/META-INF/spring.schemas</source>
        <outputDirectory>META-INF</outputDirectory>
    </file>
    <file>
        <source>src/META-INF/spring.handlers</source>
        <outputDirectory>META-INF</outputDirectory>
    </file>
  </files>
  <dependencySets>
    <dependencySet>
      <outputDirectory>/</outputDirectory>
      <useProjectArtifact>true</useProjectArtifact>
      <unpack>true</unpack>
      <scope>runtime</scope>
      <unpackOptions>
        <excludes>
            <exclude>META-INF/spring.handlers</exclude>
            <exclude>META-INF/spring.schemas</exclude>
        </excludes>
      </unpackOptions>  
    </dependencySet>
  </dependencySets>

NOTE: using one jar approach is not good enough - you can't be certain on hand mixed files, try to keep exporting of all dependence's as is...

Mikhail Tsaplin
  • 642
  • 1
  • 9
  • 21
3
assembly plugin have issues, use below plugin

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>shade</goal>
            </goals>
            <configuration>
                <transformers>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                        <mainClass>at.seresunit.lecturemanager_connector.App</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>

you may get security exception resolve it using below configuration

 <configuration>
    <filters>
        <filter>
            <artifact>*:*</artifact>
            <excludes>
                <exclude>META-INF/*.SF</exclude>
                <exclude>META-INF/*.DSA</exclude>
                <exclude>META-INF/*.RSA</exclude>
            </excludes>
        </filter>
    </filters>
</configuration>
Aamir
  • 655
  • 1
  • 8
  • 27
2

Have you tried the maven-assembly-plugin ?

It will create a single jar with dependencies for you and morevover it can make this jar be executable :

Use mainClass to specify the class you want to execute.

<plugin>
    <artifactId>maven-assembly-plugin</artifactId>
    <version>2.3</version>
    <configuration>
      <descriptorRefs>
        <descriptorRef>jar-with-dependencies</descriptorRef>
      </descriptorRefs>
      <archive>
        <manifest>
          <mainClass>org.sample.App</mainClass>
        </manifest>
      </archive>
    </configuration>
    <executions>
      <execution>
        <id>make-assembly</id> <!-- this is used for inheritance merges -->
        <phase>package</phase> <!-- bind to the packaging phase -->
        <goals>
          <goal>single</goal>
        </goals>
      </execution>
    </executions>
  </plugin>
Jean-Philippe Briend
  • 3,455
  • 29
  • 41
  • 3
    Shade and assembly plugins are the same concept. They will both explode the dependencies and try to include them in the same area. Both run into problems when multiple dependencies have files in the same path (ex: META-INF/spring.schemas) – Eric B. Jun 26 '12 at 19:08
1

For people who were hoping to find an answer for Spring Boot applications, all you need is:

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>
Koray Tugay
  • 22,894
  • 45
  • 188
  • 319
0

I had the exact same problem after upgrading to Spring 6.0.0. My project has an assembly xml, and I fixed the spring.schemas and spring.handlers problem by adding the following handler to the <assembly> section:

<containerDescriptorHandlers>
    <containerDescriptorHandler>
        <handlerName>metaInf-spring</handlerName>
    </containerDescriptorHandler>
</containerDescriptorHandlers>

This is documented in https://maven.apache.org/plugins/maven-assembly-plugin/examples/single/using-container-descriptor-handlers.html

Sol Q.
  • 1