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.
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).
Understanding Java classpath.
command line - Including all the jars in a directory within the Java classpath - Stack Overflow
Executable jar with an external class path reference
Java default ClassPath environment variable - Stack Overflow
Videos
I was surfing stackoverflow, trying to better understand what the classpath is all about and came upon this question/answer. It mostly makes sense, but there are two slightly confusing paragraphs in the accepted answer that go:
First, let's suppose that MyClass is something you built as part of your project, and it is in a directory in your project called output. The .class file would be at output/org/javaguy/coolframework/MyClass.class (along with every other file in that package). In order to get to that file, your path would simply need to contain the folder 'output', not the whole package structure, since your import statement provides all that information to the VM.
Now let's suppose that you bundle CoolFramework up into a .jar file, and put that CoolFramework.jar into a lib directory in your project. You would now need to put lib/CoolFramework.jar into your classpath. The VM will look inside the jar file for the org/javaguy/coolframework part, and find your class.
I don't understand the two sentences that say:
You would now need to put lib/CoolFramework.jar into your classpath. The VM will look inside the jar file for the org/javaguy/coolframework part, and find your class.
Why would the VM "look inside the jar file for the org/javaguy/coolframework part"? Why does that structure exist within the jar file? The answer mentions that you bundle "CoolFramework up into a .jar file", so why would that include the org/javaguy/coolframework hierarchy? Isn't CoolFrameWork just a single directory?
Using Java 6 or later, the classpath option supports wildcards. Note the following:
- Use straight quotes (
") - Use
*, not*.jar
Windows
java -cp "Test.jar;lib/*" my.package.MainClass
Unix
java -cp "Test.jar:lib/*" my.package.MainClass
This is similar to Windows, but uses : instead of ;. If you cannot use wildcards, bash allows the following syntax (where lib is the directory containing all the Java archive files):
java -cp "$(printf %s: lib/*.jar)"
(Note that using a classpath is incompatible with the -jar option. See also: Execute jar file with multiple classpath libraries from command prompt)
Understanding Wildcards
From the Classpath document:
Class path entries can contain the basename wildcard character
*, which is considered equivalent to specifying a list of all the files in the directory with the extension.jaror.JAR. For example, the class path entryfoo/*specifies all JAR files in the directory named foo. A classpath entry consisting simply of*expands to a list of all the jar files in the current directory.A class path entry that contains
*will not match class files. To match both classes and JAR files in a single directory foo, use eitherfoo;foo/*orfoo/*;foo. The order chosen determines whether the classes and resources infooare loaded before JAR files infoo, or vice versa.Subdirectories are not searched recursively. For example,
foo/*looks for JAR files only infoo, not infoo/bar,foo/baz, etc.The order in which the JAR files in a directory are enumerated in the expanded class path is not specified and may vary from platform to platform and even from moment to moment on the same machine. A well-constructed application should not depend upon any particular order. If a specific order is required then the JAR files can be enumerated explicitly in the class path.
Expansion of wildcards is done early, prior to the invocation of a program's main method, rather than late, during the class-loading process itself. Each element of the input class path containing a wildcard is replaced by the (possibly empty) sequence of elements generated by enumerating the JAR files in the named directory. For example, if the directory
foocontainsa.jar,b.jar, andc.jar, then the class pathfoo/*is expanded intofoo/a.jar;foo/b.jar;foo/c.jar, and that string would be the value of the system propertyjava.class.path.The
CLASSPATHenvironment variable is not treated any differently from the-classpath(or-cp) command-line option. That is, wildcards are honored in all these cases. However, class path wildcards are not honored in theClass-Path jar-manifestheader.
Note: due to a known bug in java 8, the windows examples must use a backslash preceding entries with a trailing asterisk: https://bugs.openjdk.java.net/browse/JDK-8131329
Under Windows this works:
java -cp "Test.jar;lib/*" my.package.MainClass
and this does not work:
java -cp "Test.jar;lib/*.jar" my.package.MainClass
Notice the *.jar, so the * wildcard should be used alone.
On Linux, the following works:
java -cp "Test.jar:lib/*" my.package.MainClass
The separators are colons instead of semicolons.
I have packaged my application as an executable jar, but I need to be able to include a directory outside of the jar on the classpath.
The folder structure is as follows and I am trying to include the conf directory
/project/test-SNAPSHOT.jar /project/conf /project/suites /project/run.sh
I tried adding the class path argument to the java command in the run.sh, but learned that when -jar is used the classpath argument is ignored
java -classpath .:conf/ -jar test-SNAPSHOT.jar suites/audit.xml
I also tried adding the the Class-Path attribute to the manifest
Manifest-Version: 1.0 Build-Jdk: 1.6.0_35 Built-By: Luvmysubi Created-By: Apache Maven Main-Class: org.testng.TestNG Archiver-Version: Plexus Archiver Class-Path: conf/*
But when this is done java complains that it cannot find the Main-Class attribute.
Failed to load Main-Class manifest attribute from test-SNAPSHOT.jar
Any ideas? The only thing I can think of is bundling all of the dependencies into a lib folder instead of using a single jar.
*formatting
The ClassPath environment variable is only used when you want your computer to look at a specific location for your .class files; generally speaking, it doesn't exist unless you make it exist, whether on purpose or a side effect of some installer.
Most of the time, the applications you are running (primarily JRE), know exactly where to look for .class files. Most of the time.
However, if you were refering to the PATH environmental variable, that can be more of an issue.
Oracle has a throughout step-by-step on setting your enviromental variables (I can vouch, I just had to reset my PATH this morning): http://docs.oracle.com/javase/tutorial/essential/environment/paths.html
However, here are the steps as I remember them:
- Start Menu, right click Computer, Choose Properties
- Advanced System on the far left, and there is an Enviromental Variables button near the bottom, click it
- In the bottom context menu, find the
PATHvariable and choose edit - Put a semicolon after the last one, and then add "C:\Program Files\Java\jre7\lib;" and "C:\Program Files\Java\jre7\bin;" or wherever your java "lib" and "bin" folders are
And then you should be all swell and dandy, no harm no fowl.
The difault of CLASSPATH environment variable is nothing, i.e. by default this variable does not exist. If you had something defined you should know what did you define. If you do not know, try to analyze your stack trace and understand what is needed to your application to work.
If you have problems, send your stack trace here and we will try to help you.
Yes I know if I use an IDE, it will handle all this automatically. But just for the sake of learning, I'm curious.
I've been figuring out how to compile a package and a regular class file on the command line (Bash).
My project is organized into folders like this.
/classes
/src
/mainDir
-main.java
/sortersDir
-bubbleSorter.javabubbleSorter . java has this package statement in the beginning:
package sorterClasses;
When I open bash at the project root directory, and type in:
" javac -d classes src/sorters/bubbleSorter.java "
I am able to see that there is now a folder within the classes folder called " sorterClasses " and my bubbleSorter . class file is in there.
I then try to compile the main . java file by typing in:
" javac -d classes -cp classes src/main.main.java "
and the statement executes with no errors.
But then when I try to run the main class file on the terminal with
" java classes/main "
it gives me an error saying " could not find or load main classes classes.main Caused by: java.lang.NoClassDefFoundError: main (wrong name: classes/main).
I then also tried typing in
" java -cp ./classes classes/main "
and it said " error: could not find or load main class classes.main "
Which makes me wonder....am I specifying the classpath correctly? Should I put down the entire absolute path? Like: ' C:/JavaPractice/Project1 ' ? Or just the relative path based on where the bash terminal currently is? That's what I did before. I added in the dot ( . ) to specify the current directory and then wrote classes to designate the classes folder.
Also correct me if I'm wrong, but you only need to specify the -cp option when you're compiling a file that uses other classes right? The -cp option is meant to figure out where to import classes from, and the -d option is meant to figure out where to export the compiled files?