Wrong classpath declaration gets a java.lang.NoClassDefFoundError - java

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.

Related

How to run scala jar with java libraries?

I need to create a scala application which uses several java library jars ( these jars are only available in java). For this, I created a Scala Project using Scala version (scala-sdk-2.13.0-M4 with Java 1.8.0_162) on IntelliJ Idea (Ver. 2018.1.6 community). Added an artifact as jar. It uses several java library jar files as well.
I need to run my scala jar on scala version 2.12.6
Case 1 : When I create the scala jar file of my code only and keep other jars in a lib folder adjacent to MyScalaJar.jar file and run command
scala -classpath lib / *.jar MyScalaJar.jar
It gives below exception:
java.lang.NullPointerException
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at scala.reflect.internal.util.ScalaClassLoader.$anonfun$tryClass$1(ScalaClassLoader.scala:45)
.
.
.
at scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:101)
at scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)
Case 2 :
When I create one consolidated jar file MyFullScalaJar.jar using option "Extract Jar" and run command:
scala MyFullScalaJar.jar
It gives Exception like missing log4j jar:
I've checked that contents of log4j jar are there in the consolidated jar file as extracted in it.
java.lang.ClassNotFoundException: org.apache.commons.logging.LogFactory
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
.
.
.
. at scala.tools.nsc.MainGenericRunner.process(MainGenericRunner.scala:96)
at scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:101)
at scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)
I must be missing something very basic. What is the correct way to create/run scala jar?

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

Run jar file with out specify supporting jar file

I create a new jar file. when i run the jar using
java -jar UpdateAvailable.jar com.dao.mysql.UpdateAvailable
I got the following exception.
Exception in thread "main" java.lang.NoClassDefFoundError: org/codehaus/jettison/json/JSONException
Caused by: java.lang.ClassNotFoundException: org.codehaus.jettison.json.JSONException
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:306)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
But I copied all the supporting jars inside the UpdateAvailable.jar. Now what my requirement is run the jar file with out specifying supporting jars, like
java -jar UpdateAvailable.jar com.dao.mysql.UpdateAvailable
Here are some points to remember while you are working with JAR files and ClassPath: -
For making your JVM find class, your classpath should be set till the directory containing the class. In this case you have JAR.
So, you need to give the path till your Jar File Name
Now, since you have your Jar files inside your currently running Jar file, you can't set your classpath till the folder inside a Jar, so basically you won't be able to set classpath for inner Jar Files..
So, clearly JVM won't be able to see classes inside your inner Jar..
So, make sure that your required JAR files are outside of all the JAR files (I mean to say - avoid Nested JAR Files)..
I'm not sure how you are packaging your jar file, but it would sound like you need something like One-Jar to help you package your file and all your supporting libraries into a single jar. One-Jar comes with it's own classloader that allows it to load all the included jars in your executable jar file.
Configuration is fairly straight forward and easy to use. If you are using Maven, you can use the one-jar maven plugin to help you configure which libs you want included.
There are also other similar packages you can use instead of One-Jar, such as JarJar and ProGuard. Also take a quick look at this SO question.
In executable jar couldn't reads any supporting jar files inside a jar. So keep all supporting jars in a folder and place the executable jar in the same directory. And add "Class-Path" as "Supporting jar files separate with space" in "MANIFEST.MF" File. Now run the jar as
java -jar UpdateAvailable.jar com.dao.mysql.UpdateAvailable

Why edit to Manifest file provides solution that CLASSPATH does not

I'm writing a short utility that performs a short task on a remote Oracle instance. The utility uses the Oracle jdbc driver found in ojdbc6.jar.
The Oracle jar is properly included in my classpath. When I export my project to a jar and run the jar on the command line using "java -jar ", I get:
Exception in thread "main" java.lang.ClassNotFoundException: oracle.jdbc.OracleDriver
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)
at java.lang.Class.forName0(Native Method)
After moving the Oracle jar into the same directory as my runnable jar file, I changed my Manifest file to include the the Oracle jar in the classpath. This fixed the problem, and my jar ran fine.
Can anyone explain why including the Oracle jar in my classpath didn't solve the problem, and why editing the Manifest file did?
Thanks!
From Sun (Oracle) documentation for the java -jar command:
Execute a program encapsulated in a JAR file. The first argument is
the name of a JAR file instead of a startup class name. In order for
this option to work, the manifest of the JAR file must contain a line
of the form Main-Class: classname. Here, classname identifies the
class having the public static void main(String[] args) method that
serves as your application's starting point. See the Jar tool
reference page and the Jar trail of the Java Tutorial for information
about working with Jar files and Jar-file manifests. When you use this
option, the JAR file is the source of all user classes, and other user
class path settings are ignored.

How do I run a class in a WAR from the command line?

