I created a jar file containing all my compiled stuff. Additionally my ant build script copies the required libs into a subfolder "libs". The structure looks like this:
MyProgram.jar
libs/
So when I try to run my program now I get the following error:
java -cp ".:/home/user/java/MyProgram/jar/libs" -jar MyProgram.jar
java.lang.ClassNotFoundException: org.postgresql.Driver
at java.net.URLClassLoader$1.run(URLClassLoader.java:217)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:205)
at java.lang.ClassLoader.loadClass(ClassLoader.java:321)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:294)
at java.lang.ClassLoader.loadClass(ClassLoader.java:266)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:186)
at database.PostgresQL.getConnection(PostgresQL.java:38)
at recommender.dao.Creative2IdxDAO.createCreatives2Idx(Creative2IdxDAO.java:19)
at main.Main.calculateCorrelationMatrix(Main.java:51)
at main.Main.main(Main.java:28)
java.lang.NullPointerException
at recommender.dao.Creative2IdxDAO.createCreatives2Idx(Creative2IdxDAO.java:25)
at main.Main.calculateCorrelationMatrix(Main.java:51)
at main.Main.main(Main.java:28)
Why does this happen?
To run an application in a nonexecutable JAR file, we have to use -cp option instead of -jar. We'll use the -cp option (short for classpath) to specify the JAR file that contains the class file we want to execute: java -cp jar-file-name main-class-name [args …]
There is only a conflict if both jars define the exact same fully qualified class names. The JVM will most definitely load both jars - but it will not load classes from them that are already loaded.
You use either -jar
or -cp
, you can't combine the two. If you want to put additional JARs on the classpath then you should either put them in the main JAR's manifest and then use java -jar
or you put the full classpath (including the main JAR and its dependencies) in -cp
and name the main class explicitly on the command line
java -cp 'MyProgram.jar:libs/*' main.Main
(I'm using the dir/*
syntax that tells the java
command to add all .jar
files from a particular directory to the classpath. Note that the *
must be protected from expansion by the shell, which is why I've used single quotes.)
You mention that you're using Ant so for the alternative manifest approach, you can use ant's <manifestclasspath>
task after copying the dependencies but before building the JAR.
<manifestclasspath property="myprogram.manifest.classpath" jarfile="MyProgram.jar">
<classpath>
<fileset dir="libs" includes="*.jar" />
</classpath>
</manifestclasspath>
<jar destfile="MyProgram.jar" basedir="classes">
<manifest>
<attribute name="Main-Class" value="main.Main" />
<attribute name="Class-Path" value="${myprogram.manifest.classpath}" />
</manifest>
</jar>
With this in place, java -jar MyProgram.jar
will work correctly, and will include all the libs
JAR files on the classpath as well.
When the -jar
option is used the -cp
option is ignored. The only way to set the classpath is using manifest file in the jar.
It is easier to just use the -cp
option, add your jar file to that, then explicitly call the main class.
Also, assuming the /home/user/java/MyProgram/jar/libs
folder contains jar files (as opposed to class files) this won't work. You cannot specify a folder of jar file but must specify each jar file individually in the classpath (it is worth writing a simple shell script to do this for you if there are a significant number of jars).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With