Łukasz Feller
Łukasz Feller

Reputation: 200

java.lang.NoClassDefFoundError after building jar file in Intellij

The structure of my first app is simple:

libs
  opencsv-3.8.jar
  yamlbeans-1.0.jar
out
  artifacts
    ...
  production
    ...
src
  META-INF
    MANIFEST.MF
  pl.krzysiu
    App.java
    CsvReplacer.java

Everything is fine during the compile and running the program. After building artifact jar file in the default out\artifacts directory, I get

java.lang.NoClassDefFoundError: net/sourceforge/yamlbeans/YamlException

when I try to run it by java -jar CsvReplacer.jar command

The libraries are included inside the jar file (they are there after unpacking it) - they are added to Libraries section in Project Structure (separately - one file per one lib), the whole libs dir is included in the Dependencies tab of Modules section (with export checkbox checked) and the libs dir is added in Output Layout of Artifacts section similarily.

The manifest file contains:

Manifest-Version: 1.0
Class-Path: libs\yamlbeans-1.0.jar libs\opencsv-3.8.jar
Main-Class: pl.krzysiu.App

Why the libs aren't visible for the App? If I copy this dir manually to the CsvReplacer.jar file's location - everything works fine.

The structure inside CsvReplacer.jar file looks like:

libs
  opencsv-3.8.jar
  yamlbeans-1.0.jar
META-INF
  MANIFEST.MF
pl
  krzysiu
    App.java
    CsvReplacer.java

IDE: Intellij IDEA 2016.3

Upvotes: 2

Views: 6983

Answers (1)

Stephen C
Stephen C

Reputation: 718826

The standard Java classloaders cannot find a JAR file embedded inside another JAR file.

You have two choices when making an executable JAR with dependencies.

  1. Create a so-called uberJAR file by merging the contents of the dependent JARs into your main JAR.

    References:

  2. Give your JAR a "Class-Path" manifest attribute to tell it where the (external!) dependent JARs are located.

You can't give a -cp and a -jar option together. But another alternative would be to get rid of the -jar option and use a -cp argument to specify the classpath.

Alternatively, you could implement a custom classloader that can load from a jar inside a jar, or use something like one-jar or Spring Boot.

Upvotes: 4

Related Questions