I have a Java class which has a main and I used to run as a standalone app from the command line e.g.
java -jar myjar.jar params
I needed to repackage the code to run under apache and all my code, including the entry point class from the old jar, has ended up in a WAR file for easy deplyment into the web server.
However, I still want to be able to run it from the command line and the code has not changed and is all in there, I just can't figure out how to get it to run.
Here's what I tried...
I presumed the WAR was just like a jar, so
java -jar mywar.war params
That failed saying there was no main class defined in the manifest.
I manually added a manifest to the war and tried again, with the same effect.
I noticed that in my war I had a folder called META-INF containing a manifest.mf, so I added a line to that declaring my main class as I would to a normal manifest...
Manifest-Version: 1.0
Main-Class: mypackage.MyEntryPointClass
This gave a noClassDefFoundError mypackage.MyEntryPointClass, which is progress of a sort. That led me to believe that it was just a path issue, so I tried
Manifest-Version: 1.0
Main-Class: WEB-INF.classes.mypackage.MyEntryPointClass
I now get the same error, but with a stack trace...
Exception in thread "main" java.lang.NoClassDefFoundError: WEB-INF/classes/mypackage/MyEntryPointClass (wrong name: mypackage/MyEntryPointClass)
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(Unknown Source)
at java.security.SecureClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.access$100(Unknown Source)
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClassInternal(Unknown Source)
I've googled for a bit but can't find anything which answers my question, and I read a couple of other questions here which are slightly different, so I thought I would post.
Java 1.5, not that I think that should make any difference.
Similar to what Richard Detsch but with a bit easier to follow (works with packages as well)
Step 1: Unwrap the War file.
jar -xvf MyWar.war
Step 2: move into the directory
cd WEB-INF
Step 3: Run your main with all dependendecies
java -classpath "lib/*:classes/." my.packages.destination.FileToRun
You can do what Hudson (continuous integration project) does.
you download a war which can be deployed in tomcat or to execute using
java -jar hudson.war
(Because it has an embedded Jetty engine, running it from command line cause a server to be launched.) Anyway by looking at hudson's manifest I understand that they put a Main class in the root for the archive. In your case your war layout should be look like:
under root:
mypackage/MyEntryPointClass.class
WEB-INF/lib
WEB-INF/classes
META-INF/MANIFEST.MF
while the manifest should include the following line:
Main-Class: mypackage.MyEntryPointClass
please notice that the mypackage/MyEntryPointClass.class is accessable from the command line only, and the classes under WEB-INF/classes are accessable from the application server only.
HTH
A war is a webapp. If you want to have a console/standalone application reusing the same classes as you webapp, consider packaging your shared classes in a jar, which you can put in WEB-INF/lib. Then use that jar from the command line.
Thus you get both your console application, and you can use the same classes in your servlets, without making two different packages.
This, of course, is true when the war is exploded.
If you're using Maven, just follow the maven-war-plugin documentation about "How do I create a JAR containing the classes in my webapp?": add <attachClasses>true</attachClasses> to the <configuration> of the plugin:
<project>
...
<artifactId>mywebapp</artifactId>
<version>1.0-SNAPSHOT</version>
...
<build>
<plugins>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.6</version>
<configuration>
<attachClasses>true</attachClasses>
</configuration>
</plugin>
</plugins>
</build>
...
</project>
The you will have 2 products in the target/ folder:
The project.war itself
The project-classes.jar which contains all the compiled classes in a jar
Then you will be able to execute a main class using classic method: java -cp target/project-classes.jar 'com.mycompany.MainClass' param1 param2
To execute SomeClass.main(String [] args) from a deployed war file do:
Write class SomeClass.java that has a main method method i.e. (public static void main(String[] args) {...})
Deploy your WAR
cd /usr/local/<yourprojectsname>/tomcat/webapps/projectName/WEB-INF
java -cp "lib/jar1.jar:lib/jar2.jar: ... :lib/jarn.jar" com.mypackage.SomeClass arg1 arg2 ... arg3
Note1: to see if the class SomeOtherClass.class is in /usr/tomcat/webapps/<projectName>/WEB-INF/lib run:
cd /usr/tomcat/webapps/projectName/WEB-INF/lib &&
find . -name '*.jar' | while read jarfile; do if jar tf "$jarfile" | grep SomeOtherClass.class; then echo "$jarfile"; fi; done
Note2: Write to standard out so you can see if your main actually works via print statements to the console. This is called a back door.
Note3: The comment above by Bozhidar Bozhanov seems correct
The rules of locating classes in an archive file is that the location of the file's package declaration and the location of the file within the archive have to match. Since your class is located in WEB-INF/classes, it thinks the class is not valid to run in the current context.
The only way you can do what you're asking is to repackage the war so the .class file resides in the mypackage directory in the root of the archive rather than the WEB-INF/classes directory. However, if you do that you won't be able to access the file from any of your web classes anymore.
If you want to reuse this class in both the war and outside from the java command line, consider building an executable jar you can run from the command line, then putting that jar in the war file's WEB-INF/lib directory.
In Maven project, You can build jar automatically using Maven War plugin by setting archiveClasses to true. Example below.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<archiveClasses>true</archiveClasses>
</configuration>
</plugin>
the best way if you use Spring Boot is :
1/ Create a ServletInitializer extends SpringBootServletInitializer Class
. With method configure which run your Application Class
2/ Generate always a maven install WAR file
3/ With this artefact you can even :
. start application from war file with java -jar file.war
. put your war file in your favorite Web App server (like tomcat, ...)
Well, according to Wikipedia, with a WAR file, the classes that get loaded into the classpath are in the "/WEB-INF/classes" and "/WEB-INF/lib" directory.
You could try simply putting a copy of the classes on the root file system of the zip file (which is what a war/jar is). I'm not sure if that would work though.
You can always just create two separate files.
As an alternative option, include into the war file, the rest service to trigger the application logic via url. Deploy the war file onto any web/application server you want.
Then you can start your application via any command-line based HTTP client like curl on Linux.
The disadvantage: usually these HTTP clients are different on different OSs. Which is not critical for a lot of cases. Also you can install curl on Windows.
It's not possible to run a java class from a WAR file. WAR files have a different structure to Jar files.
To find the related java classes, export (preferred way to use ant) them as Jar put it in your web app lib.
Then you can use the jar file as normal to run java program. The same jar was also referred in web app (if you put this jar in web app lib)

Categories