java.lang.NoClassDefFoundError after building jar file in Intellij - java

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

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.
Create a so-called uberJAR file by merging the contents of the dependent JARs into your main JAR.
References:
IntelliJ IDEA export Runnable program as Uber Jar
https://blog.jetbrains.com/idea/2010/08/quickly-create-jar-artifact/
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.

Related

java Jar containing jars => java.lang.NoClassDefFoundError -> How to include .jar files

jar file
when I run java -jar main.jar I get the following error:
The main class of the .jar file second.jar which is one of several libraries inside is not accessible.
I cannot rebuild the project since I just have the main.jar file.
How can I write a run.bat file or a mainifest.mf file that all .jar files that are contained in the main.jar file are accessible.
Here is the mainifest.mf file inside the main.jar:
There are following probable options for you to solve.
Add all the required jar files in the Manifest.MF as given below.
Manifest-Version: 1.0
Main-Class: com.comapany.product.MainClass
Class-Path: a.jar b.jar c.jar
You can run manually using the following command
java -cp a.jar;b.jar;c.jar com.comapany.product.MainClass
It is highly recommended to create a fat jar using Maven Shade plugin in case of Maven or Shadow plugin in case of Gradle.

Add a jar file to another jar file

In my project I have this code that tell class loader to load Driver.class like so:
Class.forName(org.gjt.mm.mysql.Driver);
In Eclipse it runs with no problems and I have created the Jar file of the project. But I don't know how to insert the
mysql-connector-java-5.1.7-bin.jar
into a Jar file of my project. The folder structure look like this:
MANIFEST file:
Manifest-Version: 1.0
Main-Class: server.MultiServer
I am assuming that you finally just want to run your code as
java -jar myjar.jar
There are two options.
Keep mysql-connector-java-5.1.7-bin.jar next to your jar in the same folder and add classpath: mysql-connector-java-5.1.7-bin.jar to the manifest.
Copy all the classes in mysql-connector-java-5.1.7-bin.jar to your jar. Do not copy the jar but the classes in the jar. This is called a fat jar or uber jar. You can automate the same using maven shade plugin.
When you invoke your application jar add the -cp or -classpath option and provide the path to the dependent libraries, here the mysql-connector-java-5.1.7-bin.jar.
for example refer the below example
java -jar -classpath C:\myproject\lib\mysql-connector-java-5.1.7-bin.jar myproject.jar

Standalone Jar Execution From Batch File

Below is my Jar structure. This is standalone jar.
MyApp.jar
--> .settings
--> com
--> lib
--> META-INF
--> resources
--> .classpath
--> .project
I am attempting to execute this jar file from bat file.
I have mentioned classpath and main class in MANIFEST.MF file under META-INF folder from MyApp.jar
Manifest-Version: 1.0
Class-Path: ./lib/jar1.jar ./lib/jar2.jar ./lib/jar3.jar
Main-Class: com.bank.Main
Inside my bat file:
java -jar D:\app\MyApp.jar
Is it correct way to lib folder inside jar?
But still i am facing ClassNotFoundException.
Exception in thread "main" java.lang.NoClassDefFoundError: javax/jms/JMSException
Anything i missed out Please advise me.
Put the lib folder outside of your current main jar [MyApp.jar] directory and execute it.
You have packaged the jar dependency inside your main jar. The intention of Class-Path is to add an external jar to the classpath, with the path relative to the location of the main jar.
Packaging a jar within a jar is not supported by standard Java classloaders. If you want, you can explode the inner jar into the main jar, though. Maven can do this for you.
Fat jar is not supported in Java by default. There are two options.
You can define a custom class loader which has to load jars inside lib directory programmatically.
You can manually merge all packages of jars inside lib directory to make a one jar and run it. Refer [https://dzone.com/articles/java-8-how-to-create-executable-fatjar-without-ide ]

Can't find dependent libraries in jar

My java project uses javax.mail.jar. So, in netbeans, I created a new folder Libraries, copied the jar file there and added this in project properties. I added this folder to git and this runs fine on netbeans. But when I build the project with ant on another machine and run the project jar with
java -jar myproject.jar
I get the error
Exception in thread "main" java.lang.NoClassDefFoundError:
javax/mail/MessagingException
I can see that myproject.jar contains the dependent library
$jar tf TakServer.jar
Libraries/
Libraries/javax.mail.jar
...
I'm not sure what is going wrong. Any idea how to get it to run?
Solution: As #Gimby pointed out, the jar files from Netbeans and ant build are different. Netbeans includes a lib/ folder containing all dependencies in dist/ folder and its MANIFEST.ML adds lib/ to classpath. The Libraries folder inside the main jar is not used at all.
The ClassPath in the manifest points to the filesystem outside the jar.
It it not possible to use jars inside jars
https://docs.oracle.com/javase/tutorial/deployment/jar/downman.html

Creating jar which includes classpath

I am trying to send my jar file to other people without the need to send multiple jar files to a person for them to run my application. Is there a way to include a secondary jar file inside of my jar and have it as my Class-path instead of it being in my working directory?
This is my manifest for when i create the Jar.
Manifest-Version: 1.0
Main-Class: MultipleLinearRegression
Class-Path: Jama.jar
This is how I am creating my jar file
jar cvfm MyApplication.jar manifest.txt Jama.jar *.class
With Maven and the Shade plugin you can create an Uber JAR, containing all dependend JARs in one JAR file. There is also a Shade Plugin for Gradle. (If you don't use Maven or Gradle, you should really consider to do so.)
There is an interesting article here: Creating Executable Uber Jar’s and Native Applications with Java 8 and Maven
There are other similar tools like One-JAR.
for creating a jar file, we can follow these steps,
1) Class-Path: <lib1.jar> <lib2.jar> <path/lib3.jar>
2) Main-Class: <classname>
3) Place a new line at the end of this file

Categories

Resources