How to create Runnable JAR using Maven?

08 April, 2016
Many times we need to create a runnable jar using maven. So that we can run the application as below.

java -jar MyApp.jar

This can be achieved using 2 different ways as far as I have learnt.
1.Using "maven-shade-plugin" Plugin of Maven
2.Using "maven-jar-plugin" Plugin of Maven



Using "maven-shade-plugin" Plugin of Maven


This might be the easiest way of creating a jar file of your java program. Simply add the following plugin to pom.xml.


<project>
  ...
  <build>
    <plugins>
      ...
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>2.3</version>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>shade</goal>
            </goals>
            <configuration>
              <transformers>
                <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                  <mainClass>com.xxx.sample.MyMainClass</mainClass>
                </transformer>
              </transformers>
            </configuration>
          </execution>
        </executions>
      </plugin>
      ...
    </plugins>
  </build>
  ...
</project>

Here we have to add the reference path of the class which contains the main method to the "mainClass" element in the xml.

We may encounter the following exception.
Exception in thread "main" java.lang.SecurityException: Invalid signature file digest for Manifest main attributes

The reason java.lang.SecurityException is raised is because some dependency jar files are signed jar files. A jar file is signed by using jarsigner, which creates 2 additional files and places them in META-INF:

      •a signature file, with a .SF extension, and
      •a signature block file, with a .DSA, .RSA, or .EC extension.

Since the uber-jar file is created, the signatures and integrity of signed JAR files are no longer valid. When the uber-jar file is executed, java.lang.SecurityException is thrown. " - maven shade plugin: Invalid signature file digest for Manifest main attributes


The solution is it add the filter. The below configuration filters all files in META-INF ending with .SF, .DSA, and .RSA for all artifacts (*:*) when creating uber-jar file.


<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>

To build the jar, run the following command...

mvn clean install

...and thats it, you get a shaded jar.


Using "maven-jar-plugin" Plugin of Maven


Using this way requires to use 2 maven plugins. After executing "mvn clean install", the target folder will contain the jar file and also a "lib" folder. The "lib" folder will contain all the dependencies. This way is more advantageous as the depending library files are available from outside of the jar. Later if we need to replace the dependency jar with a new version or so, this will become useful.

Add the following to the pom.xml.


<project> 
  ...
  <build> 
    <plugins> 
      ...
      <plugin> 
 <artifactId> maven-dependency-plugin</artifactId> 
 <executions> 
   <execution> 
     <phase> install</phase> 
     <goals> 
              <goal> copy-dependencies</goal> 
            </goals> 
            <configuration> 
       <outputDirectory> ${project.build.directory}/lib</outputDirectory> 
     </configuration> 
   </execution> 
 </executions> 
      </plugin> 
      <plugin> 
 <groupId> org.apache.maven.plugins</groupId> 
 <artifactId> maven-jar-plugin</artifactId> 
 <configuration> 
   <archive> 
            <manifest> 
       <addClasspath> true</addClasspath> 
       <useUniqueVersions> false</useUniqueVersions> 
       <classpathPrefix> lib/</classpathPrefix> 
       <mainClass> com.hemika.samples.Main</mainClass> 
            </manifest> 
          </archive> 
 </configuration> 
      </plugin> 
      ...
    </plugins> 
  </build> 
  ...
</project> 

The class that has the main method needs to be added at the "mainClass" node in the xml.

To build the jar, run the following command...

mvn clean install


...and thats it to create a runnable jar.

No comments:

Post a Comment