Class not found despite of classpath in MANIFEST - java

I have this jar:
/mybundle.jar/
de/mybundle/myclass.class
lib/mysql.jar
META-INF/MANIFEST.MF
With the following MANIFEST.MF
Manifest-Version: 1.0
Class-Path: lib/mysql.jar
Main-Class: de.mybundle.myclass
It all seems perfectly correct for me, but when I run
java -jar mybundle.jar
I get a NoClassDefFoundException when the class tries to instantiate one of the MySQL-Library classes.
What did I do wrong?

You can't bundle jar files in other jar files. The paths specified in the Manifest are relative to the location of the jar file you're calling, so in your case relative to the location of mybundle.jar.
You have two options:
Either put the MySQL jar in the lib directory outside of your mybundle.jar.
Create a fat jar, which contains all classes from the required jar files in addition to your own classes. This is available from within Eclipse or Maven.

If your mybundle.jar is in c:/foo, then your mysql.jar has be in c:/foo/lib. The Class-Path in the manifest is relative to the executable JAR the way you've written it.

Related

"Could find or load main class" while running executable jar file in Java code

After converting my java program to executable jar file using commands in command prompt in windows 10,while executing jar file I am getting error:
Could find or load main class Combine.class" caused
by:java.lang.ClassNotFoundException:Combine.class
My jdk-11.0.1 has javamail api and excelapi.While executing I have set my classpath as:
classpath=%classpath%;C:\Program Files\Java\jdk-11.0.1\javamail_api\javax.mail-1.6.2.jar;C:\Program Files\Java\jdk-11.0.1\javamail_api\activation.jar;C:\Program Files\Java\jdk-11.0.1\jexcelapi\jxl.jar;.;
It was compiling and executing properly but after converting to executable jar file it is not running and giving above error.
Any help would be appreciated.
Thank you
The clue is in the exception message. It is trying to load a class with the name Combine.class. But the classes real name is Combine.
You have created the JAR file incorrectly.
echo Main-Class: Combine.class > manifest.txt
jar cmf manifest.txt FinalExecutable.jar Combine.class
If Combine is in the default package (i.e. it doesn't have a package statement) then the above should be:
echo Main-Class: Combine > manifest.txt
jar cmf manifest.txt FinalExecutable.jar Combine.class
If Combine is declared in package foo.bar, then the above should be.
echo Main-Class: foo.bar.Combine > manifest.txt
jar cmf manifest.txt FinalExecutable.jar foo/bar/Combine.class
and you need to be in the directory above the foo directory.
NB: the "Main-Class" attribute in the manifest must be a Java fully qualified class name, NOT a filename or file pathname.
It also should be noted that the CLASSPATH environment variable and the -cp argument will be ignored when you run a JAR using java -jar .... If your executable JAR depends on other JAR files, you should either combine them (to create a shaded JAR) or you should add a "Class-Path" attribute to the manifest; see https://docs.oracle.com/javase/tutorial/deployment/jar/downman.html
Finally, my advice would be to use a build tool (e.g. Maven) to compile your code, create the executable JAR file, etc rather than doing it by hand.

Execute JAR from lib directory

I have the "SomeJarA.jar" with the followiung structure:
SomeJarA
|
|--lib/SomeJarB.jar
|--com/.../SomeClass.class
Im trying to execute the "SomeJarB.jar" in "SomeClass.java" using:
Runtime.getRuntime().exec("java -jar SomeJarB.jar");
Is this possible?
As far as I know, if there's a way to achieve this, it is going to be a tricky and highly unsupported arrangement. I'll look around for some supporting documentation, but I'm inclined to say "No."
This related link might help, though.
EDIT: Found the reference I wanted. It's here. Specifically, there's a note which says, "The Class-Path header points to classes or JAR files on the local network, not JAR files within the JAR file or classes accessible over internet protocols."
This is from user #Tezar and Question Classpath including JAR within a JAR
You can use "Class-Path" in your manifest file.
For example:
Create manifest file MANIFEST.MF
Manifest-Version: 1.0
Created-By: Bundle
Class-Path: ./custom_lib.jar
Main-Class: YourMainClass
Compile all your classes and run
jar cfm Testing.jar MANIFEST.MF *.class custom_lib.jar
c stands for create archive f indicates that you want to specify file v
is for verbose input m means that we will pass custom manifest file
Be sure that you included lib in jar package. You should be able to run
jar in the normal way.
based on: http://www.ibm.com/developerworks/library/j-5things6/
See the linked Question. It seems like the sanest method for jars in jars and avoids third-party class loaders. If you feel like upvoting, go to Tezar's answer and upvote that entry, not this one, as this is just a copy.

Reference jars inside a jar

I have a jar whose content looks as shown below,
Below is my manifest file
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.8.3
Created-By: 1.7.0_06-b24 (Oracle Corporation)
Main-Class: org.sai.com.DerbyDemo
Class-Path: derby.jar derbyclient.jar derbynet.jar derbytools.jar
When i try to run the jar, it has thrown a ClassNotFoundExcception meaning it isn't referencing the jars inside the outer jar.
In the Class-Path attribute, how can I reference jars (derby.jar, etc) inside the actual jar?
You will need a custom class loader for this, have a look at One Jar.
One-JAR lets you package a Java application together with its dependency Jars into a single executable Jar file.
It has an ant task which can simplify the building of it as well.
REFERENCE (from background)
Most developers reasonably assume that putting a dependency Jar file into their own Jar file, and adding a Class-Path attribute to the META-INF/MANIFEST will do the trick:
jarname.jar
| /META-INF
| | MANIFEST.MF
| | Main-Class: com.mydomain.mypackage.Main
| | Class-Path: commons-logging.jar
| /com/mydomain/mypackage
| | Main.class
| commons-logging.jar
Unfortunately this is does not work. The Java Launcher$AppClassLoader does not know how to load classes from a Jar inside a Jar with this kind of Class-Path. Trying to use jar:file:jarname.jar!/commons-logging.jar also leads down a dead-end. This approach will only work if you install (i.e. scatter) the supporting Jar files into the directory where the jarname.jar file is installed.
You can't. From the official tutorial:
By using the Class-Path header in the manifest, you can avoid having
to specify a long -classpath flag when invoking Java to run the your
application.
Note: The Class-Path header points to classes or JAR files on the
local network, not JAR files within the JAR file or classes accessible
over internet protocols. To load classes in JAR files within a JAR
file into the class path, you must write custom code to load those
classes. For example, if MyJar.jar contains another JAR file called
MyUtils.jar, you cannot use the Class-Path header in MyJar.jar's
manifest to load classes in MyUtils.jar into the class path.
In Eclipse you have option to export executable jar.
You have an option to package all project related jars into generated jar and in this way eclipse add custom class loader which will refer to you integrated jars within new jar.
Default implementations of the classloader cannot load from a jar-within-a-jar: in order to do so, the entire 'sub-jar' would have to be loaded into memory, which defeats the random-access benefits of the jar format (reference pending - I'll make an edit once I find the documentation supporting this).
I recommend using a program such as JarSplice to bundle everything for you into one clean executable jar.
Edit: Couldn't find the source reference, but here's an un-resolved RFE off the Sun website describing this exact 'problem': http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4648386
Also, you could 'test' that your program works by placing the library jar files in a \lib sub-directory of your classes directory, then running from the command line. In other words, with the following directory structure:
classes/org/sai/com/DerbyDemo.class
classes/org/sai/com/OtherClassFiles.class
classes/lib/derby.jar
classes/lib/derbyclient.jar
From the command line, navigate to the above-mentioned 'classes' directory, and type:
java -cp .:lib/* org.sai.com.DerbyDemo
if you do not want to create a custom class loader. You can read the jar file stream. And transfer it to a File object. Then you can get the url of the File. Send it to the URLClassLoader, you can load the jar file as you want.
sample:
InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("example"+ ".jar");
final File tempFile = File.createTempFile("temp", ".jar");
tempFile.deleteOnExit(); // you can delete the temp file or not
try (FileOutputStream out = new FileOutputStream(tempFile)) {
IOUtils.copy(resourceAsStream, out);
}
IOUtils.closeQuietly(resourceAsStream);
URL url = tempFile.toURI().toURL();
URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{url});
urlClassLoader.loadClass()
...
Add the jar files to your library(if using netbeans) and modify your manifest's file classpath as follows:
Class-Path: lib/derby.jar lib/derbyclient.jar lib/derbynet.jar lib/derbytools.jar
a similar answer exists here
in eclipse, right click project, select RunAs -> Run Configuration and save your run configuration, this will be used when you next export as Runnable JARs

Cannot find class even when jar file is in working directory

I am struggling to get my Java program to run on AIX. I used Eclipse on Windows to create a runnable Jar file, jRams.jar below. I kept on getting a class not found error, until finally I put all the external libraries in the same directory.
$ ls
JAXB2_20081030.jar
JAXB2_20110601.jar
activation.jar
asjava.jar
commons-beanutils-1.8.3.jar
commons-beanutils-bean-collections-1.8.3.jar
commons-beanutils-core-1.8.3.jar
commons-codec-1.5.jar
commons-collections-3.2.1.jar
commons-configuration-1.6.jar
commons-digester-2.1.jar
commons-jxpath-1.3.jar
commons-lang-2.6.jar
commons-logging-1.1.1.jar
commons-logging-adapters-1.1.1.jar
commons-logging-api-1.1.1.jar
jRams.jar
jaxb-api.jar
jaxb-impl.jar
jaxb-xjc.jar
jaxb1-impl.jar
jremote.jar
jsr173_1.0_api.jar
log4j-1.2.16.jar
netty-3.2.4.Final.jar
$
Still, I get the class not found error.
$ java -jar jRams.jar
The java class is not found: com.jbase.jremote.JRemoteException
jremote.jar definitely contains JRemoteException. Why isn't this working?
UPDATE
Thank you for your straight-to-the-point answers. I now understand the nature of a java application and a manifest file far better.
Turns out my ftp client was transferring in ASCII mode and not Binary, so the jar files were corrupt. I have learned a great deal, nonetheless.
When using the -jar option, you need to specify which jar-files should be on your class path in the manifest file. Just having the required jar files in the same directory won't do it.
Add a line in your manifest that says:
Class-Path: JAXB2_20081030.jar:JAXB2_20110601.jar:....:netty-3.2.4.Final.jar
or skip the -jar option and launch using
java -cp JAXB2_20081030.jar:....:netty-3.2.4.Final.jar:jRams.jar pkg.JRamsMain
and it should work fine.
(Note that on *nix systems, as opposed to Windows machines, the jar files in the class paths should be separated using : instead of ;.)
Further reading:
The Java Tutorials: Adding Classes to the JAR File's Classpath
You need to add all those JARs to the runtime CLASSPATH by adding the -classpath parameter. AIX requires you to separate the JARs using :
You will have to specify the full path(if libraries not in the same directory as jRams) or just the names of the jar file in a manifest file (If all dependency jars are in the same folder). Alternative specify the path to all the dependent jars using -cp argument.
Example (This assume every dependency is in the same directory you are executing java command from):
java -cp commons-collections-3.2.1.jar; jaxb-impl.jar; etc.. ;jRams.jar package_to_class.MyMainClass.java
Where package_to_class is example: com.myproj.example.
EDITED.
Follow these steps to add "Class-Path" to existing jar file -
Create "newmanifest" file with following entry
Class-Path: additional/jars
Update existing jar file e.g. "classes.jar"
jar --update --manifest=newmanifest --file classes.jar
Inflate jar file
jar -xvf classes.jar
created: META-INF/
inflated: META-INF/MANIFEST.MF
Verify "Class-Path" is added to MANIFEST.MF
cat META-INF/MANIFEST.MF
Manifest-Version: 1.0
main-class: CLASSNAME
Created-By: 15.0.2 (Oracle Corporation)
Class-Path: additional/jars

Main-Class can't be set to existing class

I have a build setup that requires that my classes be put into a folder in a subdirectory of my current directory. I.E., if I'm at '.', then the classes could be in './somewhere_else/'
The problem is that when I do this I can't set a value for Main-Class that can find the main class. I have no problem when I build the jar from files at '.', but all the following attempts for main class result in java.lang.NoClassDefFoundError's:
Main-Class: ClassName
Main-Class: FolderName.ClassName
Main-Class: FolderName/ClassName
What should I be using?
The classes inside your jar have to be in the same directory structure as your package structure.
So, if you want to have your class ClassName (without any package) to be the main class, it has to be in the root directory of your jar.
If you want to have the class in the directory FolderName, this same name has to be the package name, meaning the first (non-empty non-comment) line of your source file should be package FolderName;.
If your problem is only the build setup - this is not a problem, the folder-layout of your directories outside the jar does not necessarily have to be the same as the layout inside your jar. But it still helps if the folder-structure fits to the package-structure (with maybe additionally directories above).
I think you should reference Main-Class simply by the class name (without directory structure). What will help you solve this problem is what you put as the classpath. Make sure the directory of Main-Class is in the classpath.
If your ClassName resides in package FolderName, then, it should be:-
Manifest-Version: 1.0
Main-Class: FolderName.ClassName
Class-Path: <third-party>.jar <another-third-party>.jar
They are case-sensitive, by the way.

Categories

Resources