Including all the jars in a directory within the Java classpath

1,185,685

Solution 1

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 .jar or .JAR. For example, the class path entry foo/* 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 either foo;foo/* or foo/*;foo. The order chosen determines whether the classes and resources in foo are loaded before JAR files in foo, or vice versa.

Subdirectories are not searched recursively. For example, foo/* looks for JAR files only in foo, not in foo/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 foo contains a.jar, b.jar, and c.jar, then the class path foo/* is expanded into foo/a.jar;foo/b.jar;foo/c.jar, and that string would be the value of the system property java.class.path.

The CLASSPATH environment 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 the Class-Path jar-manifest header.

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

Solution 2

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.

Solution 3

We get around this problem by deploying a main jar file myapp.jar which contains a manifest (Manifest.mf) file specifying a classpath with the other required jars, which are then deployed alongside it. In this case, you only need to declare java -jar myapp.jar when running the code.

So if you deploy the main jar into some directory, and then put the dependent jars into a lib folder beneath that, the manifest looks like:

Manifest-Version: 1.0
Implementation-Title: myapp
Implementation-Version: 1.0.1
Class-Path: lib/dep1.jar lib/dep2.jar

NB: this is platform-independent - we can use the same jars to launch on a UNIX server or on a Windows PC.

Solution 4

My solution on Ubuntu 10.04 using java-sun 1.6.0_24 having all jars in "lib" directory:

java -cp .:lib/* my.main.Class

If this fails, the following command should work (prints out all *.jars in lib directory to the classpath param)

java -cp $(for i in lib/*.jar ; do echo -n $i: ; done). my.main.Class

Solution 5

Short answer: java -classpath lib/*:. my.package.Program

Oracle provides documentation on using wildcards in classpaths here for Java 6 and here for Java 7, under the section heading Understanding class path wildcards. (As I write this, the two pages contain the same information.) Here's a summary of the highlights:

  • In general, to include all of the JARs in a given directory, you can use the wildcard * (not *.jar).

  • The wildcard only matches JARs, not class files; to get all classes in a directory, just end the classpath entry at the directory name.

  • The above two options can be combined to include all JAR and class files in a directory, and the usual classpath precedence rules apply. E.g. -cp /classes;/jars/*

  • The wildcard will not search for JARs in subdirectories.

  • The above bullet points are true if you use the CLASSPATH system property or the -cp or -classpath command line flags. However, if you use the Class-Path JAR manifest header (as you might do with an ant build file), wildcards will not be honored.

Yes, my first link is the same one provided in the top-scoring answer (which I have no hope of overtaking), but that answer doesn't provide much explanation beyond the link. Since that sort of behavior is discouraged on Stack Overflow these days, I thought I'd expand on it.

Share:
1,185,685
Bulki
Author by

Bulki

Recent computer science graduate working as a programmer analyst.

Updated on July 13, 2022

Comments

  • Bulki
    Bulki almost 2 years

    Is there a way to include all the jar files within a directory in the classpath?

    I'm trying java -classpath lib/*.jar:. my.package.Program and it is not able to find class files that are certainly in those jars. Do I need to add each jar file to the classpath separately?

    • Bulki
      Bulki about 13 years
      Sorry I've never accepted this. It should be a community wiki. Never used one of the provided answers. I believe I created a shell script that just scanned the lib/ directory and created the classpath from parsing file names.
    • Alex R
      Alex R about 13 years
      There's some kind of bug in this new Java feature, because it does not work as described. I gave up and used Ant to work around it, as described in one of the answers.
    • Mike
      Mike almost 12 years
      There is issue with wildcard processing in Windows. stackoverflow.com/questions/11607873/…
    • KNU
      KNU over 9 years
      At first I thought the . after jar: is put by mistake but..... The standard symbol for `current directory' is a single period (.) in both Unix and Windows systems.
    • Evgeni Sergeev
      Evgeni Sergeev over 9 years
      Short answer: (1) drop the .jar part, (2) must have at least 2 parts, separated by a ; on Windows (which is usually : elsewhere). For example: java -classpath ".;lib/*" Program
    • Sagar Kharab
      Sagar Kharab almost 3 years
      Really sorry but since this is a popular question and I can't ask my own question, I am seeking Java Expert Answer for what is the difference between the flag create vs create new at here github.com/frohoff/jdk8u-jdk/blob/master/src/solaris/classes‌​/…
  • Giovanni Funchal
    Giovanni Funchal almost 14 years
    This works, but watch out, pass the -Djava.ext.dirs= BEFORE -jar
  • Tom
    Tom over 13 years
    Awesome. Something like this works for me:java -cp target/classes;target/lib/* de.byteconsult.Main
  • Cristopher Van Paul
    Cristopher Van Paul over 13 years
    java.ext.dirs will work very different from a normal jar in classpath. It has higher priority and permission which will able to somehow override classes in bootstamp(rt.jar)
  • Alex R
    Alex R about 13 years
    The feature is poorly documented, and seems to require some less-than-obvious pre-conditions to be satisfied in order to work as intended.
  • Raku
    Raku over 12 years
    This seems to work for a lot of people, however, Java seems to plainly ignore the Class-Path entries in the manifest file here. We cannot run the application without manually adding "lib/*" to the classpath using -cp. Any ideas?
  • albfan
    albfan about 12 years
    a funny note. java -cp lib/* my.main.Class will fail always because shell glob expansion of lib/*, while java -cp .:lib/* my.main.Class will not because .:lib/* is not a valid glob path. Take a while to note that
  • Ellen Spertus
    Ellen Spertus almost 12 years
    Lord Torgamus below provides an example and explanation.
  • JohnnyLambada
    JohnnyLambada almost 12 years
    You can also use find: cp=$(find /path/to/std/jars /path/to/your/jar -not -type d -printf "%p:")
  • Eyad Ebrahim
    Eyad Ebrahim over 11 years
    my problem was with lib/*.jar rather than lib/*. Thanks a lot this fixed it. I noticed that there's a difference between : and ; but that could be my testing-many-changes-at-the-same-time kind of thing.
  • Wim Deblauwe
    Wim Deblauwe over 11 years
    The perfect answer. 2 important things to notice: 1) Use quotes and 2) Use * only, not *.jar
  • rzwitserloot
    rzwitserloot over 11 years
    oxbow_lakes's answer isn't entirely correct; the Class-Path thing is honored (and ONLY that is honored; -cp/-classpath is ignored!) if you start this jar with java -jar myapp.jar. I presume oxbow_lakes meant to write that when he wrote 'java -classpath myapp.jar'.
  • rzwitserloot
    rzwitserloot over 11 years
    This does not work; linux will expand the . you can try: java -cp '.:lib/' and that works fine (note the single quotes! It won't work with double quotes!). Actually, .:lib/* might work if that's not a legit glob due to the colon, but it feels a bit iffy. I'd add the quotes. The single quotes tell bash to not touch any part of the contents.
  • Supr
    Supr about 11 years
    +1 for the last bash/tr trick. Java/JamVM here doesn't like wildcards for paths outside the working directory, but explicitly referencing each JAR using shell wildcard + tr works!
  • jamesmortensen
    jamesmortensen over 10 years
    A year and 8 months later, the edit I made to include the UNIX version saved me yet again. :) Funny how it wouldn't recognize my jar files with *.jar but only with *.
  • yellavon
    yellavon about 10 years
    I have a command java -classpath /jars/*:/anotherJarsDir/* com.test.MyClass without any quotes and it works fine. I'm wondering why shell isn't expanding it and erroring out?
  • user13107
    user13107 about 10 years
    I found that the order of classpaths is important (but I don't know why). I was getting errors until I switched order of classpaths.
  • Sebastian
    Sebastian about 10 years
    @jmort253, the thing is, this is not the shell * expanding, but the wildcard is java parsing the classpath, seeing the * and filling in the wildcard
  • jamesmortensen
    jamesmortensen about 10 years
    @SebastianGodelet - Yeh, that's just me getting confused between Regex wildcards and this notation, which isn't the same I guess. Mostly, what saved me is knowing the difference between : on one platform and ; on the other. :) I compile with Java from the command line about once per year, just enough not to remember how yet often enough to be annoying.
  • simo.3792
    simo.3792 over 9 years
    This may have been the only way back in '08, but not anymore.
  • simo.3792
    simo.3792 over 9 years
    This may have been the only way back in '08, but not anymore.
  • AndiDog
    AndiDog about 9 years
    Mind that java -cp "Test.jar;lib/*" my.package.MainClass works but if the classpath parameter is given as second argument, it does not work (java my.package.MainClass -cp "Test.jar;lib/*").
  • Devon Peticolas
    Devon Peticolas about 9 years
    This isn't the worst thing. It's a hack, but I have this set in my bashrc for jar in $(ls $HOME/bin/*.jar); do export CLASSPATH=$jar:$CLASSPATH; done
  • Sohail Si
    Sohail Si almost 9 years
    Also don't use ~ in the -cp
  • Angel O'Sphere
    Angel O'Sphere almost 8 years
    It does not matter (in this context) if you use single or double quotes. You want to prevent the shell from expanding (globbing) the *, that is all. And pass the text "lib/*" litterally to the JVM, so the VM recognices this as a "special pattern" and searches by itself for jar files.
  • manifold
    manifold almost 8 years
    Following is not valid as well java -cp = " " like you use in set classpath=" "
  • Konstantin Pelepelin
    Konstantin Pelepelin about 6 years
    Single quotes should be used in bash
  • philwalk
    philwalk almost 6 years
    Your windows example doesn't work with java 8 or earlier, but would with this classpath: Test.jar;lib\* ... forward slash is okay except when preceding an asterisk and a few others ... see bugs.openjdk.java.net/browse/JDK-8131329
  • philwalk
    philwalk almost 6 years
    windows example doesn't work for java 8 and earlier: see bugs.openjdk.java.net/browse/JDK-8131329
  • Wender
    Wender almost 6 years
    Maybe does not work for open JDK, I will test this and I will talk about here
  • philwalk
    philwalk almost 6 years
    windows example seems to have worked for java 6, maybe java 7, but not for java 8 (see bugs.openjdk.java.net/browse/JDK-8131329)
  • burak
    burak almost 6 years
    Thanks for the emphasising the difference between * and *.jar
  • Wender
    Wender over 5 years
    Sorry, I did test with HotSpot and I did think that works with openjdk.
  • philwalk
    philwalk over 5 years
    Oracle java under windows requires a backslash prior to the asterisk rather than a forward slash, although I haven't re-tested the most recent or alternate java versions.
  • Jonathan Drapeau
    Jonathan Drapeau over 5 years
    Works for java 8 in linux
  • Peter
    Peter almost 5 years
    In Cygwin we need to use semicolon (;) separator instead of colon (:)
  • Matt Campbell
    Matt Campbell over 4 years
    Thanks. On 'java version "1.8.0_221" Java(TM) SE Runtime Environment (build 1.8.0_221-b27) Java HotSpot(TM) 64-Bit Server VM (build 25.221-b27, mixed mode)', only this -D version of passing in the classpath worked. The traditional form did not.
  • Anish B.
    Anish B. over 4 years
    @basszero With double quotes, It worked on MacOS 10.15.2 Catalina. Thanks :) +1 for this.
  • Aman
    Aman about 4 years
    what about older version than java 6 @basszero
  • Mugeesh Husain
    Mugeesh Husain almost 4 years
    java -classpath "lib/*:." my.package.Program is worked for me
  • Datbates
    Datbates almost 4 years
    I am not sure why having the additional classpath entry for "." fixed my problem, but it works now. "." is the same directory as the directory I specified with the wildcard. I can't see why this would matter, but it did. Thanks!
  • Hardik Rana
    Hardik Rana over 3 years
    java -cp "Test.jar;lib/*" my.package.MainClass will this not look for children folders under lib? Eg my jar is in directory lib/org/abc.jar
  • Hardik Rana
    Hardik Rana over 3 years
    java -cp "Test.jar;lib/*" my.package.MainClass will this not look for children folders under lib? Eg my jar is in directory lib/org/abc.ja
  • Hardik Rana
    Hardik Rana over 3 years
    java -cp "Test.jar;lib/*" my.package.MainClass will this not look for children folders under lib? Eg my jar is in directory lib/org/abc.ja
  • Hardik Rana
    Hardik Rana over 3 years
    java -cp "Test.jar;lib/*" my.package.MainClass will this not look for children folders under lib? Eg my jar is in directory lib/org/abc.ja
  • Sridhar Sarnobat
    Sridhar Sarnobat over 2 years
    I may no longer need groovy! -classpath ~/".groovy/lib/*"