Search code examples
javamavenjarclassnotfoundexception

How to produce an executable jar file with all maven dependencies?


I have a maven project and I would like to produce the jar file with all dependencies. I use package shade plugin and the command mvn package to produce the jar file.

However, the produced jar file does not consider any of the dependencies that is pom.xml. The produced jar file keep give me exception:

Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/log4j/Level

Here is the content of pom.xml:

<dependencies>
    <dependency>
        <groupId>${project.groupId}</groupId>
        <artifactId>myProject-core</artifactId>
        <version>${project.version}</version>
    </dependency>
    <dependency>
        <groupId>${project.groupId}</groupId>
        <artifactId>myProject-parser</artifactId>
        <version>${project.version}</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>${slf4j.version}</version>
    </dependency>
    <dependency>
        <groupId>info.picocli</groupId>
        <artifactId>picocli</artifactId>
        <version>${picoli.version}</version>
    </dependency>
    <dependency>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>${shade.version}</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/log4j/log4j -->
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.16</version>
    </dependency>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-api</artifactId>
        <version>2.13.1</version>
     </dependency>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>2.13.1</version>
     </dependency>
</dependencies>
<profiles>
    <profile>
        <id>client</id>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-shade-plugin</artifactId>
                    <version>${shade.version}</version>
                    <executions>
                        <execution>
                            <phase>package</phase>
                            <goals>
                                <goal>shade</goal>
                            </goals>
                            <configuration>
                                <finalName>myProject-client-${project.version}</finalName>
                                <transformers>
                                    <transformer
                                        implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                        <mainClass>myProject.package.main</mainClass>
                                    </transformer>
                                    <transformer
                                        implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer" />
                                </transformers>
                                <filters>
                                    <!-- This is necessary to avoid a java.lang.SecurityException -->
                                    <filter>
                                        <artifact>*:*</artifact>
                                        <excludes>
                                            <exclude>META-INF/*.SF</exclude>
                                            <exclude>META-INF/*.DSA</exclude>
                                            <exclude>META-INF/*.RSA</exclude>
                                        </excludes>
                                    </filter>
                                </filters>
                            </configuration>
                        </execution>
                    </executions>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-jar-plugin</artifactId>
                    <configuration>
                         <archive>
                            <manifest>
                                <!-- Jar file entry point -->
                                <mainClass>myProject.package.main</mainClass>
                            </manifest>
                         </archive>
                    </configuration>
                </plugin>

            </plugins>
        </build>

Where is my mistake? It is even does not consider <mainClass>myProject.package.main</mainClass> for the main class when I run the jar I have to specify the class name:

java -cp myApp.jar myProject.package.main 

I looked over most of the questions and nothing solve my issue.


Solution

  • First of all, there are two plugins that you can use to create fat jars: maven-shade-plugin and maven-assembly-plugin.

    The main difference between them is that maven-assembly just builds a jar containing all the dependency, while maven-shade also relocate these dependencies internally so that, if another project is depending on your jar, you won't risk having conflicts on dependencies.

    If you don't expect yo use this artifact as a dependency of other projects, you can use maven-assembly-plugin for it. Here is an example of how to use it:

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>3.1.1</version>
                <configuration>
                    <finalName>${project.artifactId}</finalName>
                    <archive>
                        <manifest>
                            <mainClass>myProject.package.main</mainClass>
                        </manifest>
                    </archive>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                    <appendAssemblyId>false</appendAssemblyId>
                </configuration>
                <executions>
                    <execution>
                        <id>make-assembly</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
    

    If you really need to shade your dependencies, try to modify the manifest config of the plugin with this, at least it should solve the problem that you-re having with identifying the main class:

                <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                  <manifestEntries>
                    <Main-Class>myProject.package.main</Main-Class>
                    <X-Compile-Source-JDK>${maven.compiler.source}</X-Compile-Source-JDK>
                    <X-Compile-Target-JDK>${maven.compiler.target}</X-Compile-Target-JDK>
                  </manifestEntries>
                </transformer>