0

My app is facing a NoClassDefFoundError when trying to access external dependencies, but only when run as a jar.

Using Intellij, I have a simple app with main class with some calls to external dependencies such as slf4j.

public class Main {
private static final Logger logger = LoggerFactory.getLogger(Main.class);
     ///
    public static void main(String[] args) {
    logger.debug("start");
    }

}

The pom.xml includes the relevant dependencies and the app is compiled successfully.

When running the app from the intellij as regular application it is running with no problem.

But when creating an executable jar out of it and trying to run it, it crashes and can't find external dependencies:

 java.lang.NoClassDefFoundError: org/slf4j/LoggerFactory
  at com.example.Main.<clinit>(Main.java:18)
Caused by: java.lang.ClassNotFoundException: org.slf4j.LoggerFactory
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:338)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    ... 1 more
Exception in thread "main" 
Process finished with exit code 1

I added this to the pom to try to solve the problem, but it didn't help:

    <build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
        </plugin>
        <plugin>
            <!-- Build an executable JAR -->
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>3.0.2</version>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                        <classpathPrefix>lib/</classpathPrefix>
                        <mainClass>com.example.Main</mainClass>
                    </manifest>
                </archive>
            </configuration>
        </plugin>
    </plugins>
</build>

The manifest file is located in src/main/resources/META-INF/MANIFEST.MF:

Manifest-Version: 1.0
Main-Class: com.example.Main
riorio
  • 6,500
  • 7
  • 47
  • 100
  • 1
    Dependencies are probable not included in the jar. See https://stackoverflow.com/questions/574594/how-can-i-create-an-executable-jar-with-dependencies-using-maven – StephaneM Apr 03 '18 at 12:30
  • you should add slf4j jar in build path while running jar out of your IDE, IDE will automatically manage build path and add dependency declare in pom.xml. @riorio – Afgan Apr 03 '18 at 12:42

2 Answers2

1

Your meta-inf should have following attributes Manifest-Version: 1.0
Created-By: xxxx
Main-Class: com.sample.Main
ClassPath: path/to/jars/your.jar

java -cp yourpath/example.jar com.sample.Main
Or
java -jar example.jar

1

It's simple to understand. The jar that you are creating contains only the .class files of your code, not of the other libraries that you're importing. So when you run your code, it is unable to find the external library (org.slf4j in this case) that you have referenced in your code.

I don't know about the maven jar plugin that you're using, but try the maven assembly plugin. This plugin is used to bundle up all the other libraries that you use along with your code and create a "bundled" jar. Add the following to your pom.xml. You can add this portion between <plugins> and </plugins>.

<plugin>
  <artifactId>maven-assembly-plugin</artifactId>
    <executions>
      <execution>
        <id>example</id>
        <configuration>
          <archive>
            <manifest>
              <mainClass>com.example.Main</mainClass>
            </manifest>
          </archive>
          <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
          </descriptorRefs>
          <appendAssemblyId>false</appendAssemblyId>
        </configuration>
      <phase>package</phase>
      <goals>
        <goal>single</goal>
      </goals>
    </execution>
  </executions>
</plugin>

This additionally binds this "assembly" goal to the package phase of maven. So mvn package should create your jar.

Shiva
  • 459
  • 4
  • 15