Adding external dependencies to a jar file through the command line - java

After reading this question I have managed to run a .jar file that had external dependencies locate in jar files:
/usr/lib/jvm/java-8-jdk/bin/java -classpath /usr/local/bin/kiaragen.jar:/home/kiara/AppLab/KIARA/kiaragen/src/main/resources/org/fiware/kiara/generator/idl/templates/*:/usr/lib/jvm/java-8-jdk/jre/lib/*:/home/kiara/AppLab/KIARA/kiaragen/lib/* org.fiware.kiara.generator.kiaragen
where /usr/local/bin/kiaragen.jar is the file to execute. Now, I'm trying to run a different version that depends on an a .class file:
/home/kiara/AppLab/KIARA/IDL-Parser/target/classes/com/eprosima/idl/parser/exception/ParseException.class
Adding the file to the classpath:
/usr/lib/jvm/java-8-jdk/bin/java -classpath /usr/local/bin/kiaragen-0.2.0.jar:/home/kiara/AppLab/KIARA/IDL-Parser/target/classes/com/eprosima/idl/parser/exception/ParseException.class:/home/kiara/AppLab/KIARA/kiaragen/src/main/resources/org/fiware/kiara/generator/idl/templates/*:/usr/lib/jvm/java-8-jdk/jre/lib/*:/home/kiara/AppLab/KIARA/kiaragen/lib/* org.fiware.kiara.generator.kiaragen
gives the following exception:
Error: A JNI error has occurred, please check your installation and try again
Exception in thread "main" java.lang.NoClassDefFoundError: com/eprosima/idl/parser/exception/ParseException
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
at java.lang.Class.privateGetMethodRecursive(Class.java:3048)
at java.lang.Class.getMethod0(Class.java:3018)
at java.lang.Class.getMethod(Class.java:1784)
at sun.launcher.LauncherHelper.validateMainClass(LauncherHelper.java:544)
at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:526)
Caused by: java.lang.ClassNotFoundException: com.eprosima.idl.parser.exception.ParseException
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 7 more
Why?
The manifest file of the .jar is the same as before:
$ cat META-INF/MANIFEST.MF
Manifest-Version: 1.0
Main-Class: org.fiware.kiara.generator.kiaragen
How can I add the .class file to the class path?

You're not understanding what the classpath is. The classpath is a collection of jar files and directories where Java looks for classes (and other resources loaded by the class loader).
If a program uses the class com.foo.Bar, what must be in the classpath is not the file /somedirectory/com/foo/Bar.class. What must be in the classpath is the directory /somedirectory. Or the jar file containing that class.
From that base directory or jar file, the class loader will then look for a file corresponding to the class name:
com.foo.Bar --> com/foo/Bar.class
This is essential, because it allows Java to have access to hundreds of classes at once, without having to list those hundreds of class files in the classpath. All you need in the classpath is the directory or jar containing those hundreds of classes.
Also note that /usr/lib/jvm/java-8-jdk/jre/lib/* must not be inthe classpath either. Java knows where to find the libraries of the JRE itself.

Related

Wrong classpath declaration gets a java.lang.NoClassDefFoundError

I have a small project which in my local IDE is running just fine, a screenshot will show the project structure:
I have highlighted the jewelcli jar because on that class i get the exception mentioned in the header.
While running locally all goes fine, on a testing ubuntu server i get:
java -verbose -classpath "/correct/path/jarName.jar:lib/jars/*" correct.package.and.main.Class
***all bootstrapping class from RT.JAR***
java.lang.NoClassDefFoundError: uk/co/flamingpenguin/jewel/cli/ArgumentValidationException
at correct.package.and.main.Class.main(Class.java:31)
Caused by: java.lang.ClassNotFoundException: uk.co.flamingpenguin.jewel.cli.ArgumentValidationException
at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
... 1 more
I dont think this is actually related at all to that jewelcli jar in particular, because i double checked and its there:
unzip -l jarname.jar | grep jewelcli
435937 11-20-11 01:22 lib/jars/jewelcli-0.7.6.jar
But it happens for that Jar because it is the very first jar that the program needs (after all the bootstrapping classes in rt.jar).
This is where i am basing my command line from
But i also see:
Subdirectories are not searched recursively. For example, foo/* looks for JAR files only in foo, not in foo/bar, foo/baz, etc.
I thought that by specifying in the command line the jar file containing all the libraries, java would automaticaly, and recursively, scan all subdirectories, but it does not work:
java -verbose -classpath "/correct/path/jarName" correct.package.and.main.Class
Any tip on how can i get java to scan the whole jar i specify in the -classpath option?
I thought that by specifying in the command line the jar file containing all the libraries, java would automaticaly, and recursively, scan all subdirectories
It depends. The standard Java classloaders do not know how to load classes from JARs that embedded inside other JARs.
And that's what you appear to have done ... if I am reading your question correctly.
There are a few ways to address this:
Copy all of the dependent JARs to the server, put them into a directory, and add the directory to the classpath; e.g.
java -classpath "/correct/path/jarName.jar:/correct/path/lib/*" \
correct.package.and.main.Class
Build an UberJAR or shaded JAR by unpacking the dependent JARs into a directory, adding your classes and producing a JAR from the tree. There are maven plugins for building such JAR files.
Use something like Spring Boot which uses a classloader that understands how to deal with JARs withing JARs.

Unable load jar from my jar: NoClassDefFoundError

I have this jar:
/weekly/
/database.class
/report.class
/META-INF
/MANIFEST.MF
The MANIFEST.MF
Manifest-Version: 1.0
Main-Class: weekly.report
Class-Path: /root/java
In this jar i used two external jar files, postgresql-9.1-901.jdbc4.jar, javax.mail.jar. I also put those into /root/java.
but when i run it use
java -jar weekly.jar
It shows those two jars class can't find
Exception in thread "main" java.lang.NoClassDefFoundError: javax/mail/internet/AddressException
Caused by: java.lang.ClassNotFoundException: javax.mail.internet.AddressException
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
even i try to put those two jars to my $CLASSPATH
/usr/java/jdk1.6.0_21/lib:/usr/java/jdk1.6.0_21/jre/lib
It also shows same error result. I can successfully run it in my Mac, but when i try to remove it to my server CentOS system ,it shows those NoclassDefFounderror.
Finding a JAR file using a classpath is similar to finding a package
file in a classpath. The difference is that when you specify a path
for a JAR file, you must include the name of the JAR file at the end
of the path.
So you can try something like this:
java -classpath /usr/java/jdk1.6.0_21/lib/javax.mail.jar:/usr/java/jdk1.6.0_21/jre/lib/postgresql-9.1-901.jdbc4.jar -jar weekly.jar
Another option is to put your jars into jre/lib/ext (but I don't think it's a good idea)

How to Run a Java Class File from the Command Line that was Compiled by Eclipse? External Jar problems

I have a project that runs fine in Eclipse. The project uses many external jars.
My file directory for the project has a bin and src directory, and a .classpath and .project files.
From this directory, if I execute:
java -cp bin com.brm.main.Demo2
I receive the following error:
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/lucene/sea
rch/Query
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2442)
at java.lang.Class.getMethod0(Class.java:2685)
at java.lang.Class.getMethod(Class.java:1620)
at sun.launcher.LauncherHelper.getMainMethod(LauncherHelper.java:494)
at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:486)
Caused by: java.lang.ClassNotFoundException: org.apache.lucene.search.Query
at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
... 6 more
org/apache/lucene is an external jar.
You also need to include your other dependencies on the classpath, separating classpath elements with ; on Windows or : on Linux.
On Windows:
java -cp bin;path\to\lucene.jar com.brm.main.Demo2
On Linux:
java -cp bin:path/to/lucene.jar com.brm.main.Demo2
If you have other jarfiles or directories in addition to lucene and bin, you'll have to add those, too.
If you're trying to deploy your program, a better solution is to use Eclipse's "Export" wizard to export a Runnable JAR File, which will walk you through the steps to select your main class and bundle your dependencies. Or, going even further, you can use ant or maven to build your project and create a deployable bundle.
How about trying like this:-
java -cp .;%CLASSPATH% com.brm.main.Demo2
seems like your classpath is invalid and because of that the .jars for the external libraries are not found.

How to run a jar file in hadoop?

I have created a jar file using the java file from this blog using following statements
javac -classpath /usr/local/hadoop/hadoop-core-1.0.3.jar -d /home/hduser/dir Dictionary.java
/usr/lib/jvm/jdk1.7.0_07/bin/jar cf Dictionary.jar /home/hduser/dir
Now i have tried running this jar in hadoop by hit and trial of various commands
1hduser#ubuntu:~$ /usr/local/hadoop/bin/hadoop jar Dictionary.jar
Output:
Warning: $HADOOP_HOME is deprecated.
RunJar jarFile [mainClass] args...
2.hduser#ubuntu:~$ /usr/local/hadoop/bin/hadoop jar Dictionary.jar Dictionary
Output:
Warning: $HADOOP_HOME is deprecated.
Exception in thread "main" java.lang.ClassNotFoundException: Dictionary
at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:264)
at org.apache.hadoop.util.RunJar.main(RunJar.java:149)
How can i run the jar in hadoop? I have the right DFS Locations as per needed by my program.
I was able to reproduce your problem. The problem is where you are creating the jar.
Basically, the directory that you are packaging into the jar is confusing the jar file in locating the main class file. Instead if you try doing :
/usr/lib/jvm/jdk1.7.0_07/bin/jar cf Dictionary.jar /home/hduser/dir/Dictionary.class
i.e. package the class file specifically into the jar and then run:
/usr/local/hadoop/bin/hadoop jar Dictionary.jar Dictionary
It just works fine provided that you have a main function in your class called Dictionary.
The problem is when you package a full directory inside a jar then the jar also needs to be aware of the directory structure to locate the class file. For this, we need to have a well defined package hierarchy to define the class location. So, when you are packaging /home/hduser/dir/ into the jar, the jar is not aware of the location of the class file which is located deep inside this directory structure. For this you need to add a package name to your .java file according to the directory structure , for example home.hduser.dir and while running the hadoop jar command specify the class name with the package structure, for example home.hduser.dir.Dictionary.
Use the below command to run the hadoop jar file from the CLI.
hadoop jar <jarFileName> <mainClassname> <AnyCommandLineArguements>
I also ran into the same problem and the console does not show much information but just
RunJar jarFile [mainClass] args...
Please check the jar for the package folders location, as a straightforward approach please try is the package starts with com.company...
The "com" folder should be the first level folder when the jar is unpacked

link GetOpt to main jar

I have a folder gnu\getopt contains Getopt.class which is need by ChatDemo.jar for parser argument parameters, when I ran with java -cp xSocket.jar;. ChatDemo.jar it produce:
Exception in thread "main" java.lang.NoClassDefFoundError: gnu/getopt/Getopt
at ChatDemo.main(ChatDemo.java:24)
Caused by: java.lang.ClassNotFoundException: gnu.getopt.Getopt
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
... 1 more
ChatDemo.java:
import gnu.getopt.Getopt;
ChatDemo Manifest:
Manifest-Version: 1.0
Created-By: 1.6.0_22 (Sun Microsystems Inc.)
Main-Class: ChatDemo
Class-Path: xSocket.jar
Run it with java -classpath "xSocket.jar;.;ChatDemo.jar ChatDemo (no .jar after the name of the main class).
Note that you must add the folder which contains "gnu" to the classpath. Another solution is to put the getopt classes in a JAR and add that to the classpath. Make sure that the folder structure (gnu\getopt) is preserved.
It looks like you are mixing up the two ways of running java. You should either supply a classpath (e.g. using the -cp argument), or launch from a JAR file. You cannot do both.
If you launch using a JAR file, the -cp argument is ignored. In that case, you must specify the complete classpath in the JAR file's manifest.
The manifest in the ChatDemo.jar file apparently doesn't include. You can remedy this in two ways:
Update the manifest classpath to be "Class-path: xSocket.jar ." ... note we use a space to separate the entries here, not ; or :.
Add Getopt.class to the JAR file as gnu/getopt/Getopt.class.
However, if you launch using a JAR file you have to use the -jar option. If you try to your application like this:
java -cp xSocket.jar;. ChatDemo.jar
it will fail telling you that it cannot find a class called ChatDemo.jar ; i.e. it will misinterpret the JAR filename as a qualified classname.
Add Main-Class - as fully qualified (I mean as per package structure) class name of your class which contains main method.

Categories